/[gxemul]/trunk/src/debugger/debugger.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/debugger/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22609 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


1 /*
2 * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: debugger.c,v 1.10 2006/06/16 18:31:26 debug Exp $
29 *
30 * Single-step debugger.
31 *
32 *
33 * TODO:
34 *
35 * This entire module is very much non-reentrant. :-/
36 *
37 * Add more functionality that already exists elsewhere in the emulator.
38 *
39 * Call stack display (back-trace)?
40 *
41 * More generic expression evaluator (for example + - * / between multiple
42 * terms), including _TAB COMPLETION_ of symbols and register names!
43 * Must be possible to reach any emul, any machine in any emul, any
44 * cpu in any machine, other variables in the emulator, and so forth.
45 * Perhaps a "settable variables registry" somewhere?
46 *
47 * Nicer looking output of register dumps, floating point registers,
48 * etc. Warn about weird/invalid register contents.
49 *
50 * Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)...
51 *
52 * Many other TODOs.
53 */
54
55 #include <ctype.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include "console.h"
63 #include "cpu.h"
64 #include "device.h"
65 #include "debugger.h"
66 #include "debugger_gdb.h"
67 #include "diskimage.h"
68 #include "emul.h"
69 #include "machine.h"
70 #include "memory.h"
71 #include "misc.h"
72 #include "net.h"
73 #include "settings.h"
74 #include "x11.h"
75
76
77 extern int extra_argc;
78 extern char **extra_argv;
79 extern struct settings *global_settings;
80 extern int quiet_mode;
81
82
83 /*
84 * Global debugger variables:
85 *
86 * TODO: Some of these should be moved to some other place!
87 */
88
89 volatile int single_step = 0;
90 volatile int exit_debugger;
91 int force_debugger_at_exit = 0;
92 int show_opcode_statistics = 0;
93
94 volatile int single_step_breakpoint = 0;
95 int debugger_n_steps_left_before_interaction = 0;
96
97 int old_instruction_trace = 0;
98 int old_quiet_mode = 0;
99 int old_show_trace_tree = 0;
100
101
102 /*
103 * Private (global) debugger variables:
104 */
105
106 static volatile int ctrl_c;
107
108 static int debugger_n_emuls;
109 static struct emul **debugger_emuls;
110 static struct emul *debugger_emul;
111 static struct machine *debugger_machine;
112
113 #define MAX_CMD_BUFLEN 72
114 #define N_PREVIOUS_CMDS 150
115 static char *last_cmd[N_PREVIOUS_CMDS];
116 static int last_cmd_index;
117
118 static char repeat_cmd[MAX_CMD_BUFLEN];
119
120 #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL
121
122 static uint64_t last_dump_addr = MAGIC_UNTOUCHED;
123 static uint64_t last_unasm_addr = MAGIC_UNTOUCHED;
124
125
126 /*
127 * debugger_readchar():
128 */
129 char debugger_readchar(void)
130 {
131 int ch, i, j;
132
133 while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) {
134 /* Check for X11 events: */
135 x11_check_event(debugger_emuls, debugger_n_emuls);
136
137 /* Check for incoming GDB packets: */
138 for (i=0; i<debugger_n_emuls; i++) {
139 struct emul *e = debugger_emuls[i];
140 if (e == NULL)
141 continue;
142
143 for (j=0; j<e->n_machines; j++) {
144 if (e->machines[j]->gdb.port > 0)
145 debugger_gdb_check_incoming(
146 e->machines[j]);
147 }
148 }
149
150 /* TODO: The X11 and GDB checks above should probably
151 be factored out... */
152
153 /* Give up some CPU time: */
154 usleep(1);
155 }
156 return ch;
157 }
158
159
160 /*
161 * debugger_activate():
162 *
163 * This is a signal handler for CTRL-C. It shouldn't be called directly,
164 * but setup code in emul.c sets the CTRL-C signal handler to use this
165 * function.
166 */
167 void debugger_activate(int x)
168 {
169 ctrl_c = 1;
170
171 if (single_step) {
172 /* Already in the debugger. Do nothing. */
173 int i;
174 for (i=0; i<MAX_CMD_BUFLEN; i++)
175 console_makeavail(MAIN_CONSOLE, '\b');
176 console_makeavail(MAIN_CONSOLE, ' ');
177 console_makeavail(MAIN_CONSOLE, '\n');
178 printf("^C");
179 fflush(stdout);
180 } else {
181 /* Enter the single step debugger. */
182 single_step = 1;
183
184 /* Discard any chars in the input queue: */
185 while (console_charavail(MAIN_CONSOLE))
186 console_readchar(MAIN_CONSOLE);
187 }
188
189 /* Clear the repeat-command buffer: */
190 repeat_cmd[0] = '\0';
191
192 /* Reactivate the signal handler: */
193 signal(SIGINT, debugger_activate);
194 }
195
196
197 /*
198 * debugger_parse_name():
199 *
200 * This function reads a string, and tries to match it to a register name,
201 * a symbol, or treat it as a decimal numeric value.
202 *
203 * Some examples:
204 *
205 * "0x7fff1234" ==> numeric value (hex, in this case)
206 * "pc", "r5", "hi", "t4" ==> register (CPU dependent)
207 * "memcpy+64" ==> symbol (plus offset)
208 *
209 * Register names can be preceeded by "x:" where x is the CPU number. (CPU
210 * 0 is assumed by default.)
211 *
212 * To force detection of different types, a character can be added in front of
213 * the name: "$" for numeric values, "%" for registers, and "@" for symbols.
214 *
215 * Return value is:
216 *
217 * NAME_PARSE_NOMATCH no match
218 * NAME_PARSE_MULTIPLE multiple matches
219 *
220 * or one of these (and then *valuep is read or written, depending on
221 * the writeflag):
222 *
223 * NAME_PARSE_REGISTER a register
224 * NAME_PARSE_NUMBER a hex number
225 * NAME_PARSE_SYMBOL a symbol
226 */
227 #define NAME_PARSE_NOMATCH 0
228 #define NAME_PARSE_MULTIPLE 1
229 #define NAME_PARSE_REGISTER 2
230 #define NAME_PARSE_NUMBER 3
231 #define NAME_PARSE_SYMBOL 4
232 static int debugger_parse_name(struct machine *m, char *name, int writeflag,
233 uint64_t *valuep)
234 {
235 int match_register = 0, match_symbol = 0, match_numeric = 0;
236 int skip_register, skip_numeric, skip_symbol;
237
238 if (m == NULL || name == NULL) {
239 fprintf(stderr, "debugger_parse_name(): NULL ptr\n");
240 exit(1);
241 }
242
243 /* Warn about non-signextended values: */
244 if (writeflag) {
245 if (m->cpus[0]->is_32bit) {
246 /* Automagically sign-extend. TODO: Is this good? */
247 if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
248 (*valuep) |= 0xffffffff00000000ULL;
249 } else {
250 if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
251 printf("WARNING: The value is not sign-extende"
252 "d. Is this what you intended?\n");
253 }
254 }
255
256 skip_register = name[0] == '$' || name[0] == '@';
257 skip_numeric = name[0] == '%' || name[0] == '@';
258 skip_symbol = name[0] == '$' || name[0] == '%';
259
260 /* Check for a register match: */
261 if (!skip_register && strlen(name) >= 1)
262 cpu_register_match(m, name, writeflag, valuep,
263 &match_register);
264
265 /* Check for a number match: */
266 if (!skip_numeric && isdigit((int)name[0])) {
267 uint64_t x;
268 x = strtoull(name, NULL, 0);
269 if (writeflag) {
270 printf("You cannot assign like that.\n");
271 } else
272 *valuep = x;
273 match_numeric = 1;
274 }
275
276 /* Check for a symbol match: */
277 if (!skip_symbol) {
278 int res;
279 char *p, *sn;
280 uint64_t newaddr, ofs = 0;
281
282 sn = malloc(strlen(name) + 1);
283 if (sn == NULL) {
284 fprintf(stderr, "out of memory in debugger\n");
285 exit(1);
286 }
287 strlcpy(sn, name, strlen(name)+1);
288
289 /* Is there a '+' in there? Then treat that as an offset: */
290 p = strchr(sn, '+');
291 if (p != NULL) {
292 *p = '\0';
293 ofs = strtoull(p+1, NULL, 0);
294 }
295
296 res = get_symbol_addr(&m->symbol_context, sn, &newaddr);
297 if (res) {
298 if (writeflag) {
299 printf("You cannot assign like that.\n");
300 } else
301 *valuep = newaddr + ofs;
302 match_symbol = 1;
303 }
304
305 free(sn);
306 }
307
308 if (match_register + match_symbol + match_numeric > 1)
309 return NAME_PARSE_MULTIPLE;
310
311 if (match_register)
312 return NAME_PARSE_REGISTER;
313 if (match_numeric)
314 return NAME_PARSE_NUMBER;
315 if (match_symbol)
316 return NAME_PARSE_SYMBOL;
317
318 return NAME_PARSE_NOMATCH;
319 }
320
321
322 /*
323 * show_breakpoint():
324 */
325 static void show_breakpoint(struct machine *m, int i)
326 {
327 printf("%3i: 0x", i);
328 if (m->cpus[0]->is_32bit)
329 printf("%08"PRIx32, (uint32_t) m->breakpoint_addr[i]);
330 else
331 printf("%016"PRIx64, (uint64_t) m->breakpoint_addr[i]);
332 if (m->breakpoint_string[i] != NULL)
333 printf(" (%s)", m->breakpoint_string[i]);
334 if (m->breakpoint_flags[i])
335 printf(": flags=0x%x", m->breakpoint_flags[i]);
336 printf("\n");
337 }
338
339
340 /****************************************************************************/
341
342
343 #include "debugger_cmds.c"
344
345
346 /****************************************************************************/
347
348
349 /*
350 * debugger_assignment():
351 *
352 * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
353 */
354 void debugger_assignment(struct machine *m, char *cmd)
355 {
356 char *left, *right;
357 int res_left, res_right;
358 uint64_t tmp;
359 uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */
360
361 left = malloc(MAX_CMD_BUFLEN);
362 if (left == NULL) {
363 fprintf(stderr, "out of memory in debugger_assignment()\n");
364 exit(1);
365 }
366 strlcpy(left, cmd, MAX_CMD_BUFLEN);
367 right = strchr(left, '=');
368 if (right == NULL) {
369 fprintf(stderr, "internal error in the debugger\n");
370 exit(1);
371 }
372 *right = '\0';
373
374 /* Remove trailing spaces in left: */
375 while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
376 left[strlen(left)-1] = '\0';
377
378 /* Remove leading spaces in right: */
379 right++;
380 while (*right == ' ' && *right != '\0')
381 right++;
382
383 /* printf("left = '%s'\nright = '%s'\n", left, right); */
384
385 res_right = debugger_parse_name(m, right, 0, &tmp);
386 switch (res_right) {
387 case NAME_PARSE_NOMATCH:
388 printf("No match for the right-hand side of the assignment.\n");
389 break;
390 case NAME_PARSE_MULTIPLE:
391 printf("Multiple matches for the right-hand side of the "
392 "assignment.\n");
393 break;
394 default:
395 res_left = debugger_parse_name(m, left, 1, &tmp);
396 switch (res_left) {
397 case NAME_PARSE_NOMATCH:
398 printf("No match for the left-hand side of the "
399 "assignment.\n");
400 break;
401 case NAME_PARSE_MULTIPLE:
402 printf("Multiple matches for the left-hand side "
403 "of the assignment.\n");
404 break;
405 default:
406 debugger_cmd_print(m, left);
407 }
408 }
409
410 /*
411 * If the PC has changed, then release any breakpoint we were
412 * currently stopped at.
413 *
414 * TODO: multiple cpus?
415 */
416 if (old_pc != m->cpus[0]->pc)
417 single_step_breakpoint = 0;
418
419 free(left);
420 }
421
422
423 /*
424 * debugger_execute_cmd():
425 */
426 void debugger_execute_cmd(char *cmd, int cmd_len)
427 {
428 int i, n, i_match, matchlen;
429
430 /*
431 * Is there a '=' on the command line? Then try to do an
432 * assignment. (Only if there is just one word, followed
433 * by the '=' sign. This makes it possible to use commands
434 * such as "device add name addr=xyz".)
435 */
436 if (strchr(cmd, '=') != NULL) {
437 /* Count the nr of words: */
438 int nw = 0, inword = 0;
439 char *p = cmd;
440 while (*p) {
441 if (*p == '=')
442 break;
443 if (*p != ' ') {
444 if (!inword)
445 nw ++;
446 inword = 1;
447 } else
448 inword = 0;
449 p++;
450 }
451
452 if (nw == 1) {
453 debugger_assignment(debugger_machine, cmd);
454 return;
455 }
456 }
457
458 i = 0;
459 while (cmds[i].name != NULL)
460 cmds[i++].tmp_flag = 0;
461
462 /* How many chars in cmd to match against: */
463 matchlen = 0;
464 while (isalpha((int)cmd[matchlen]))
465 matchlen ++;
466
467 /* Check for a command name match: */
468 n = i = i_match = 0;
469 while (cmds[i].name != NULL) {
470 if (strncasecmp(cmds[i].name, cmd, matchlen) == 0
471 && cmds[i].f != NULL) {
472 cmds[i].tmp_flag = 1;
473 i_match = i;
474 n++;
475 }
476 i++;
477 }
478
479 /* No match? */
480 if (n == 0) {
481 printf("Unknown command '%s'. Type 'help' for help.\n", cmd);
482 return;
483 }
484
485 /* More than one match? */
486 if (n > 1) {
487 printf("Ambiguous command '%s': ", cmd);
488 i = 0;
489 while (cmds[i].name != NULL) {
490 if (cmds[i].tmp_flag)
491 printf(" %s", cmds[i].name);
492 i++;
493 }
494 printf("\n");
495 return;
496 }
497
498 /* Exactly one match: */
499 if (cmds[i_match].f != NULL) {
500 char *p = cmd + matchlen;
501 /* Remove leading whitespace from the args... */
502 while (*p != '\0' && *p == ' ')
503 p++;
504
505 /* ... and run the command: */
506 cmds[i_match].f(debugger_machine, p);
507 } else
508 printf("FATAL ERROR: internal error in debugger.c:"
509 " no handler for this command?\n");
510 }
511
512
513 /*
514 * debugger_readline():
515 *
516 * Read a line from the terminal.
517 */
518 static char *debugger_readline(void)
519 {
520 int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
521 int read_from_index = last_cmd_index;
522 char *cmd = last_cmd[last_cmd_index];
523
524 cmd_len = 0; cmd[0] = '\0';
525 printf("GXemul> ");
526 fflush(stdout);
527
528 ch = '\0';
529 cmd_len = 0;
530 cursor_pos = 0;
531
532 while (ch != '\n' && !exit_debugger) {
533 ch = debugger_readchar();
534
535 if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
536 /* Backspace. */
537 cursor_pos --;
538 cmd_len --;
539 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
540 cmd_len);
541 cmd[cmd_len] = '\0';
542 printf("\b");
543 for (i=cursor_pos; i<cmd_len; i++)
544 printf("%c", cmd[i]);
545 printf(" \b");
546 for (i=cursor_pos; i<cmd_len; i++)
547 printf("\b");
548 } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
549 /* CTRL-D: Delete. */
550 cmd_len --;
551 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
552 cmd_len);
553 cmd[cmd_len] = '\0';
554 for (i=cursor_pos; i<cmd_len; i++)
555 printf("%c", cmd[i]);
556 printf(" \b");
557 for (i=cursor_pos; i<cmd_len; i++)
558 printf("\b");
559 } else if (ch == 1) {
560 /* CTRL-A: Start of line. */
561 while (cursor_pos > 0) {
562 cursor_pos --;
563 printf("\b");
564 }
565 } else if (ch == 2) {
566 /* CTRL-B: Backwards one character. */
567 if (cursor_pos > 0) {
568 printf("\b");
569 cursor_pos --;
570 }
571 } else if (ch == 5) {
572 /* CTRL-E: End of line. */
573 while (cursor_pos < cmd_len) {
574 printf("%c", cmd[cursor_pos]);
575 cursor_pos ++;
576 }
577 } else if (ch == 6) {
578 /* CTRL-F: Forward one character. */
579 if (cursor_pos < cmd_len) {
580 printf("%c",
581 cmd[cursor_pos]);
582 cursor_pos ++;
583 }
584 } else if (ch == 11) {
585 /* CTRL-K: Kill to end of line. */
586 for (i=0; i<MAX_CMD_BUFLEN; i++)
587 console_makeavail(MAIN_CONSOLE, 4); /* :-) */
588 } else if (ch == 14 || ch == 16) {
589 /* CTRL-P: Previous line in the command history,
590 CTRL-N: next line */
591 do {
592 if (ch == 14 &&
593 read_from_index == last_cmd_index)
594 break;
595 if (ch == 16)
596 i = read_from_index - 1;
597 else
598 i = read_from_index + 1;
599
600 if (i < 0)
601 i = N_PREVIOUS_CMDS - 1;
602 if (i >= N_PREVIOUS_CMDS)
603 i = 0;
604
605 /* Special case: pressing 'down'
606 to reach last_cmd_index: */
607 if (i == last_cmd_index) {
608 read_from_index = i;
609 for (i=cursor_pos; i<cmd_len;
610 i++)
611 printf(" ");
612 for (i=cmd_len-1; i>=0; i--)
613 printf("\b \b");
614 cmd[0] = '\0';
615 cmd_len = cursor_pos = 0;
616 } else if (last_cmd[i][0] != '\0') {
617 /* Copy from old line: */
618 read_from_index = i;
619 for (i=cursor_pos; i<cmd_len;
620 i++)
621 printf(" ");
622 for (i=cmd_len-1; i>=0; i--)
623 printf("\b \b");
624 strlcpy(cmd,
625 last_cmd[read_from_index],
626 MAX_CMD_BUFLEN);
627 cmd_len = strlen(cmd);
628 printf("%s", cmd);
629 cursor_pos = cmd_len;
630 }
631 } while (0);
632 } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) {
633 /* Visible character: */
634 memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
635 cmd_len - cursor_pos);
636 cmd[cursor_pos] = ch;
637 cmd_len ++;
638 cursor_pos ++;
639 cmd[cmd_len] = '\0';
640 printf("%c", ch);
641 for (i=cursor_pos; i<cmd_len; i++)
642 printf("%c", cmd[i]);
643 for (i=cursor_pos; i<cmd_len; i++)
644 printf("\b");
645 } else if (ch == '\r' || ch == '\n') {
646 ch = '\n';
647 printf("\n");
648 } else if (ch == '\t') {
649 /* Super-simple tab-completion: */
650 i = 0;
651 while (cmds[i].name != NULL)
652 cmds[i++].tmp_flag = 0;
653
654 /* Check for a (partial) command match: */
655 n = i = i_match = 0;
656 while (cmds[i].name != NULL) {
657 if (strncasecmp(cmds[i].name, cmd,
658 cmd_len) == 0) {
659 cmds[i].tmp_flag = 1;
660 i_match = i;
661 n++;
662 }
663 i++;
664 }
665
666 switch (n) {
667 case 0: /* Beep. */
668 printf("\a");
669 break;
670 case 1: /* Add the rest of the command: */
671 reallen = strlen(cmds[i_match].name);
672 for (i=cmd_len; i<reallen; i++)
673 console_makeavail(MAIN_CONSOLE,
674 cmds[i_match].name[i]);
675 /* ... and a space, if the command takes
676 any arguments: */
677 if (cmds[i_match].args != NULL &&
678 cmds[i_match].args[0] != '\0')
679 console_makeavail(MAIN_CONSOLE, ' ');
680 break;
681 default:
682 /* Show all possible commands: */
683 printf("\a\n"); /* Beep. :-) */
684 i = 0; /* i = cmds index */
685 j = 0; /* j = # of cmds printed */
686 while (cmds[i].name != NULL) {
687 if (cmds[i].tmp_flag) {
688 size_t q;
689 if (j == 0)
690 printf(" ");
691 printf("%s",
692 cmds[i].name);
693 j++;
694 if (j != 6)
695 for (q=0; q<13-strlen(
696 cmds[i].name); q++)
697 printf(" ");
698 if (j == 6) {
699 printf("\n");
700 j = 0;
701 }
702 }
703 i++;
704 }
705 if (j != 0)
706 printf("\n");
707 printf("GXemul> ");
708 for (i=0; i<cmd_len; i++)
709 printf("%c", cmd[i]);
710 }
711 } else if (ch == 27) {
712 /* Escape codes: (cursor keys etc) */
713 while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
714 usleep(1);
715 if (ch == '[' || ch == 'O') {
716 while ((ch = console_readchar(MAIN_CONSOLE))
717 < 0)
718 usleep(1);
719 switch (ch) {
720 case '2': /* 2~ = ins */
721 case '5': /* 5~ = pgup */
722 case '6': /* 6~ = pgdn */
723 /* TODO: Ugly hack, but might work. */
724 while ((ch = console_readchar(
725 MAIN_CONSOLE)) < 0)
726 usleep(1);
727 /* Do nothing for these keys. */
728 break;
729 case '3': /* 3~ = delete */
730 /* TODO: Ugly hack, but might work. */
731 while ((ch = console_readchar(
732 MAIN_CONSOLE)) < 0)
733 usleep(1);
734 console_makeavail(MAIN_CONSOLE, '\b');
735 break;
736 case 'A': /* Up. */
737 /* Up cursor ==> CTRL-P */
738 console_makeavail(MAIN_CONSOLE, 16);
739 break;
740 case 'B': /* Down. */
741 /* Down cursor ==> CTRL-N */
742 console_makeavail(MAIN_CONSOLE, 14);
743 break;
744 case 'C':
745 /* Right cursor ==> CTRL-F */
746 console_makeavail(MAIN_CONSOLE, 6);
747 break;
748 case 'D': /* Left */
749 /* Left cursor ==> CTRL-B */
750 console_makeavail(MAIN_CONSOLE, 2);
751 break;
752 case 'F':
753 /* End ==> CTRL-E */
754 console_makeavail(MAIN_CONSOLE, 5);
755 break;
756 case 'H':
757 /* Home ==> CTRL-A */
758 console_makeavail(MAIN_CONSOLE, 1);
759 break;
760 }
761 }
762 }
763
764 fflush(stdout);
765 }
766
767 if (exit_debugger)
768 cmd[0] = '\0';
769
770 return cmd;
771 }
772
773
774 /*
775 * debugger():
776 *
777 * This is a loop, which reads a command from the terminal, and executes it.
778 */
779 void debugger(void)
780 {
781 int i, cmd_len;
782 char *cmd;
783
784 if (debugger_n_steps_left_before_interaction > 0) {
785 debugger_n_steps_left_before_interaction --;
786 return;
787 }
788
789 /*
790 * Clear all dyntrans translations, because otherwise things would
791 * become to complex to keep in sync.
792 */
793 /* TODO: In all machines */
794 for (i=0; i<debugger_machine->ncpus; i++)
795 if (debugger_machine->cpus[i]->translation_cache != NULL)
796 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
797
798 /*
799 * Ugly GDB hack: After single stepping, we need to send back
800 * status to GDB:
801 */
802 if (exit_debugger == -1) {
803 int i, j;
804 for (i=0; i<debugger_n_emuls; i++) {
805 struct emul *e = debugger_emuls[i];
806 if (e == NULL)
807 continue;
808
809 for (j=0; j<e->n_machines; j++) {
810 if (e->machines[j]->gdb.port > 0)
811 debugger_gdb_after_singlestep(
812 e->machines[j]);
813 }
814 }
815 }
816
817
818 exit_debugger = 0;
819
820 while (!exit_debugger) {
821 /* Read a line from the terminal: */
822 cmd = debugger_readline();
823
824 /* Special hack for the "step" _GDB_ command: */
825 if (exit_debugger == -1)
826 return;
827
828 cmd_len = strlen(cmd);
829
830 /* Remove spaces: */
831 while (cmd_len > 0 && cmd[0]==' ')
832 memmove(cmd, cmd+1, cmd_len --);
833 while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
834 cmd[(cmd_len--)-1] = '\0';
835
836 /* No command? Then try reading another line. */
837 if (cmd_len == 0) {
838 /* Special case for repeated commands: */
839 if (repeat_cmd[0] != '\0')
840 strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN);
841 else
842 continue;
843 } else {
844 last_cmd_index ++;
845 if (last_cmd_index >= N_PREVIOUS_CMDS)
846 last_cmd_index = 0;
847
848 repeat_cmd[0] = '\0';
849 }
850
851 debugger_execute_cmd(cmd, cmd_len);
852
853 /* Special hack for the "step" command: */
854 if (exit_debugger == -1)
855 return;
856 }
857
858 gettimeofday(&debugger_machine->starttime, NULL);
859 debugger_machine->ncycles_since_gettimeofday = 0;
860
861 single_step = 0;
862 debugger_machine->instruction_trace = old_instruction_trace;
863 debugger_machine->show_trace_tree = old_show_trace_tree;
864 quiet_mode = old_quiet_mode;
865 }
866
867
868 /*
869 * debugger_reset():
870 *
871 * This function should be called before calling debugger(), when it is
872 * absolutely necessary that debugger() is interactive. Otherwise, it might
873 * return without doing anything, such as when single-stepping multiple
874 * instructions at a time.
875 */
876 void debugger_reset(void)
877 {
878 debugger_n_steps_left_before_interaction = 0;
879 }
880
881
882 /*
883 * debugger_init():
884 *
885 * Must be called before any other debugger function is used.
886 */
887 void debugger_init(struct emul **emuls, int n_emuls)
888 {
889 int i, j;
890
891 debugger_n_emuls = n_emuls;
892 debugger_emuls = emuls;
893
894 if (n_emuls < 1) {
895 fprintf(stderr, "\nERROR: No emuls (?)\n");
896 exit(1);
897 }
898
899 debugger_emul = emuls[0];
900 if (emuls[0]->n_machines < 1) {
901 fprintf(stderr, "\nERROR: No machines in emuls[0], "
902 "cannot handle this situation yet.\n\n");
903 exit(1);
904 }
905
906 for (i=0; i<n_emuls; i++)
907 for (j=0; j<emuls[i]->n_machines; j++)
908 debugger_gdb_init(emuls[i]->machines[j]);
909
910 debugger_machine = emuls[0]->machines[0];
911
912 for (i=0; i<N_PREVIOUS_CMDS; i++) {
913 last_cmd[i] = malloc(MAX_CMD_BUFLEN);
914 if (last_cmd[i] == NULL) {
915 fprintf(stderr, "debugger_init(): out of memory\n");
916 exit(1);
917 }
918 last_cmd[i][0] = '\0';
919 }
920
921 last_cmd_index = 0;
922 repeat_cmd[0] = '\0';
923 }
924

  ViewVC Help
Powered by ViewVC 1.1.26