2
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
#include "gnashconfig.h"
25
#include <boost/algorithm/string/case_conv.hpp>
27
#include "smart_ptr.h" // GNASH_USE_GC
33
#include "as_environment.h"
35
#include "ASHandlers.h"
36
#include "movie_root.h"
39
gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
43
using namespace gnash::SWF;
48
const char *as_arg_strs[] = {
59
const char *state_strs[] = { "rw", "w", "r" };
62
: _enabled(false), _tracing(false), _state(NONE), _skipb(0), _env(0), _pc(0)
64
// GNASH_REPORT_FUNCTION;
69
// GNASH_REPORT_FUNCTION;
73
Debugger::getDefaultInstance()
82
// GNASH_REPORT_FUNCTION;
83
cerr << "Gnash Debugger" << endl;
84
cerr << "\t? - help" << endl;
85
cerr << "\tq - Quit" << endl;
86
cerr << "\tt - Toggle Trace Mode" << endl;
87
cerr << "\tc - Continue" << endl;
88
cerr << "\td - Dissasemble current line" << endl;
90
cerr << "\ti i - Dump Movie Info" << endl;
91
cerr << "\ti f - Dump Stack Frame" << endl;
92
cerr << "\ti s - Dump symbols" << endl;
93
cerr << "\ti g - Dump Global Regs" << endl;
94
cerr << "\ti r - Dump Local Regs" << endl;
95
cerr << "\ti l - Dump Local Variables" << endl;
96
cerr << "\ti w - Dump watch points" << endl;
97
cerr << "\ti b - Dump break points" << endl;
98
cerr << "\ti c - Dump Function Call Stack" << endl;
99
// break and watch points
100
cerr << "\tw name [r:w:b] - set variable watchpoint" << endl;
101
cerr << "\tw name d - delete variable watchpoint" << endl;
102
cerr << "\tb name [t:f]- enable/disable function break point" << endl;
103
cerr << "\tb name d - delete function break point" << endl;
105
cerr << "\tset var [name] [value] - set a local variable" << endl;
106
cerr << "\tset stack [index] [value] - set a stack entry" << endl;
107
cerr << "\tset reg [index] [value] - set a local register" << endl;
108
cerr << "\tset global [index] [value] - set a global register" << endl;
114
// GNASH_REPORT_FUNCTION;
118
// Open a user console for debugging commands. The abbreviations and
119
// commands are roughly based on GDBs.
121
Debugger::console(as_environment &env)
123
// GNASH_REPORT_FUNCTION;
125
// If the debugger isn't enabled, there is nothing to do.
126
if (!this->isEnabled()) {
131
cerr << "WARNING: environment not set yet";
132
cerr << "\nOnly watch point commands will work untill after you continue." << endl;
134
// if (this->isContinuing()) {
138
string var, val, sstate;
140
Debugger::watch_state_e wstate;
141
bool keep_going = true;
143
log_debug (_("Debugger enabled >> "));
145
cerr << "gnashdbg> ";
153
// Continue executing.
158
// Change the value of a variable on the stack
160
if (action == "set") {
164
// change a parameter on the stack
167
asval.set_string(val);
168
this->changeStackValue(index, asval);
170
// change a local variable
173
asval.set_string(val);
174
this->changeLocalVariable(var, asval);
176
// change a local register
179
asval.set_string(val);
180
this->changeLocalRegister(index, asval);
182
// change a global register
185
asval.set_string(val);
186
this->changeGlobalRegister(index, asval);
193
// Informational commands.
201
this->dumpMovieInfo();
204
this->dumpBreakPoints();
207
this->dumpWatchPoints();
210
this->dumpLocalRegisters(env);
213
this->dumpGlobalRegisters(env);
216
this->dumpLocalVariables(env);
219
this->dumpStackFrame(env);
226
this->callStackDump();
230
// Tracing mode. This prints a disasembly every time
231
// Gnash stops at a watch or break point.
233
if (this->isTracing()) {
234
this->traceMode(false);
236
this->traceMode(true);
239
// Print a help screen
245
cin >> var >> sstate;
248
this->setBreakPoint(var, true);
251
this->setBreakPoint(var, false);
254
this->removeBreakPoint(var);
259
cin >> var >> sstate;
263
wstate = Debugger::READS;
267
wstate = Debugger::WRITES;
269
// Break on any accesses
272
wstate = Debugger::BOTH;
275
// Delete a watch point
276
if (sstate[0] == 'd') {
277
this->removeWatchPoint(var);
279
this->setWatchPoint(var, wstate);
290
Debugger::callStackDump()
292
// GNASH_REPORT_FUNCTION;
293
vector<string>::const_iterator it;
294
for (it=_callstack.begin(); it!=_callstack.end(); it++) {
296
void *addr = this->lookupSymbol(str);
297
cerr << "\t=> " << *it << "() <" << addr << ">" << endl;
302
Debugger::dumpMovieInfo()
304
// GNASH_REPORT_FUNCTION;
305
if (VM::isInitialized()) {
307
movie_root &mr = vm.getRoot();
309
mr.get_mouse_state(x, y, buttons);
311
cerr << "Movie is Flash v" << vm.getSWFVersion() << endl;
312
cerr << "Mouse coordinates are: X=" << x << ", Y=" << y << endl;
313
vm.getGlobal()->dump_members();
318
Debugger::disassemble()
320
// GNASH_REPORT_FUNCTION;
321
this->disassemble(_pc);
325
Debugger::disassemble(const unsigned char *data)
327
// GNASH_REPORT_FUNCTION;
328
as_arg_t fmt = ARG_HEX;
329
action_type action_id = static_cast<action_type>(data[0]);
332
unsigned char num[10];
335
const gnash::SWF::SWFHandlers& ash = gnash::SWF::SWFHandlers::instance();
341
if (action_id > ash.lastType()) {
342
cerr << "WARNING: <unknown>[0x" << action_id << "]" << endl;
344
if (ash[action_id].getName().size() > 0) {
345
cerr << "Action: " << (void *)action_id << ": " << ash[action_id].getName().c_str() << endl;
347
cerr << "Action: " << (void *)action_id << ": " << "WARNING: unknown ID" << endl;
349
fmt = ash[action_id].getArgFormat();
352
// If we get a ActionPushData opcode, get the parameters
353
if (action_id & 0x80) {
354
int length = data[1] | (data[2] << 8);
355
cerr << "\tArg format is: " << as_arg_strs[fmt] << " Length is: " << length << endl;
358
log_error (_("No format flag"));
361
if ((length == 1) && (data[3] == 0)) {
364
for (int i = 0; i < length; i++) {
365
if (data[3 + i] != 0) {
372
cerr << "Got string (" << length << " bytes): " << "\"" << str << "\"" << endl;
375
cerr << hexify((const unsigned char *)&data[3], length, false) << endl;
379
// cerr << "FIXME: Got u8: " << val << endl;
382
val = data[3] | (data[4] << 8);
383
// cerr << "FIXME: Got u16: " << val << endl;
386
val = data[3] | (data[4] << 8);
388
val |= ~0x7FFF; // sign-extend
390
// cerr << "FIXME: Got s16: " << val << endl;
399
log_error (_("No format flag"));
401
} // end of switch(fmt)
406
Debugger::setBreakPoint(const std::string &func, bool enabled)
408
// GNASH_REPORT_FUNCTION;
409
_breakpoints[func] = enabled;
413
Debugger::removeBreakPoint(const std::string &func)
415
// GNASH_REPORT_FUNCTION;
418
std::map<std::string, bool>::const_iterator it;
419
it = _breakpoints.find(func);
420
if (it != _breakpoints.end()) {
421
_breakpoints.erase(func);
426
Debugger::dumpBreakPoints()
428
// GNASH_REPORT_FUNCTION;
431
std::map<std::string, bool>::const_iterator it;
434
for (it=_breakpoints.begin(); it != _breakpoints.end(); it++) {
438
string str = (val) ? " is enabled" : " is disabled";
439
cerr << "\tbreak #" << index++ << ": " << name << str << endl;
445
Debugger::matchBreakPoint(const std::string &func, bool state)
447
// GNASH_REPORT_FUNCTION;
448
std::map<std::string, bool>::const_iterator it;
449
it =_breakpoints.find(func);
450
if (it == _breakpoints.end()) {
451
// log_debug ("No Match for variable \"%s\"", var);
454
if (state == _breakpoints[func]) {
455
// log_debug ("Matched for Function \"%s\"", func);
464
Debugger::setWatchPoint(const std::string &var, watch_state_e state)
466
// GNASH_REPORT_FUNCTION;
467
_watchpoints[var] = state;
468
log_debug (_("Setting watchpoint for variable: \"%s\""), var.c_str());
472
Debugger::removeWatchPoint(const std::string &var)
474
// GNASH_REPORT_FUNCTION;
477
std::map<std::string, watch_state_e>::const_iterator it;
478
it = _watchpoints.find(var);
479
if (it != _watchpoints.end()) {
480
_watchpoints.erase(var);
485
Debugger::dumpWatchPoints()
487
// GNASH_REPORT_FUNCTION;
491
std::map<std::string, watch_state_e>::const_iterator it;
493
for (it=_watchpoints.begin(); it != _watchpoints.end(); it++) {
498
cerr << "\twatch #" << index << ": " << name
499
<< " \"" << state_strs[state] << "\"" << endl;
505
Debugger::matchWatchPoint(const std::string &var, watch_state_e state)
507
// GNASH_REPORT_FUNCTION;
508
std::map<std::string, watch_state_e>::const_iterator it;
509
it =_watchpoints.find(var);
510
if (it == _watchpoints.end()) {
511
// log_debug ("No Match for variable \"%s\"", var);
514
if (state == _watchpoints[var]) {
515
log_debug (_("Matched for variable \"%s\": \"%s\""), var.c_str(),
524
// These functions manipulate the environment stack
526
Debugger::dumpStackFrame()
528
// GNASH_REPORT_FUNCTION;
530
log_error (_("WARNING: environment not set in %s"), __PRETTY_FUNCTION__);
533
this->dumpStackFrame(*_env);
536
// Change the value of a parameter on the stack
538
Debugger::changeStackValue(unsigned int index, as_value &val)
540
// GNASH_REPORT_FUNCTION;
541
changeStackValue(*_env, index, val);
545
Debugger::changeStackValue(as_environment &env, unsigned int index, as_value &val)
547
// GNASH_REPORT_FUNCTION;
549
log_error (_("WARNING: environment not set in %s"), __PRETTY_FUNCTION__);
552
if (env.stack_size()) {
553
env.bottom(index) = val;
558
Debugger::dumpStackFrame(as_environment &env)
560
// GNASH_REPORT_FUNCTION;
562
log_error (_("WARNING: environment not set in %s"), __PRETTY_FUNCTION__);
565
if (env.stack_size()) {
566
log_debug (_("Stack Dump of: %p"), (void *)&env);
567
for (unsigned int i=0, n=env.stack_size(); i<n; i++) {
568
// FIXME, shouldn't these go to the log as well as to cerr?
569
cerr << "\t" << i << ": ";
570
as_value val = env.bottom(i);
571
// FIXME: we want to print the name of the function
572
// if (val.is_as_function()) {
573
// // cerr << val.get_symbol_handle() << endl;
574
// string name = this->lookupSymbol(val.to_object());
575
// if (name.size()) {
576
// cerr << name << " ";
579
cerr << env.bottom(i);
581
if (val.is_object()) {
582
boost::intrusive_ptr<as_object> o = val.to_object();
583
string name = lookupSymbol(o.get());
585
cerr << " \"" << name << "\"";
588
cerr << " has #" << o->get_ref_count() << " references";
595
log_debug (_("Stack Dump of 0x%p: empty"), (void *)&env);
600
Debugger::dumpLocalRegisters()
602
// GNASH_REPORT_FUNCTION;
603
this->dumpLocalRegisters(*_env);
607
Debugger::dumpLocalRegisters(as_environment &env)
609
// GNASH_REPORT_FUNCTION;
610
env.dump_local_registers(cerr);
614
Debugger::dumpGlobalRegisters()
616
// GNASH_REPORT_FUNCTION;
617
this->dumpGlobalRegisters(*_env);
621
Debugger::dumpGlobalRegisters(as_environment &env)
623
// GNASH_REPORT_FUNCTION;
625
log_error (_("WARNING: environment not set in %s"), __PRETTY_FUNCTION__);
628
std::string registers;
630
log_debug (_("Global Registers Dump:"));
631
for (unsigned int i=0; i<4; ++i) {
632
ss << "\treg #" << i << ": \"";
633
ss << env.global_register(i) << "\"" << endl;
635
cerr << ss.str().c_str() << endl;
638
// Change the value of a local variable
640
Debugger::changeLocalVariable(const std::string &var, as_value &val)
642
// GNASH_REPORT_FUNCTION;
643
changeLocalVariable(*_env, var, val);
647
Debugger::changeLocalVariable(as_environment &env, const std::string &var, as_value &val)
649
// GNASH_REPORT_FUNCTION;
650
env.set_local(var, val);
653
// Change the value of a local variable
655
Debugger::changeLocalRegister(unsigned index, as_value &val)
657
// GNASH_REPORT_FUNCTION;
658
changeLocalRegister(*_env, index, val);
662
Debugger::changeLocalRegister(as_environment &env, unsigned index, as_value &val)
664
// GNASH_REPORT_FUNCTION;
665
env.set_local_register(index, val);
668
// Change the value of a global variable
670
Debugger::changeGlobalRegister(unsigned index, as_value &val)
672
// GNASH_REPORT_FUNCTION;
673
this->changeLocalRegister(*_env, index, val);
677
Debugger::changeGlobalRegister(as_environment &env, unsigned index, as_value &val)
679
// GNASH_REPORT_FUNCTION;
680
env.set_global_register(index, val);
684
Debugger::dumpLocalVariables()
686
// GNASH_REPORT_FUNCTION;
687
this->dumpLocalVariables(*_env);
691
Debugger::dumpLocalVariables(as_environment &env)
693
env.dump_local_variables(cerr);
696
/// Get the address associated with a name
698
Debugger::lookupSymbol(std::string &name)
700
// GNASH_REPORT_FUNCTION;
701
if (_symbols.size()) {
702
VM& vm = VM::get(); // cache this ?
703
std::string namei = PROPNAME(name);
704
std::map<void *, std::string>::const_iterator it;
705
for (it=_symbols.begin(); it != _symbols.end(); it++) {
706
if (it->second == namei) {
707
// log_debug ("Found symbol %s at address %p", namei.c_str(),
717
Debugger::addSymbol(void *ptr, std::string name)
719
// GNASH_REPORT_FUNCTION;
720
VM& vm = VM::get(); // cache this ?
721
std::string namei = PROPNAME(name);
722
if (namei.size() > 1)
724
// log_debug ("Adding symbol %s at address: %p", namei, ptr);
725
_symbols[ptr] = namei;
730
/// Get the name associated with an address
732
Debugger::lookupSymbol(void *ptr)
734
// GNASH_REPORT_FUNCTION;
737
if (_symbols.size()) {
738
std::map<void *, std::string>::const_iterator it;
739
it = _symbols.find(ptr);
740
// dbglogfile.setStamp(false);
741
if (it != _symbols.end()) {
742
// log_debug ("Found symbol %s at address: %p", it->second.c_str(), ptr);
745
// log_debug ("No symbol found for address %p", ptr);
748
// dbglogfile.setStamp(false);
753
Debugger::dumpSymbols()
755
// GNASH_REPORT_FUNCTION;
757
std::map<void *, std::string>::const_iterator it;
758
for (it=_symbols.begin(); it != _symbols.end(); it++) {
759
string name = it->second;
760
void *addr = it->first;
762
cerr << "\tsym #" << index << ": " << name << " <" << addr << ">" << endl;
768
} // end of gnash namespace
772
// indent-tabs-mode: t