1G pages support for CPU
[bochs-mirror.git] / bx_debug / dbg_main.cc
blob677af8be0131fb3c4ee00c5c6df78463d1ff15b8
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: dbg_main.cc,v 1.165 2008/12/08 20:20:30 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 extern "C" {
29 #include <signal.h>
32 #include "bochs.h"
33 #include "cpu/cpu.h"
34 #include "iodev/iodev.h"
35 #if BX_DEBUGGER
37 #define LOG_THIS genlog->
39 #if HAVE_LIBREADLINE
40 extern "C" {
41 #include <stdio.h>
42 #include <readline/readline.h>
43 #if HAVE_READLINE_HISTORY_H
44 #include <readline/history.h>
45 #endif
47 #endif
49 // default CPU in the debugger. For commands like "dump_cpu" it will
50 // use the default instead of always dumping all cpus.
51 unsigned dbg_cpu = 0;
52 bx_list_c *dbg_cpu_list = 0;
54 extern const char* cpu_mode_string(unsigned cpu_mode);
55 extern void bx_sr_after_restore_state(void);
57 static bx_param_bool_c *sim_running = NULL;
59 static char tmp_buf[512];
60 static char tmp_buf_prev[512];
61 static char *tmp_buf_ptr;
62 static char *argv0 = NULL;
64 static FILE *debugger_log = NULL;
66 static struct {
67 // some fields used for single CPU debugger
68 bx_bool auto_disassemble;
69 unsigned disassemble_size;
70 char default_display_format;
71 char default_unit_size;
72 Bit32u default_addr;
73 unsigned next_bpoint_id;
74 unsigned next_wpoint_id;
75 } bx_debugger;
77 typedef struct {
78 FILE *fp;
79 char fname[BX_MAX_PATH];
80 unsigned lineno;
81 } bx_infile_stack_entry_t;
83 bx_infile_stack_entry_t bx_infile_stack[BX_INFILE_DEPTH];
84 int bx_infile_stack_index = 0;
86 static int bx_nest_infile(char *path);
88 void bx_debug_ctrlc_handler(int signum);
90 static void bx_unnest_infile(void);
91 static void bx_get_command(void);
92 static void bx_dbg_print_guard_results();
93 static void bx_dbg_breakpoint_changed(void);
95 bx_guard_t bx_guard;
97 // DMA stuff
98 void bx_dbg_post_dma_reports(void);
99 #define BX_BATCH_DMA_BUFSIZE 512
101 static struct {
102 unsigned this_many; // batch this many max before posting events
103 unsigned Qsize; // this many have been batched
104 struct {
105 bx_phy_address addr; // address of DMA op
106 unsigned len; // number of bytes in op
107 unsigned what; // BX_READ or BX_WRITE
108 Bit32u val; // value of DMA op
109 Bit64u time; // system time at this dma op
110 } Q[BX_BATCH_DMA_BUFSIZE];
111 } bx_dbg_batch_dma;
113 // some buffers for disassembly
114 static disassembler bx_disassemble;
115 static Bit8u bx_disasm_ibuf[32];
116 static char bx_disasm_tbuf[512];
118 unsigned num_write_watchpoints = 0;
119 unsigned num_read_watchpoints = 0;
120 bx_phy_address write_watchpoint[BX_DBG_MAX_WATCHPONTS];
121 bx_phy_address read_watchpoint[BX_DBG_MAX_WATCHPONTS];
122 bx_bool watchpoint_continue = 0;
124 #define DBG_PRINTF_BUFFER_LEN 1024
126 void dbg_printf(const char *fmt, ...)
128 va_list ap;
129 va_start(ap, fmt);
130 char *buf = new char[DBG_PRINTF_BUFFER_LEN+1];
131 vsnprintf(buf, DBG_PRINTF_BUFFER_LEN, fmt, ap);
132 va_end(ap);
133 if (debugger_log != NULL) {
134 fprintf(debugger_log,"%s", buf);
135 fflush(debugger_log);
137 SIM->debug_puts(buf); // send to debugger, which will free buf when done.
140 void bx_dbg_init_infile(void)
142 bx_infile_stack_index = 0;
143 bx_infile_stack[0].fp = stdin;
144 bx_infile_stack[0].lineno = 0;
147 int bx_dbg_set_rcfile(const char *rcfile)
149 strncpy(bx_infile_stack[0].fname, rcfile, BX_MAX_PATH);
150 bx_infile_stack[0].fname[BX_MAX_PATH-1] = 0;
151 BX_INFO(("debugger using rc file '%s'.", rcfile));
152 return bx_nest_infile((char*)rcfile);
155 int bx_dbg_main(void)
157 setbuf(stdout, NULL);
158 setbuf(stderr, NULL);
160 bx_dbg_batch_dma.this_many = 1;
161 bx_dbg_batch_dma.Qsize = 0;
163 memset(&bx_guard, 0, sizeof(bx_guard));
164 bx_guard.async.irq = 1;
165 bx_guard.async.dma = 1;
167 memset(&bx_debugger, 0, sizeof(bx_debugger));
168 bx_debugger.auto_disassemble = 1;
169 bx_debugger.disassemble_size = 0;
170 bx_debugger.default_display_format = 'x';
171 bx_debugger.default_unit_size = 'w';
172 bx_debugger.default_addr = 0;
173 bx_debugger.next_bpoint_id = 1;
174 bx_debugger.next_wpoint_id = 1;
176 dbg_cpu_list = (bx_list_c*) SIM->get_param("cpu0", SIM->get_bochs_root());
177 const char *debugger_log_filename = SIM->get_param_string(BXPN_DEBUGGER_LOG_FILENAME)->getptr();
179 // Open debugger log file if needed
180 if (strlen(debugger_log_filename) > 0 && (strcmp(debugger_log_filename, "-") != 0))
182 debugger_log = fopen(debugger_log_filename, "w");
183 if (!debugger_log) {
184 BX_PANIC(("Can not open debugger log file '%s'", debugger_log_filename));
186 else {
187 BX_INFO(("Using debugger log file %s", debugger_log_filename));
191 memset(bx_disasm_ibuf, 0, sizeof(bx_disasm_ibuf));
193 // create a boolean parameter that will tell if the simulation is
194 // running (continue command) or waiting for user response. This affects
195 // some parts of the GUI.
196 if (sim_running == NULL) {
197 bx_list_c *base = (bx_list_c*) SIM->get_param("general");
198 sim_running = new bx_param_bool_c(base,
199 "debug_running",
200 "Simulation is running", "", 0);
201 } else {
202 sim_running->set(0);
204 // setup Ctrl-C handler
205 if (!SIM->has_debug_gui()) {
206 signal(SIGINT, bx_debug_ctrlc_handler);
207 BX_INFO(("set SIGINT handler to bx_debug_ctrlc_handler"));
210 // Print disassembly of the first instruction... you wouldn't think it
211 // would have to be so hard. First initialize guard_found, since it is used
212 // in the disassembly code to decide what instruction to print.
213 for (int i=0; i<BX_SMP_PROCESSORS; i++) {
214 BX_CPU(i)->guard_found.cs = BX_CPU(i)->sregs[BX_SEG_REG_CS].selector.value;
215 BX_CPU(i)->guard_found.eip = BX_CPU(i)->prev_rip;
216 BX_CPU(i)->guard_found.laddr =
217 BX_CPU(i)->get_laddr(BX_SEG_REG_CS, BX_CPU(i)->prev_rip);
218 BX_CPU(i)->guard_found.is_32bit_code =
219 (BX_CPU(i)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b);
220 BX_CPU(i)->guard_found.is_64bit_code =
221 (BX_CPU(i)->get_cpu_mode() == BX_MODE_LONG_64);
223 // finally, call the usual function to print the disassembly
224 dbg_printf("Next at t=" FMT_LL "d\n", bx_pc_system.time_ticks());
225 bx_dbg_disassemble_current(-1, 0); // all cpus, don't print time
227 bx_dbg_user_input_loop();
229 if(debugger_log != NULL)
230 fclose(debugger_log);
232 bx_dbg_exit(0);
233 return(0); // keep compiler happy
236 void bx_dbg_interpret_line(char *cmd)
238 bx_add_lex_input(cmd);
239 bxparse();
242 void bx_dbg_user_input_loop(void)
244 int reti;
245 unsigned include_cmd_len = strlen(BX_INCLUDE_CMD);
247 while(1) {
248 SIM->refresh_ci();
249 SIM->set_display_mode(DISP_MODE_CONFIG);
250 bx_get_command();
251 reparse:
252 if ((*tmp_buf_ptr == '\n') || (*tmp_buf_ptr == 0))
254 if ((*tmp_buf_prev != '\n') && (*tmp_buf_prev != 0)) {
255 strncpy(tmp_buf, tmp_buf_prev, sizeof(tmp_buf_prev));
256 goto reparse;
259 else if ((strncmp(tmp_buf_ptr, BX_INCLUDE_CMD, include_cmd_len) == 0) &&
260 (tmp_buf_ptr[include_cmd_len] == ' ' ||
261 tmp_buf_ptr[include_cmd_len] == '\t'))
263 char *ptr = tmp_buf_ptr + include_cmd_len+1;
264 while(*ptr==' ' || *ptr=='\t')
265 ptr++;
267 int len = strlen(ptr);
268 if (len == 0) {
269 dbg_printf("%s: no filename given to 'source' command.\n", argv0);
270 if (bx_infile_stack_index > 0) {
271 dbg_printf("%s: ERROR in source file causes exit.\n", argv0);
272 bx_dbg_exit(1);
274 continue;
276 ptr[len-1] = 0; // get rid of newline
277 reti = bx_nest_infile(ptr);
278 if ((reti==0) && (bx_infile_stack_index > 0)) {
279 dbg_printf("%s: ERROR in source file causes exit.\n", argv0);
280 bx_dbg_exit(1);
283 else {
284 // Give a chance to the command line extensions, to
285 // consume the command. If they return 0, then
286 // we need to process the command. A return of 1
287 // means, the extensions have handled the command
288 if (bx_dbg_extensions(tmp_buf_ptr)==0) {
289 // process command here
290 bx_add_lex_input(tmp_buf_ptr);
291 bxparse();
297 void bx_get_command(void)
299 char *charptr_ret;
301 bx_infile_stack[bx_infile_stack_index].lineno++;
303 char prompt[256];
304 if (bx_infile_stack_index == 0) {
305 sprintf(prompt, "<bochs:%d> ", bx_infile_stack[bx_infile_stack_index].lineno);
307 if (SIM->has_debug_gui() && bx_infile_stack_index == 0) {
308 // wait for wxWidgets to send another debugger command
309 charptr_ret = SIM->debug_get_next_command();
310 if (charptr_ret) {
311 strncpy(tmp_buf, charptr_ret, sizeof(tmp_buf));
312 strcat(tmp_buf, "\n");
313 // The returned string was allocated in wxmain.cc by "new char[]".
314 // Free it with delete[].
315 delete [] charptr_ret;
316 charptr_ret = &tmp_buf[0];
317 } else {
318 // if debug_get_next_command returned NULL, probably the GUI is
319 // shutting down
322 #if HAVE_LIBREADLINE
323 else if (bx_infile_stack_index == 0) {
324 charptr_ret = readline(prompt);
325 // beware, returns NULL on end of file
326 if (charptr_ret && strlen(charptr_ret) > 0) {
327 add_history(charptr_ret);
328 strcpy(tmp_buf, charptr_ret);
329 strcat(tmp_buf, "\n");
330 free(charptr_ret);
331 charptr_ret = &tmp_buf[0];
333 } else {
334 charptr_ret = fgets(tmp_buf, sizeof(tmp_buf),
335 bx_infile_stack[bx_infile_stack_index].fp);
337 #else /* !HAVE_LIBREADLINE */
338 else {
339 if (bx_infile_stack_index == 0)
340 dbg_printf("%s", prompt);
341 strncpy(tmp_buf_prev, tmp_buf, sizeof(tmp_buf));
342 charptr_ret = fgets(tmp_buf, sizeof(tmp_buf),
343 bx_infile_stack[bx_infile_stack_index].fp);
345 #endif
346 if (charptr_ret == NULL) {
347 // see if error was due to EOF condition
348 if (feof(bx_infile_stack[bx_infile_stack_index].fp)) {
349 if (bx_infile_stack_index > 0) {
350 // nested level of include files, pop back to previous one
351 bx_unnest_infile();
353 else {
354 // not nested, sitting at stdin prompt, user wants out
355 bx_dbg_quit_command();
356 BX_PANIC(("bx_dbg_quit_command should not return, but it did"));
359 // call recursively
360 bx_get_command();
361 return;
364 // error was not EOF, see if it was from a Ctrl-C
365 if (bx_guard.interrupt_requested) {
366 tmp_buf[0] = '\n';
367 tmp_buf[1] = 0;
368 tmp_buf_ptr = &tmp_buf[0];
369 bx_guard.interrupt_requested = 0;
370 return;
373 dbg_printf("fgets() returned ERROR.\n");
374 dbg_printf("intr request was %u\n", bx_guard.interrupt_requested);
375 bx_dbg_exit(1);
377 tmp_buf_ptr = &tmp_buf[0];
379 if (debugger_log != NULL) {
380 fprintf(debugger_log, "%s", tmp_buf);
381 fflush(debugger_log);
384 // look for first non-whitespace character
385 while (((*tmp_buf_ptr == ' ') || (*tmp_buf_ptr == '\t')) &&
386 (*tmp_buf_ptr != '\n') && (*tmp_buf_ptr != 0))
388 tmp_buf_ptr++;
392 int bx_nest_infile(char *path)
394 FILE *tmp_fp;
396 tmp_fp = fopen(path, "r");
397 if (!tmp_fp) {
398 dbg_printf("%s: can not open file '%s' for reading.\n", argv0, path);
399 return(0);
402 if ((bx_infile_stack_index+1) >= BX_INFILE_DEPTH) {
403 dbg_printf("%s: source files nested too deeply\n", argv0);
404 return(0);
407 bx_infile_stack_index++;
408 bx_infile_stack[bx_infile_stack_index].fp = tmp_fp;
409 strncpy(bx_infile_stack[bx_infile_stack_index].fname, path, BX_MAX_PATH);
410 bx_infile_stack[bx_infile_stack_index].fname[BX_MAX_PATH-1] = 0;
411 bx_infile_stack[bx_infile_stack_index].lineno = 0;
412 return(1);
415 void bx_unnest_infile(void)
417 if (bx_infile_stack_index <= 0) {
418 dbg_printf("%s: ERROR: unnest_infile(): nesting level = 0.\n",
419 argv0);
420 bx_dbg_exit(1);
423 fclose(bx_infile_stack[bx_infile_stack_index].fp);
424 bx_infile_stack_index--;
427 int bxwrap(void)
429 dbg_printf("%s: ERROR: bxwrap() called.\n", argv0);
430 bx_dbg_exit(1);
431 return(0); // keep compiler quiet
434 #ifdef WIN32
435 char* bxtext;
436 #endif
438 void bxerror(char *s)
440 dbg_printf("%s:%d: %s at '%s'\n",
441 bx_infile_stack[bx_infile_stack_index].fname,
442 bx_infile_stack[bx_infile_stack_index].lineno,
443 s, bxtext);
445 if (bx_infile_stack_index > 0) {
446 dbg_printf("%s: ERROR in source file causes exit.\n", argv0);
447 bx_dbg_exit(1);
451 void bx_debug_ctrlc_handler(int signum)
453 UNUSED(signum);
454 if (SIM->has_debug_gui()) {
455 // in a multithreaded environment, a signal such as SIGINT can be sent to all
456 // threads. This function is only intended to handle signals in the
457 // simulator thread. It will simply return if called from any other thread.
458 // Otherwise the BX_PANIC() below can be called in multiple threads at
459 // once, leading to multiple threads trying to display a dialog box,
460 // leading to GUI deadlock.
461 if (!SIM->is_sim_thread()) {
462 BX_INFO(("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum));
463 return;
466 BX_INFO(("Ctrl-C detected in signal handler."));
468 signal(SIGINT, bx_debug_ctrlc_handler);
469 bx_debug_break();
472 void bx_debug_break()
474 bx_guard.interrupt_requested = 1;
477 void bx_dbg_exception(unsigned cpu, Bit8u vector, Bit16u error_code)
479 static const char *exception[] = {
480 "(#DE) divide by zero",
481 "(#DB) debug break",
482 "(#NMI)",
483 "(#BP) breakpoint match",
484 "(#OF) overflow",
485 "(#BR) boundary check",
486 "(#UD) undefined opcode",
487 "(#NM) device not available",
488 "(#DF) double fault",
489 "(#CO) coprocessor overrun",
490 "(#TS) invalid TSS",
491 "(#NP) segment not present",
492 "(#SS) stack fault",
493 "(#GP) general protection fault",
494 "(#PF) page fault",
495 "(#RESERVED)",
496 "(#MF) floating point error",
497 "(#AC) alignment check",
498 "(#MC) machine check",
499 "(#XF) SIMD floating point exception",
502 if (BX_CPU(dbg_cpu)->trace || bx_dbg.exceptions)
504 if (vector <= BX_XM_EXCEPTION) {
505 dbg_printf("CPU %d: Exception 0x%02x - %s occured (error_code=0x%04x)\n",
506 cpu, vector, exception[vector], error_code);
508 else {
509 dbg_printf("CPU %d: Exception 0x%02x occured (error_code=0x%04x)\n",
510 cpu, vector, error_code);
515 void bx_dbg_interrupt(unsigned cpu, Bit8u vector, Bit16u error_code)
517 if (BX_CPU(dbg_cpu)->trace || bx_dbg.interrupts)
519 dbg_printf("CPU %d: Interrupt 0x%02x occured (error_code=0x%04x)\n",
520 cpu, vector, error_code);
524 void bx_dbg_halt(unsigned cpu)
526 if (BX_CPU(dbg_cpu)->trace)
528 dbg_printf("CPU %d: HALTED\n", cpu);
532 void bx_dbg_check_memory_watchpoints(unsigned cpu, bx_phy_address phy, unsigned len, unsigned rw)
534 if (rw & 1) {
535 // Check for physical write watch points
536 for (unsigned i = 0; i < num_write_watchpoints; i++) {
537 if (write_watchpoint[i] >= phy && write_watchpoint[i] < (phy + len)) {
538 BX_CPU(cpu)->watchpoint = phy;
539 BX_CPU(cpu)->break_point = rw;
540 break;
544 else {
545 // Check for physical read watch points
546 for (unsigned i = 0; i < num_read_watchpoints; i++) {
547 if (read_watchpoint[i] >= phy && read_watchpoint[i] < (phy + len)) {
548 BX_CPU(cpu)->watchpoint = phy;
549 BX_CPU(cpu)->break_point = rw;
550 break;
556 void bx_dbg_lin_memory_access(unsigned cpu, bx_address lin, bx_phy_address phy, unsigned len, unsigned pl, unsigned rw, Bit8u *data)
558 bx_dbg_check_memory_watchpoints(cpu, phy, len, rw);
560 if (! BX_CPU(cpu)->trace_mem)
561 return;
563 bx_bool write = rw & 1;
565 dbg_printf("[CPU%d %s]: LIN 0x" FMT_ADDRX " PHY 0x" FMT_PHY_ADDRX " (len=%d, pl=%d)",
566 cpu,
567 (write) ? "WR" : "RD",
568 lin, phy,
569 len, pl);
571 if (len == 1) {
572 Bit8u val8 = *data;
573 dbg_printf(": 0x%02X", (unsigned) val8);
575 else if (len == 2) {
576 Bit16u val16 = *((Bit16u*) data);
577 dbg_printf(": 0x%04X", (unsigned) val16);
579 else if (len == 4) {
580 Bit32u val32 = *((Bit32u*) data);
581 dbg_printf(": 0x%08X", (unsigned) val32);
583 else if (len == 8) {
584 Bit64u data64 = * (Bit64u*)(data);
585 dbg_printf(": 0x%08X 0x%08X", GET32H(data64), GET32L(data64));
587 #if BX_CPU_LEVEL >= 6
588 else if (len == 16) {
589 const BxPackedXmmRegister *xmmdata = (const BxPackedXmmRegister*)(data);
590 dbg_printf(": 0x%08X 0x%08X 0x%08X 0x%08X",
591 xmmdata->xmm32u(3), xmmdata->xmm32u(2), xmmdata->xmm32u(1), xmmdata->xmm32u(0));
593 #endif
595 dbg_printf("\n");
598 void bx_dbg_phy_memory_access(unsigned cpu, bx_phy_address phy, unsigned len, unsigned rw, Bit8u *data)
600 bx_dbg_check_memory_watchpoints(cpu, phy, len, rw);
602 if (! BX_CPU(cpu)->trace_mem)
603 return;
605 bx_bool write = rw & 1;
607 dbg_printf("[CPU%d %s]: PHY 0x" FMT_PHY_ADDRX " (len=%d)",
608 cpu,
609 (write) ? "WR" : "RD",
610 phy,
611 len);
613 if (len == 1) {
614 Bit8u val8 = *data;
615 dbg_printf(": 0x%02X", (unsigned) val8);
617 else if (len == 2) {
618 Bit16u val16 = *((Bit16u*) data);
619 dbg_printf(": 0x%04X", (unsigned) val16);
621 else if (len == 4) {
622 Bit32u val32 = *((Bit32u*) data);
623 dbg_printf(": 0x%08X", (unsigned) val32);
625 else if (len == 8) {
626 Bit64u data64 = * (Bit64u*)(data);
627 dbg_printf(": 0x%08X 0x%08X", GET32H(data64), GET32L(data64));
629 #if BX_CPU_LEVEL >= 6
630 else if (len == 16) {
631 const BxPackedXmmRegister *xmmdata = (const BxPackedXmmRegister*)(data);
632 dbg_printf(": 0x%08X 0x%08X 0x%08X 0x%08X",
633 xmmdata->xmm32u(3), xmmdata->xmm32u(2), xmmdata->xmm32u(1), xmmdata->xmm32u(0));
635 #endif
637 dbg_printf("\n");
640 void bx_dbg_exit(int code)
642 BX_DEBUG(("dbg: before exit"));
643 for (int cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
644 if (BX_CPU(cpu)) BX_CPU(cpu)->atexit();
647 bx_atexit();
648 BX_EXIT(code);
652 // functions for browsing of cpu state
655 void bx_dbg_print_sse_state(void)
657 #if BX_SUPPORT_SSE
658 Bit32u mxcsr = SIM->get_param_num("SSE.mxcsr", dbg_cpu_list)->get();
659 dbg_printf("MXCSR: 0x%08x\n", mxcsr);
661 char param_name[20];
662 for(unsigned i=0;i<BX_XMM_REGISTERS;i++) {
663 sprintf(param_name, "SSE.xmm%02d_hi", i);
664 Bit64u hi = SIM->get_param_num(param_name, dbg_cpu_list)->get64();
665 sprintf(param_name, "SSE.xmm%02d_lo", i);
666 Bit64u lo = SIM->get_param_num(param_name, dbg_cpu_list)->get64();
667 dbg_printf("XMM[%02u]: %08x%08x:%08x%08x\n", i,
668 GET32H(hi), GET32L(hi), GET32H(lo), GET32L(lo));
670 #else
671 dbg_printf("The CPU doesn't support SSE state !\n");
672 #endif
675 void bx_dbg_print_mmx_state(void)
677 #if BX_SUPPORT_MMX
678 char param_name[20];
679 for(unsigned i=0;i<8;i++) {
680 sprintf(param_name, "FPU.st%d.fraction", i);
681 Bit64u mmreg = SIM->get_param_num(param_name, dbg_cpu_list)->get64();
682 dbg_printf("MM[%d]: %08x:%08x\n", i, GET32H(mmreg), GET32L(mmreg));
684 #else
685 dbg_printf("The CPU doesn't support MMX state !\n");
686 #endif
689 void bx_dbg_print_fpu_state(void)
691 #if BX_SUPPORT_FPU
692 BX_CPU(dbg_cpu)->print_state_FPU();
693 #else
694 dbg_printf("The CPU doesn't support FPU state !\n");
695 #endif
698 void bx_dbg_info_flags(void)
700 dbg_printf("%s %s %s %s %s %s %s IOPL=%1u %s %s %s %s %s %s %s %s %s\n",
701 BX_CPU(dbg_cpu)->get_ID() ? "ID" : "id",
702 BX_CPU(dbg_cpu)->get_VIP() ? "VIP" : "vip",
703 BX_CPU(dbg_cpu)->get_VIF() ? "VIF" : "vif",
704 BX_CPU(dbg_cpu)->get_AC() ? "AC" : "ac",
705 BX_CPU(dbg_cpu)->get_VM() ? "VM" : "vm",
706 BX_CPU(dbg_cpu)->get_RF() ? "RF" : "rf",
707 BX_CPU(dbg_cpu)->get_NT() ? "NT" : "nt",
708 BX_CPU(dbg_cpu)->get_IOPL(),
709 BX_CPU(dbg_cpu)->get_OF() ? "OF" : "of",
710 BX_CPU(dbg_cpu)->get_DF() ? "DF" : "df",
711 BX_CPU(dbg_cpu)->get_IF() ? "IF" : "if",
712 BX_CPU(dbg_cpu)->get_TF() ? "TF" : "tf",
713 BX_CPU(dbg_cpu)->get_SF() ? "SF" : "sf",
714 BX_CPU(dbg_cpu)->get_ZF() ? "ZF" : "zf",
715 BX_CPU(dbg_cpu)->get_AF() ? "AF" : "af",
716 BX_CPU(dbg_cpu)->get_PF() ? "PF" : "pf",
717 BX_CPU(dbg_cpu)->get_CF() ? "CF" : "cf");
720 void bx_dbg_info_control_regs_command(void)
722 Bit32u cr0 = SIM->get_param_num("CR0", dbg_cpu_list)->get();
723 bx_address cr2 = (bx_address) SIM->get_param_num("CR2", dbg_cpu_list)->get64();
724 bx_phy_address cr3 = (bx_phy_address) SIM->get_param_num("CR3", dbg_cpu_list)->get64();
725 dbg_printf("CR0=0x%08x: %s %s %s %s %s %s %s %s %s %s %s\n", cr0,
726 (cr0 & (1<<31)) ? "PG" : "pg",
727 (cr0 & (1<<30)) ? "CD" : "cd",
728 (cr0 & (1<<29)) ? "NW" : "nw",
729 (cr0 & (1<<18)) ? "AC" : "ac",
730 (cr0 & (1<<16)) ? "WP" : "wp",
731 (cr0 & (1<<5)) ? "NE" : "ne",
732 (cr0 & (1<<4)) ? "ET" : "et",
733 (cr0 & (1<<3)) ? "TS" : "ts",
734 (cr0 & (1<<2)) ? "EM" : "em",
735 (cr0 & (1<<1)) ? "MP" : "mp",
736 (cr0 & (1<<0)) ? "PE" : "pe");
737 dbg_printf("CR2=page fault laddr=0x" FMT_ADDRX "\n", cr2);
738 dbg_printf("CR3=0x" FMT_PHY_ADDRX "\n", cr3);
739 dbg_printf(" PCD=page-level cache disable=%d\n", (cr3>>4) & 1);
740 dbg_printf(" PWT=page-level writes transparent=%d\n", (cr3>>3) & 1);
741 #if BX_CPU_LEVEL >= 4
742 Bit32u cr4 = SIM->get_param_num("CR4", dbg_cpu_list)->get();
743 dbg_printf("CR4=0x%08x: %s %s %s %s %s %s %s %s %s %s %s\n", cr4,
744 (cr4 & (1<<10)) ? "OSXMMEXCPT" : "osxmmexcpt",
745 (cr4 & (1<<9)) ? "OSFXSR" : "osfxsr",
746 (cr4 & (1<<8)) ? "PCE" : "pce",
747 (cr4 & (1<<7)) ? "PGE" : "pge",
748 (cr4 & (1<<6)) ? "MCE" : "mce",
749 (cr4 & (1<<5)) ? "PAE" : "pae",
750 (cr4 & (1<<4)) ? "PSE" : "pse",
751 (cr4 & (1<<3)) ? "DE" : "de",
752 (cr4 & (1<<2)) ? "TSD" : "tsd",
753 (cr4 & (1<<1)) ? "PVI" : "pvi",
754 (cr4 & (1<<0)) ? "VME" : "vme");
755 #endif
756 #if BX_SUPPORT_X86_64
757 Bit32u efer = SIM->get_param_num("MSR.EFER", dbg_cpu_list)->get();
758 dbg_printf("EFER=0x%08x: %s %s %s %s %s\n", efer,
759 (efer & (1<<14)) ? "FFXSR" : "ffxsr",
760 (efer & (1<<11)) ? "NXE" : "nxe",
761 (efer & (1<<10)) ? "LMA" : "lma",
762 (efer & (1<<8)) ? "LME" : "lme",
763 (efer & (1<<0)) ? "SCE" : "sce");
764 #endif
767 void bx_dbg_info_segment_regs_command(void)
769 bx_dbg_sreg_t sreg;
770 bx_dbg_global_sreg_t global_sreg;
772 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_CS);
773 dbg_printf("cs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
774 (unsigned) sreg.sel, (unsigned) sreg.des_l,
775 (unsigned) sreg.des_h, (unsigned) sreg.valid);
777 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_DS);
778 dbg_printf("ds:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
779 (unsigned) sreg.sel, (unsigned) sreg.des_l,
780 (unsigned) sreg.des_h, (unsigned) sreg.valid);
782 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_SS);
783 dbg_printf("ss:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
784 (unsigned) sreg.sel, (unsigned) sreg.des_l,
785 (unsigned) sreg.des_h, (unsigned) sreg.valid);
787 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_ES);
788 dbg_printf("es:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
789 (unsigned) sreg.sel, (unsigned) sreg.des_l,
790 (unsigned) sreg.des_h, (unsigned) sreg.valid);
792 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_FS);
793 dbg_printf("fs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
794 (unsigned) sreg.sel, (unsigned) sreg.des_l,
795 (unsigned) sreg.des_h, (unsigned) sreg.valid);
797 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, BX_DBG_SREG_GS);
798 dbg_printf("gs:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
799 (unsigned) sreg.sel, (unsigned) sreg.des_l,
800 (unsigned) sreg.des_h, (unsigned) sreg.valid);
802 BX_CPU(dbg_cpu)->dbg_get_ldtr(&sreg);
803 dbg_printf("ldtr:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
804 (unsigned) sreg.sel, (unsigned) sreg.des_l,
805 (unsigned) sreg.des_h, (unsigned) sreg.valid);
807 BX_CPU(dbg_cpu)->dbg_get_tr(&sreg);
808 dbg_printf("tr:s=0x%04x, dl=0x%08x, dh=0x%08x, valid=%u\n",
809 (unsigned) sreg.sel, (unsigned) sreg.des_l,
810 (unsigned) sreg.des_h, (unsigned) sreg.valid);
812 BX_CPU(dbg_cpu)->dbg_get_gdtr(&global_sreg);
813 dbg_printf("gdtr:base=0x%08x, limit=0x%x\n",
814 (unsigned) global_sreg.base, (unsigned) global_sreg.limit);
816 BX_CPU(dbg_cpu)->dbg_get_idtr(&global_sreg);
817 dbg_printf("idtr:base=0x%08x, limit=0x%x\n",
818 (unsigned) global_sreg.base, (unsigned) global_sreg.limit);
821 void bx_dbg_info_registers_command(int which_regs_mask)
823 bx_address reg;
825 if (which_regs_mask & BX_INFO_GENERAL_PURPOSE_REGS) {
826 #if BX_SUPPORT_SMP
827 dbg_printf("%s:\n", BX_CPU(dbg_cpu)->name);
828 #endif
829 #if BX_SUPPORT_X86_64 == 0
830 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EAX);
831 dbg_printf("eax: 0x%08x %d\n", (unsigned) reg, (int) reg);
832 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ECX);
833 dbg_printf("ecx: 0x%08x %d\n", (unsigned) reg, (int) reg);
834 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EDX);
835 dbg_printf("edx: 0x%08x %d\n", (unsigned) reg, (int) reg);
836 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBX);
837 dbg_printf("ebx: 0x%08x %d\n", (unsigned) reg, (int) reg);
838 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESP);
839 dbg_printf("esp: 0x%08x %d\n", (unsigned) reg, (int) reg);
840 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBP);
841 dbg_printf("ebp: 0x%08x %d\n", (unsigned) reg, (int) reg);
842 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESI);
843 dbg_printf("esi: 0x%08x %d\n", (unsigned) reg, (int) reg);
844 reg = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EDI);
845 dbg_printf("edi: 0x%08x %d\n", (unsigned) reg, (int) reg);
846 reg = bx_dbg_get_eip();
847 dbg_printf("eip: 0x%08x\n", (unsigned) reg);
848 #else
849 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RAX);
850 dbg_printf("rax: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
851 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RCX);
852 dbg_printf("rcx: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
853 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RDX);
854 dbg_printf("rdx: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
855 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RBX);
856 dbg_printf("rbx: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
857 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RSP);
858 dbg_printf("rsp: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
859 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RBP);
860 dbg_printf("rbp: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
861 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RSI);
862 dbg_printf("rsi: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
863 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RDI);
864 dbg_printf("rdi: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
865 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R8);
866 dbg_printf("r8 : 0x%08x:%08x ", GET32H(reg), GET32L(reg));
867 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R9);
868 dbg_printf("r9 : 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
869 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R10);
870 dbg_printf("r10: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
871 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R11);
872 dbg_printf("r11: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
873 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R12);
874 dbg_printf("r12: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
875 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R13);
876 dbg_printf("r13: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
877 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R14);
878 dbg_printf("r14: 0x%08x:%08x ", GET32H(reg), GET32L(reg));
879 reg = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_R15);
880 dbg_printf("r15: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
881 reg = bx_dbg_get_instruction_pointer();
882 dbg_printf("rip: 0x%08x:%08x\n", GET32H(reg), GET32L(reg));
883 #endif
884 reg = BX_CPU(dbg_cpu)->read_eflags();
885 dbg_printf("eflags 0x%08x\n", (unsigned) reg);
886 bx_dbg_info_flags();
889 #if BX_SUPPORT_FPU
890 if (which_regs_mask & BX_INFO_FPU_REGS) {
891 bx_dbg_print_fpu_state();
893 #endif
895 if (which_regs_mask & BX_INFO_MMX_REGS) {
896 bx_dbg_print_mmx_state();
899 if (which_regs_mask & BX_INFO_SSE_REGS) {
900 bx_dbg_print_sse_state();
905 // commands invoked from parser
908 void bx_dbg_quit_command(void)
910 BX_INFO(("dbg: Quit"));
911 bx_dbg_exit(0);
914 void bx_dbg_trace_command(bx_bool enable)
916 BX_CPU(dbg_cpu)->trace = enable;
917 dbg_printf("Tracing %s for %s\n", enable ? "enabled" : "disabled",
918 BX_CPU(dbg_cpu)->name);
921 void bx_dbg_trace_reg_command(bx_bool enable)
923 BX_CPU(dbg_cpu)->trace_reg = enable;
924 dbg_printf("Register-Tracing %s for %s\n", enable ? "enabled" : "disabled",
925 BX_CPU(dbg_cpu)->name);
928 void bx_dbg_trace_mem_command(bx_bool enable)
930 BX_CPU(dbg_cpu)->trace_mem = enable;
931 dbg_printf("Memory-Tracing %s for %s\n", enable ? "enabled" : "disabled",
932 BX_CPU(dbg_cpu)->name);
935 void bx_dbg_ptime_command(void)
937 dbg_printf("ptime: " FMT_LL "d\n", bx_pc_system.time_ticks());
940 int timebp_timer = -1;
941 Bit64u timebp_queue[MAX_CONCURRENT_BPS];
942 int timebp_queue_size = 0;
944 void bx_dbg_timebp_command(bx_bool absolute, Bit64u time)
946 Bit64u abs_time = (absolute) ? time : time + bx_pc_system.time_ticks();
948 if (abs_time < bx_pc_system.time_ticks()) {
949 dbg_printf("Request for time break point in the past. I can't let you do that.\n");
950 return;
953 if (timebp_queue_size == MAX_CONCURRENT_BPS) {
954 dbg_printf("Too many time break points\n");
955 return;
958 Bit64u diff = (absolute) ? time - bx_pc_system.time_ticks() : time;
960 if (timebp_timer >= 0) {
961 if (timebp_queue_size == 0 || abs_time < timebp_queue[0]) {
962 /* first in queue */
963 for (int i = timebp_queue_size; i >= 0; i--)
964 timebp_queue[i+1] = timebp_queue[i];
965 timebp_queue[0] = abs_time;
966 timebp_queue_size++;
967 bx_pc_system.activate_timer_ticks(timebp_timer, diff, 1);
968 } else {
969 /* not first, insert at suitable place */
970 for (int i = 1; i < timebp_queue_size; i++) {
971 if (timebp_queue[i] == abs_time) {
972 dbg_printf("Time breakpoint not inserted (duplicate)\n");
973 return;
974 } else if (abs_time < timebp_queue[i]) {
975 for (int j = timebp_queue_size; j >= i; j--)
976 timebp_queue[j+1] = timebp_queue[j];
977 timebp_queue[i] = abs_time;
978 goto inserted;
981 /* last */
982 timebp_queue[timebp_queue_size] = abs_time;
983 inserted:
984 timebp_queue_size++;
986 } else {
987 timebp_queue_size = 1;
988 timebp_queue[0] = abs_time;
989 timebp_timer = bx_pc_system.register_timer_ticks(&bx_pc_system, bx_pc_system_c::timebp_handler, diff, 0, 1, "debug.timebp");
992 dbg_printf("Time breakpoint inserted. Delta = " FMT_LL "u\n", diff);
995 Bit32u conv_4xBit8u_to_Bit32u(const Bit8u* buf)
997 Bit32u ret = 0;
998 for (int i = 0; i < 4; i++) {
999 ret |= (buf[i] << (8 * i));
1001 return ret;
1004 void bx_dbg_record_command(char* path_quoted)
1006 // skip beginning double quote
1007 if (path_quoted[0] == '"')
1008 path_quoted++;
1010 // null out ending quote
1011 int len = strlen(path_quoted);
1012 if (path_quoted[len - 1] == '"')
1013 path_quoted[len - 1] = '\0';
1015 bx_dbg.record_io = fopen(path_quoted, "w");
1016 if (bx_dbg.record_io)
1017 dbg_printf("IO record file '%s' opened\n", path_quoted);
1018 else
1019 dbg_printf("Error opening '%s' for writing\n", path_quoted);
1022 static FILE* playback_file = 0;
1024 struct playback_entry_t
1026 char command[100];
1027 Bit32u argument;
1029 void trigger();
1032 static playback_entry_t playback_entry;
1033 static Bit64u last_playback_time = 0;
1034 static int playback_timer_index = -1;
1036 void playback_function(void* this_ptr)
1038 ((playback_entry_t*)this_ptr)->trigger();
1041 static void enter_playback_entry()
1043 static const int playback_buf_size = 100;
1044 char playback_buf[playback_buf_size];
1045 if (!fgets(playback_buf, playback_buf_size, playback_file))
1046 return;
1048 Bit64u time;
1049 if (sscanf(playback_buf, "%s " FMT_LL "d %x", playback_entry.command, &time, &playback_entry.argument) != 3) {
1050 dbg_printf("Parse error in playback string '%s'\n", playback_buf);
1051 return;
1054 Bit64u diff = time - last_playback_time;
1055 last_playback_time = time;
1057 if (time < last_playback_time) {
1058 BX_PANIC(("Negative diff in playback"));
1059 } else if (diff == 0) {
1060 playback_entry.trigger();
1061 } else {
1062 if (playback_timer_index >= 0)
1063 bx_pc_system.activate_timer_ticks(playback_timer_index, diff, 0);
1064 else
1065 playback_timer_index = bx_pc_system.register_timer_ticks(&playback_entry, playback_function, diff, 0, 1, "debug.playback");
1069 void playback_entry_t::trigger()
1071 if (!strcmp("gen_scancode", command)) {
1072 DEV_kbd_gen_scancode(argument);
1073 } else {
1074 dbg_printf("Unknown playback command '%s'\n", command);
1075 return;
1077 enter_playback_entry();
1080 void bx_dbg_playback_command(char* path_quoted)
1082 // skip beginning double quote
1083 if (path_quoted[0] == '"')
1084 path_quoted++;
1086 // null out ending quote
1087 int len = strlen(path_quoted);
1088 if (path_quoted[len - 1] == '"')
1089 path_quoted[len - 1] = '\0';
1091 playback_file = fopen(path_quoted, "r");
1092 if (playback_file) {
1093 dbg_printf("Playback from '%s'\n", path_quoted);
1094 last_playback_time = 0;
1095 dbg_printf("playback times relative from " FMT_LL "d\n",
1096 bx_pc_system.time_ticks());
1097 enter_playback_entry();
1098 } else {
1099 dbg_printf("Error opening '%s' for reading\n", path_quoted);
1103 // toggles mode switch breakpoint
1104 void bx_dbg_modebp_command()
1106 BX_CPU(dbg_cpu)->mode_break = !BX_CPU(dbg_cpu)->mode_break;
1107 dbg_printf("mode switch break %s\n",
1108 BX_CPU(dbg_cpu)->mode_break ? "enabled" : "disabled");
1111 static bx_bool bx_dbg_read_linear(unsigned which_cpu, bx_address laddr, unsigned len, Bit8u *buf)
1113 unsigned remainsInPage;
1114 bx_phy_address paddr;
1115 unsigned read_len;
1116 bx_bool paddr_valid;
1118 next_page:
1119 remainsInPage = 0x1000 - PAGE_OFFSET(laddr);
1120 read_len = (remainsInPage < len) ? remainsInPage : len;
1122 paddr_valid = BX_CPU(which_cpu)->dbg_xlate_linear2phy(laddr, &paddr);
1123 if (paddr_valid) {
1124 if (! BX_MEM(0)->dbg_fetch_mem(BX_CPU(which_cpu), paddr, read_len, buf)) {
1125 dbg_printf("bx_dbg_read_linear: physical memory read error (phy=0x" FMT_PHY_ADDRX ", lin=0x" FMT_ADDRX ")\n", paddr, laddr);
1126 return 0;
1129 else {
1130 dbg_printf("bx_dbg_read_linear: physical address not available for linear 0x" FMT_ADDRX "\n", laddr);
1131 return 0;
1134 /* check for access across multiple pages */
1135 if (remainsInPage < len)
1137 laddr += read_len;
1138 len -= read_len;
1139 buf += read_len;
1140 goto next_page;
1143 return 1;
1146 // where
1147 // stack trace: ebp -> old ebp
1148 // return eip at ebp + 4
1149 void bx_dbg_where_command()
1151 if (!BX_CPU(dbg_cpu)->protected_mode()) {
1152 dbg_printf("'where' only supported in protected mode\n");
1153 return;
1155 if (BX_CPU(dbg_cpu)->get_segment_base(BX_SEG_REG_SS) != 0) {
1156 dbg_printf("non-zero stack base\n");
1157 return;
1159 Bit32u bp = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_EBP);
1160 Bit32u ip = BX_CPU(dbg_cpu)->get_instruction_pointer();
1161 dbg_printf("(%d) 0x%08x\n", 0, ip);
1162 for (int i = 1; i < 50; i++) {
1163 // Up
1164 bx_phy_address paddr;
1165 Bit8u buf[4];
1167 // bp = [bp];
1168 bx_bool paddr_valid = BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(bp, &paddr);
1169 if (paddr_valid) {
1170 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), paddr, 4, buf)) {
1171 bp = conv_4xBit8u_to_Bit32u(buf);
1172 } else {
1173 dbg_printf("(%d) Physical memory read error (BP)\n", i);
1174 break;
1176 } else {
1177 dbg_printf("(%d) Could not translate linear address (BP)\n", i);
1178 break;
1181 // ip = [bp + 4];
1182 paddr_valid = BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(bp + 4, &paddr);
1183 if (paddr_valid) {
1184 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), paddr, 4, buf)) {
1185 ip = conv_4xBit8u_to_Bit32u(buf);
1186 } else {
1187 dbg_printf("(%d) Physical memory read error (IP)\n", i);
1188 break;
1190 } else {
1191 dbg_printf("(%d) Could not translate linear address (IP)\n", i);
1192 break;
1195 // Print
1196 dbg_printf("(%d) 0x%08x\n", i, ip);
1200 void bx_dbg_print_string_command(bx_address start_addr)
1202 dbg_printf("0x%08x: ", start_addr);
1203 for (int i = 0; ; i++) {
1204 Bit8u buf = 0;
1205 if (! bx_dbg_read_linear(dbg_cpu, start_addr+i, 1, &buf)) break;
1206 if (buf == 0) break;
1207 if (isgraph(buf) || buf == 0x20)
1208 dbg_printf("%c", buf);
1209 else
1210 dbg_printf("\\%d", buf);
1212 dbg_printf("\n");
1215 static void dbg_print_guard_found(unsigned cpu_mode, Bit32u cs, bx_address eip, bx_address laddr)
1217 #if BX_SUPPORT_X86_64
1218 if (cpu_mode == BX_MODE_LONG_64) {
1219 dbg_printf("0x%04x:" FMT_ADDRX " (0x" FMT_ADDRX ")", cs, eip, laddr);
1220 return;
1222 #endif
1224 if (cpu_mode >= BX_MODE_IA32_PROTECTED)
1225 dbg_printf("%04x:%08x (0x%08x)", cs, (unsigned) eip, (unsigned) laddr);
1226 else // real or v8086 mode
1227 dbg_printf("%04x:%04x (0x%08x)", cs, (unsigned) eip, (unsigned) laddr);
1230 void bx_dbg_xlate_address(bx_lin_address laddr)
1232 bx_phy_address paddr;
1233 laddr &= BX_CONST64(0xfffffffffffff000);
1235 bx_bool paddr_valid = BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(laddr, &paddr);
1236 if (paddr_valid) {
1237 dbg_printf("linear page 0x" FMT_ADDRX " maps to physical page 0x" FMT_PHY_ADDRX "\n", laddr, paddr);
1239 else {
1240 dbg_printf("physical address not available for linear 0x" FMT_ADDRX "\n", laddr);
1244 unsigned dbg_show_mask = 0;
1246 #define BX_DBG_SHOW_CALLRET (Flag_call|Flag_ret)
1247 #define BX_DBG_SHOW_SOFTINT (Flag_softint)
1248 #define BX_DBG_SHOW_EXTINT (Flag_intsig)
1249 #define BX_DBG_SHOW_IRET (Flag_iret)
1250 #define BX_DBG_SHOW_INT (Flag_softint|Flag_iret|Flag_intsig)
1251 #define BX_DBG_SHOW_MODE (Flag_mode)
1253 void bx_dbg_show_command(const char* arg)
1255 if(arg) {
1256 if (!strcmp(arg, "mode")) {
1257 if (dbg_show_mask & BX_DBG_SHOW_MODE) {
1258 dbg_show_mask &= ~BX_DBG_SHOW_MODE;
1259 dbg_printf("show mode switch: OFF\n");
1260 } else {
1261 dbg_show_mask |= BX_DBG_SHOW_MODE;
1262 dbg_printf("show mode switch: ON\n");
1264 } else if (!strcmp(arg, "int")) {
1265 if (dbg_show_mask & BX_DBG_SHOW_INT) {
1266 dbg_show_mask &= ~BX_DBG_SHOW_INT;
1267 dbg_printf("show interrupts tracing (extint/softint/iret): OFF\n");
1268 } else {
1269 dbg_show_mask |= BX_DBG_SHOW_INT;
1270 dbg_printf("show interrupts tracing (extint/softint/iret): ON\n");
1272 } else if (!strcmp(arg, "extint")) {
1273 if (dbg_show_mask & BX_DBG_SHOW_EXTINT) {
1274 dbg_show_mask &= ~BX_DBG_SHOW_EXTINT;
1275 dbg_printf("show external interrupts: OFF\n");
1276 } else {
1277 dbg_show_mask |= BX_DBG_SHOW_EXTINT;
1278 dbg_printf("show external interrupts: ON\n");
1280 } else if (!strcmp(arg, "softint")) {
1281 if (dbg_show_mask & BX_DBG_SHOW_SOFTINT) {
1282 dbg_show_mask &= ~BX_DBG_SHOW_SOFTINT;
1283 dbg_printf("show software interrupts: OFF\n");
1284 } else {
1285 dbg_show_mask |= BX_DBG_SHOW_SOFTINT;
1286 dbg_printf("show software interrupts: ON\n");
1288 } else if (!strcmp(arg, "iret")) {
1289 if (dbg_show_mask & BX_DBG_SHOW_IRET) {
1290 dbg_show_mask &= ~BX_DBG_SHOW_IRET;
1291 dbg_printf("show iret: OFF\n");
1292 } else {
1293 dbg_show_mask |= BX_DBG_SHOW_IRET;
1294 dbg_printf("show iret: ON\n");
1296 } else if(!strcmp(arg,"call")) {
1297 if (dbg_show_mask & BX_DBG_SHOW_CALLRET) {
1298 dbg_show_mask &= ~BX_DBG_SHOW_CALLRET;
1299 dbg_printf("show calls/returns: OFF\n");
1300 } else {
1301 dbg_show_mask |= BX_DBG_SHOW_CALLRET;
1302 dbg_printf("show calls/returns: ON\n");
1304 } else if(!strcmp(arg,"off")) {
1305 dbg_show_mask = 0x0;
1306 dbg_printf("Disable all show flags\n");
1307 } else if(!strcmp(arg,"dbg-all")) {
1308 bx_dbg.floppy = 1;
1309 bx_dbg.keyboard = 1;
1310 bx_dbg.video = 1;
1311 bx_dbg.disk = 1;
1312 bx_dbg.pit = 1;
1313 bx_dbg.pic = 1;
1314 bx_dbg.bios = 1;
1315 bx_dbg.cmos = 1;
1316 bx_dbg.a20 = 1;
1317 bx_dbg.interrupts = 1;
1318 bx_dbg.exceptions = 1;
1319 bx_dbg.mouse = 1;
1320 bx_dbg.io = 1;
1321 bx_dbg.debugger = 1;
1322 bx_dbg.dma = 1;
1323 bx_dbg.unsupported_io = 1;
1324 /* bx_dbg.record_io = 1; this is a pointer .. somewhere */
1325 dbg_printf("Turned ON all bx_dbg flags\n");
1326 return;
1327 } else if(!strcmp(arg,"dbg-none")) {
1328 bx_dbg.floppy = 0;
1329 bx_dbg.keyboard = 0;
1330 bx_dbg.video = 0;
1331 bx_dbg.disk = 0;
1332 bx_dbg.pit = 0;
1333 bx_dbg.pic = 0;
1334 bx_dbg.bios = 0;
1335 bx_dbg.cmos = 0;
1336 bx_dbg.a20 = 0;
1337 bx_dbg.interrupts = 0;
1338 bx_dbg.exceptions = 0;
1339 bx_dbg.mouse = 0;
1340 bx_dbg.io = 0;
1341 bx_dbg.debugger = 0;
1342 bx_dbg.dma = 0;
1343 bx_dbg.unsupported_io = 0;
1344 /* bx_dbg.record_io = 0; this is a pointer .. somewhere */
1345 dbg_printf("Turned OFF all bx_dbg flags\n");
1346 return;
1347 } else if(!strcmp(arg,"vga")){
1348 DEV_vga_refresh();
1349 return;
1350 } else {
1351 dbg_printf("Unrecognized arg: %s (only 'mode', 'int', 'softint', 'extint', 'iret', 'call', 'off', 'dbg-all' and 'dbg-none' are valid)\n", arg);
1352 return;
1356 if (dbg_show_mask) {
1357 dbg_printf("show mask is:");
1358 if (dbg_show_mask & BX_DBG_SHOW_CALLRET)
1359 dbg_printf(" call");
1360 if (dbg_show_mask & BX_DBG_SHOW_SOFTINT)
1361 dbg_printf(" softint");
1362 if (dbg_show_mask & BX_DBG_SHOW_EXTINT)
1363 dbg_printf(" extint");
1364 if (dbg_show_mask & BX_DBG_SHOW_IRET)
1365 dbg_printf(" iret");
1366 if (dbg_show_mask & BX_DBG_SHOW_MODE)
1367 dbg_printf(" mode");
1368 dbg_printf("\n");
1370 else {
1371 dbg_printf("show mask is: 0\n");
1375 void bx_dbg_show_param_command(char *param)
1377 dbg_printf("show param name: <%s>\n", param);
1378 bx_param_c *node = SIM->get_param(param, SIM->get_bochs_root());
1379 if (node) {
1380 print_tree(node, 0);
1382 else {
1383 node = SIM->get_param(param, dbg_cpu_list);
1384 if (node)
1385 print_tree(node, 0);
1386 else
1387 dbg_printf("can't find param <%s> in global or default CPU tree\n", param);
1391 // return non zero to cause a stop
1392 int bx_dbg_show_symbolic(void)
1394 static unsigned last_cpu_mode = 0;
1395 static bx_phy_address last_cr3 = 0;
1397 /* modes & address spaces */
1398 if (dbg_show_mask & BX_DBG_SHOW_MODE) {
1399 if(BX_CPU(dbg_cpu)->get_cpu_mode() != last_cpu_mode) {
1400 dbg_printf (FMT_TICK ": switched from '%s' to '%s'\n",
1401 bx_pc_system.time_ticks(),
1402 cpu_mode_string(last_cpu_mode),
1403 cpu_mode_string(BX_CPU(dbg_cpu)->get_cpu_mode()));
1406 if(last_cr3 != BX_CPU(dbg_cpu)->cr3)
1407 dbg_printf(FMT_TICK ": address space switched. CR3: 0x" FMT_PHY_ADDRX "\n",
1408 bx_pc_system.time_ticks(), BX_CPU(dbg_cpu)->cr3);
1411 /* interrupts */
1412 if (dbg_show_mask & BX_DBG_SHOW_SOFTINT) {
1413 if(BX_CPU(dbg_cpu)->show_flag & Flag_softint) {
1414 dbg_printf(FMT_TICK ": softint ", bx_pc_system.time_ticks());
1415 dbg_print_guard_found(BX_CPU(dbg_cpu)->get_cpu_mode(),
1416 BX_CPU(dbg_cpu)->guard_found.cs, BX_CPU(dbg_cpu)->guard_found.eip,
1417 BX_CPU(dbg_cpu)->guard_found.laddr);
1418 dbg_printf("\n");
1422 if (dbg_show_mask & BX_DBG_SHOW_EXTINT) {
1423 if((BX_CPU(dbg_cpu)->show_flag & Flag_intsig) && !(BX_CPU(dbg_cpu)->show_flag & Flag_softint)) {
1424 dbg_printf(FMT_TICK ": exception (not softint) ", bx_pc_system.time_ticks());
1425 dbg_print_guard_found(BX_CPU(dbg_cpu)->get_cpu_mode(),
1426 BX_CPU(dbg_cpu)->guard_found.cs, BX_CPU(dbg_cpu)->guard_found.eip,
1427 BX_CPU(dbg_cpu)->guard_found.laddr);
1428 dbg_printf("\n");
1432 if (dbg_show_mask & BX_DBG_SHOW_IRET) {
1433 if(BX_CPU(dbg_cpu)->show_flag & Flag_iret) {
1434 dbg_printf(FMT_TICK ": iret ", bx_pc_system.time_ticks());
1435 dbg_print_guard_found(BX_CPU(dbg_cpu)->get_cpu_mode(),
1436 BX_CPU(dbg_cpu)->guard_found.cs, BX_CPU(dbg_cpu)->guard_found.eip,
1437 BX_CPU(dbg_cpu)->guard_found.laddr);
1438 dbg_printf("\n");
1442 /* calls */
1443 if (dbg_show_mask & BX_DBG_SHOW_CALLRET)
1445 if(BX_CPU(dbg_cpu)->show_flag & Flag_call) {
1446 bx_phy_address phy = 0;
1447 bx_bool valid = BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(BX_CPU(dbg_cpu)->guard_found.laddr, &phy);
1448 dbg_printf(FMT_TICK ": call ", bx_pc_system.time_ticks());
1449 dbg_print_guard_found(BX_CPU(dbg_cpu)->get_cpu_mode(),
1450 BX_CPU(dbg_cpu)->guard_found.cs, BX_CPU(dbg_cpu)->guard_found.eip,
1451 BX_CPU(dbg_cpu)->guard_found.laddr);
1452 if (!valid) dbg_printf(" phys not valid");
1453 else {
1454 dbg_printf(" (phy: 0x" FMT_PHY_ADDRX ") %s", phy,
1455 bx_dbg_symbolic_address(BX_CPU(dbg_cpu)->cr3,
1456 BX_CPU(dbg_cpu)->guard_found.eip,
1457 BX_CPU(dbg_cpu)->guard_found.laddr - BX_CPU(dbg_cpu)->guard_found.eip));
1459 dbg_printf("\n");
1463 last_cr3 = BX_CPU(dbg_cpu)->cr3;
1464 last_cpu_mode = BX_CPU(dbg_cpu)->get_cpu_mode();
1465 BX_CPU(dbg_cpu)->show_flag = 0;
1467 return 0;
1470 void bx_dbg_print_stack_command(unsigned nwords)
1472 bx_address linear_sp;
1473 unsigned len;
1475 #if BX_SUPPORT_X86_64
1476 if (BX_CPU(dbg_cpu)->get_cpu_mode() == BX_MODE_LONG_64) {
1477 linear_sp = BX_CPU(dbg_cpu)->get_reg64(BX_64BIT_REG_RSP);
1478 len = 8;
1480 else
1481 #endif
1483 if (BX_CPU(dbg_cpu)->sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
1484 linear_sp = BX_CPU(dbg_cpu)->get_reg32(BX_32BIT_REG_ESP);
1486 if (BX_CPU(dbg_cpu)->protected_mode()) {
1487 linear_sp += BX_CPU(dbg_cpu)->sregs[BX_SEG_REG_SS].cache.u.segment.base;
1488 linear_sp &= 0xffffffff;
1491 len = 4;
1493 else {
1494 linear_sp = BX_CPU(dbg_cpu)->get_reg16(BX_16BIT_REG_SP);
1495 len = 2;
1499 Bit8u buf[8];
1501 dbg_printf("Stack address size %d\n", len);
1503 for (unsigned i = 0; i < nwords; i++) {
1504 if (! bx_dbg_read_linear(dbg_cpu, linear_sp, len, buf)) break;
1505 #if BX_SUPPORT_X86_64
1506 if (len == 8) {
1507 dbg_printf(" | STACK 0x%08x%08x [0x%08x:0x%08x]\n",
1508 GET32H(linear_sp), GET32L(linear_sp),
1509 (unsigned) conv_4xBit8u_to_Bit32u(buf+4),
1510 (unsigned) conv_4xBit8u_to_Bit32u(buf));
1512 else
1513 #endif
1515 if (len == 4) {
1516 dbg_printf(" | STACK 0x%08x [0x%08x]\n",
1517 (unsigned) linear_sp, (unsigned) conv_4xBit8u_to_Bit32u(buf));
1519 else {
1520 dbg_printf(" | STACK 0x%04x [0x%04x]\n",
1521 (unsigned) linear_sp, (unsigned) conv_4xBit8u_to_Bit32u(buf));
1525 linear_sp += len;
1529 void bx_dbg_watch(int type, bx_phy_address address)
1531 if (type == -1) {
1532 // print watch point info
1533 for (unsigned i = 0; i < num_read_watchpoints; i++) {
1534 Bit8u buf[2];
1535 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), read_watchpoint[i], 2, buf))
1536 dbg_printf("rd 0x"FMT_PHY_ADDRX" (%04x)\n",
1537 read_watchpoint[i], (int)buf[0] | ((int)buf[1] << 8));
1538 else
1539 dbg_printf("rd 0x"FMT_PHY_ADDRX" (read error)\n", read_watchpoint[i]);
1541 for (unsigned i = 0; i < num_write_watchpoints; i++) {
1542 Bit8u buf[2];
1543 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), write_watchpoint[i], 2, buf))
1544 dbg_printf("wr 0x"FMT_PHY_ADDRX" (%04x)\n",
1545 write_watchpoint[i], (int)buf[0] | ((int)buf[1] << 8));
1546 else
1547 dbg_printf("wr 0x"FMT_PHY_ADDRX" (read error)\n", write_watchpoint[i]);
1549 } else {
1550 if (type == BX_READ) {
1551 if (num_read_watchpoints == BX_DBG_MAX_WATCHPONTS) {
1552 dbg_printf("Too many read watchpoints (%d)\n", BX_DBG_MAX_WATCHPONTS);
1553 return;
1555 read_watchpoint[num_read_watchpoints++] = address;
1556 dbg_printf("read watchpoint at 0x" FMT_PHY_ADDRX " inserted\n", address);
1558 else {
1559 if (num_write_watchpoints == BX_DBG_MAX_WATCHPONTS) {
1560 dbg_printf("Too many write watchpoints (%d)\n", BX_DBG_MAX_WATCHPONTS);
1561 return;
1563 write_watchpoint[num_write_watchpoints++] = address;
1564 dbg_printf("write watchpoint at 0x" FMT_PHY_ADDRX " inserted\n", address);
1569 void bx_dbg_unwatch(bx_phy_address address)
1571 if (address == (bx_phy_address) -1) {
1572 // unwatch all
1573 num_read_watchpoints = num_write_watchpoints = 0;
1574 dbg_printf("All watchpoints removed\n");
1575 return;
1578 for (unsigned i=0; i<num_read_watchpoints; i++) {
1579 if (read_watchpoint[i] == address) {
1580 dbg_printf("read watchpoint at 0x" FMT_PHY_ADDRX " removed\n", address);
1581 // found watchpoint, delete it by shifting remaining entries left
1582 for (unsigned j=i; j<(num_read_watchpoints-1); j++) {
1583 read_watchpoint[j] = read_watchpoint[j+1];
1585 num_read_watchpoints--;
1586 break;
1590 for (unsigned i=0; i<num_write_watchpoints; i++) {
1591 if (write_watchpoint[i] == address) {
1592 dbg_printf("write watchpoint at 0x" FMT_PHY_ADDRX " removed\n", address);
1593 // found watchpoint, delete it by shifting remaining entries left
1594 for (unsigned j=i; j<(num_write_watchpoints-1); j++) {
1595 write_watchpoint[j] = write_watchpoint[j+1];
1597 num_write_watchpoints--;
1598 break;
1603 void bx_dbg_continue_command(void)
1605 int cpu;
1607 // continue executing, until a guard found
1609 one_more:
1611 // I must guard for ICOUNT or one CPU could run forever without giving
1612 // the others a chance.
1613 for (cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
1614 BX_CPU(cpu)->guard_found.guard_found = 0;
1615 BX_CPU(cpu)->guard_found.icount = 0;
1616 BX_CPU(cpu)->guard_found.time_tick = bx_pc_system.time_ticks();
1619 // update gui (disable continue command, enable stop command, etc.)
1620 sim_running->set(1);
1621 SIM->refresh_ci();
1623 // use simulation mode while executing instructions. When the prompt
1624 // is printed, we will return to config mode.
1625 SIM->set_display_mode(DISP_MODE_SIM);
1627 bx_guard.interrupt_requested = 0;
1628 int stop = 0;
1629 int which = -1;
1630 while (!stop && !bx_guard.interrupt_requested) {
1631 // the quantum is an arbitrary number of cycles to run in each
1632 // processor. In SMP mode, when this limit is reached, the
1633 // cpu_loop exits so that another processor can be simulated
1634 // for a few cycles. With a single processor, the quantum
1635 // setting should have no effect, although a low setting does
1636 // lead to poor performance because cpu_loop is returning and
1637 // getting called again, over and over.
1639 #define BX_DBG_DEFAULT_ICOUNT_QUANTUM 5
1641 Bit32u quantum = (BX_SMP_PROCESSORS>1) ? BX_DBG_DEFAULT_ICOUNT_QUANTUM : 0;
1642 Bit32u max_executed = 0;
1643 for (cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
1644 Bit64u cpu_icount = BX_CPU(cpu)->guard_found.icount;
1645 BX_CPU(cpu)->cpu_loop(quantum);
1646 Bit32u executed = BX_CPU(cpu)->guard_found.icount - cpu_icount;
1647 if (executed > max_executed) max_executed = executed;
1648 // set stop flag if a guard found other than icount or halted
1649 unsigned long found = BX_CPU(cpu)->guard_found.guard_found;
1650 stop_reason_t reason = (stop_reason_t) BX_CPU(cpu)->stop_reason;
1651 if (found || (reason != STOP_NO_REASON && reason != STOP_CPU_HALTED)) {
1652 stop = 1;
1653 which = cpu;
1655 // even if stop==1, finish cycling through all processors.
1656 // "which" remembers which cpu set the stop flag. If multiple
1657 // cpus set stop, too bad.
1660 #if BX_SUPPORT_SMP
1661 // increment time tick only after all processors have had their chance.
1662 if (BX_SMP_PROCESSORS > 1) {
1663 // potential deadlock if all processors are halted. Then
1664 // max_executed will be 0, tick will be incremented by zero, and
1665 // there will never be a timed event to wake them up. To avoid this,
1666 // always tick by a minimum of 1.
1667 if (max_executed < 1) max_executed=1;
1669 BX_TICKN(max_executed);
1671 #endif
1674 sim_running->set(0);
1675 SIM->refresh_ci();
1677 // (mch) hack
1678 DEV_vga_refresh();
1680 BX_INSTR_DEBUG_PROMPT();
1681 bx_dbg_print_guard_results();
1683 if (watchpoint_continue && (BX_CPU(which)->stop_reason == STOP_READ_WATCH_POINT ||
1684 BX_CPU(which)->stop_reason == STOP_WRITE_WATCH_POINT))
1685 goto one_more;
1688 void bx_dbg_stepN_command(Bit32u count)
1690 if (count == 0) {
1691 dbg_printf("Error: stepN: count=0\n");
1692 return;
1695 // use simulation mode while executing instructions. When the prompt
1696 // is printed, we will return to config mode.
1697 SIM->set_display_mode(DISP_MODE_SIM);
1699 // reset guard counters for all CPUs
1700 int stop = 0;
1701 for (unsigned cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
1702 BX_CPU(cpu)->guard_found.icount = 0;
1703 BX_CPU(cpu)->guard_found.time_tick = bx_pc_system.time_ticks();
1706 // for now, step each CPU one instruction at a time
1707 for (unsigned cycle=0; !stop && cycle < count; cycle++) {
1708 for (unsigned cpu=0; cpu < BX_SMP_PROCESSORS; cpu++) {
1709 bx_guard.interrupt_requested = 0;
1710 BX_CPU(cpu)->guard_found.guard_found = 0;
1711 BX_CPU(cpu)->cpu_loop(1);
1712 // set stop flag if a guard found other than icount or halted
1713 unsigned long found = BX_CPU(cpu)->guard_found.guard_found;
1714 stop_reason_t reason = (stop_reason_t) BX_CPU(cpu)->stop_reason;
1715 if (found || (reason != STOP_NO_REASON && reason != STOP_CPU_HALTED))
1716 stop = 1;
1719 #if BX_SUPPORT_SMP
1720 // when (BX_SMP_PROCESSORS == 1) ticks are handled inside the cpu loop
1721 if (BX_SMP_PROCESSORS > 1) BX_TICK1();
1722 #endif
1725 BX_INSTR_DEBUG_PROMPT();
1726 bx_dbg_print_guard_results();
1729 void bx_dbg_disassemble_current(int which_cpu, int print_time)
1731 bx_phy_address phy;
1733 if (which_cpu < 0) {
1734 // iterate over all of them.
1735 for (int i=0; i<BX_SMP_PROCESSORS; i++)
1736 bx_dbg_disassemble_current(i, print_time);
1737 return;
1740 bx_bool phy_valid = BX_CPU(which_cpu)->dbg_xlate_linear2phy(BX_CPU(which_cpu)->guard_found.laddr, &phy);
1741 if (! phy_valid) {
1742 dbg_printf("(%u).[" FMT_LL "d] ??? (physical address not available)\n", which_cpu, bx_pc_system.time_ticks());
1743 return;
1746 if (bx_dbg_read_linear(which_cpu, BX_CPU(which_cpu)->guard_found.laddr, 16, bx_disasm_ibuf))
1748 unsigned ilen = bx_disassemble.disasm(BX_CPU(which_cpu)->guard_found.is_32bit_code,
1749 BX_CPU(which_cpu)->guard_found.is_64bit_code,
1750 BX_CPU(which_cpu)->get_segment_base(BX_SEG_REG_CS),
1751 BX_CPU(which_cpu)->guard_found.eip, bx_disasm_ibuf, bx_disasm_tbuf);
1753 // Note: it would be nice to display only the modified registers here, the easy
1754 // way out I have thought of would be to keep a prev_eax, prev_ebx, etc copies
1755 // in each cpu description (see cpu/cpu.h) and update/compare those "prev" values
1756 // from here. (eks)
1757 if(BX_CPU(dbg_cpu)->trace_reg)
1758 bx_dbg_info_registers_command(BX_INFO_GENERAL_PURPOSE_REGS);
1760 if (print_time)
1761 dbg_printf("(%u).[" FMT_LL "d] ", which_cpu, bx_pc_system.time_ticks());
1762 else
1763 dbg_printf("(%u) ", which_cpu);
1765 if (BX_CPU(which_cpu)->protected_mode()) {
1766 dbg_printf("[0x"FMT_PHY_ADDRX"] %04x:" FMT_ADDRX " (%s): ",
1767 phy, BX_CPU(which_cpu)->guard_found.cs,
1768 BX_CPU(which_cpu)->guard_found.eip,
1769 bx_dbg_symbolic_address((BX_CPU(which_cpu)->cr3) >> 12,
1770 BX_CPU(which_cpu)->guard_found.eip,
1771 BX_CPU(which_cpu)->get_segment_base(BX_SEG_REG_CS)));
1773 else { // Real & V86 mode
1774 dbg_printf("[0x"FMT_PHY_ADDRX"] %04x:%04x (%s): ",
1775 phy, BX_CPU(which_cpu)->guard_found.cs,
1776 (unsigned) BX_CPU(which_cpu)->guard_found.eip,
1777 bx_dbg_symbolic_address_16bit(BX_CPU(which_cpu)->guard_found.eip,
1778 BX_CPU(which_cpu)->sregs[BX_SEG_REG_CS].selector.value));
1780 dbg_printf("%-25s ; ", bx_disasm_tbuf);
1781 for (unsigned j=0; j<ilen; j++) {
1782 dbg_printf("%02x", (unsigned) bx_disasm_ibuf[j]);
1784 dbg_printf("\n");
1788 void bx_dbg_print_guard_results(void)
1790 unsigned cpu, i;
1792 for (cpu=0; cpu<BX_SMP_PROCESSORS; cpu++) {
1793 unsigned long found = BX_CPU(cpu)->guard_found.guard_found;
1794 if (! found) { /* ... */ }
1795 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1796 else if (found & BX_DBG_GUARD_IADDR_VIR) {
1797 i = BX_CPU(cpu)->guard_found.iaddr_index;
1798 dbg_printf("(%u) Breakpoint %u, in ");
1799 dbg_print_guard_found(BX_CPU(dbg_cpu)->get_cpu_mode(),
1800 BX_CPU(cpu)->guard_found.cs, BX_CPU(cpu)->guard_found.eip,
1801 BX_CPU(cpu)->guard_found.laddr);
1802 dbg_printf("\n");
1804 #endif
1805 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1806 else if (found & BX_DBG_GUARD_IADDR_LIN) {
1807 i = BX_CPU(cpu)->guard_found.iaddr_index;
1808 if (bx_guard.iaddr.lin[i].bpoint_id != 0)
1809 dbg_printf("(%u) Breakpoint %u, 0x" FMT_ADDRX " in ?? ()\n",
1810 cpu,
1811 bx_guard.iaddr.lin[i].bpoint_id,
1812 BX_CPU(cpu)->guard_found.laddr);
1814 #endif
1815 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1816 else if (found & BX_DBG_GUARD_IADDR_PHY) {
1817 i = BX_CPU(cpu)->guard_found.iaddr_index;
1818 dbg_printf("(%u) Breakpoint %u, 0x" FMT_ADDRX " in ?? ()\n",
1819 cpu,
1820 bx_guard.iaddr.phy[i].bpoint_id,
1821 BX_CPU(cpu)->guard_found.laddr);
1823 #endif
1824 switch(BX_CPU(cpu)->stop_reason) {
1825 case STOP_NO_REASON:
1826 case STOP_CPU_HALTED:
1827 break;
1828 case STOP_TIME_BREAK_POINT:
1829 dbg_printf("(%u) Caught time breakpoint\n", cpu);
1830 break;
1831 case STOP_READ_WATCH_POINT:
1832 dbg_printf("(%u) Caught read watch point at 0x" FMT_PHY_ADDRX "\n", cpu, BX_CPU(cpu)->watchpoint);
1833 break;
1834 case STOP_WRITE_WATCH_POINT:
1835 dbg_printf("(%u) Caught write watch point at 0x" FMT_PHY_ADDRX "\n", cpu, BX_CPU(cpu)->watchpoint);
1836 break;
1837 case STOP_MAGIC_BREAK_POINT:
1838 dbg_printf("(%u) Magic breakpoint\n", cpu);
1839 break;
1840 case STOP_MODE_BREAK_POINT:
1841 dbg_printf("(%u) Caught mode switch breakpoint switching to '%s'\n",
1842 cpu, cpu_mode_string(BX_CPU(cpu)->get_cpu_mode()));
1843 break;
1844 default:
1845 dbg_printf("Error: (%u) print_guard_results: guard_found ? (stop reason %u)\n",
1846 cpu, BX_CPU(cpu)->stop_reason);
1849 if (bx_debugger.auto_disassemble) {
1850 if (cpu==0) {
1851 // print this only once
1852 dbg_printf("Next at t=" FMT_LL "d\n", bx_pc_system.time_ticks());
1854 bx_dbg_disassemble_current(cpu, 0); // one cpu, don't print time
1857 #if 0
1858 // print the TSC value for every CPU
1859 for (cpu=0; cpu<BX_SMP_PROCESSORS; cpu++) {
1860 dbg_printf("TSC[%d] = " FMT_LL "d\n", cpu, BX_CPU(cpu)->tsc);
1862 #endif
1865 void bx_dbg_breakpoint_changed(void)
1867 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1868 if (bx_guard.iaddr.num_virtual)
1869 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_VIR;
1870 else
1871 bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_VIR;
1872 #endif
1874 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1875 if (bx_guard.iaddr.num_linear)
1876 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_LIN;
1877 else
1878 bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_LIN;
1879 #endif
1881 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1882 if (bx_guard.iaddr.num_physical)
1883 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_PHY;
1884 else
1885 bx_guard.guard_for &= ~BX_DBG_GUARD_IADDR_PHY;
1886 #endif
1889 void bx_dbg_en_dis_breakpoint_command(unsigned handle, bx_bool enable)
1891 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1892 if (bx_dbg_en_dis_vbreak(handle, enable))
1893 goto done;
1894 #endif
1896 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1897 if (bx_dbg_en_dis_lbreak(handle, enable))
1898 goto done;
1899 #endif
1901 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1902 if (bx_dbg_en_dis_pbreak(handle, enable))
1903 goto done;
1904 #endif
1906 dbg_printf("Error: breakpoint %u not found.\n", handle);
1907 return;
1909 done:
1910 bx_dbg_breakpoint_changed();
1913 bx_bool bx_dbg_en_dis_pbreak(unsigned handle, bx_bool enable)
1915 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1916 // see if breakpoint is a physical breakpoint
1917 for (unsigned i=0; i<bx_guard.iaddr.num_physical; i++) {
1918 if (bx_guard.iaddr.phy[i].bpoint_id == handle) {
1919 bx_guard.iaddr.phy[i].enabled=enable;
1920 return 1;
1923 #endif
1924 return 0;
1927 bx_bool bx_dbg_en_dis_lbreak(unsigned handle, bx_bool enable)
1929 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1930 // see if breakpoint is a linear breakpoint
1931 for (unsigned i=0; i<bx_guard.iaddr.num_linear; i++) {
1932 if (bx_guard.iaddr.lin[i].bpoint_id == handle) {
1933 bx_guard.iaddr.lin[i].enabled=enable;
1934 return 1;
1937 #endif
1938 return 0;
1941 bx_bool bx_dbg_en_dis_vbreak(unsigned handle, bx_bool enable)
1943 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1944 // see if breakpoint is a virtual breakpoint
1945 for (unsigned i=0; i<bx_guard.iaddr.num_virtual; i++) {
1946 if (bx_guard.iaddr.vir[i].bpoint_id == handle) {
1947 bx_guard.iaddr.vir[i].enabled=enable;
1948 return 1;
1951 #endif
1952 return 0;
1955 void bx_dbg_del_breakpoint_command(unsigned handle)
1957 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1958 if (bx_dbg_del_vbreak(handle))
1959 goto done;
1960 #endif
1962 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1963 if (bx_dbg_del_lbreak(handle))
1964 goto done;
1965 #endif
1967 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1968 if (bx_dbg_del_pbreak(handle))
1969 goto done;
1970 #endif
1972 dbg_printf("Error: breakpoint %u not found.\n", handle);
1973 return;
1975 done:
1976 bx_dbg_breakpoint_changed();
1979 bx_bool bx_dbg_del_pbreak(unsigned handle)
1981 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1982 // see if breakpoint is a physical breakpoint
1983 for (unsigned i=0; i<bx_guard.iaddr.num_physical; i++) {
1984 if (bx_guard.iaddr.phy[i].bpoint_id == handle) {
1985 // found breakpoint, delete it by shifting remaining entries left
1986 for (unsigned j=i; j<(bx_guard.iaddr.num_physical-1); j++) {
1987 bx_guard.iaddr.phy[j] = bx_guard.iaddr.phy[j+1];
1989 bx_guard.iaddr.num_physical--;
1990 return 1;
1993 #endif
1994 return 0;
1997 bx_bool bx_dbg_del_lbreak(unsigned handle)
1999 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
2000 // see if breakpoint is a linear breakpoint
2001 for (unsigned i=0; i<bx_guard.iaddr.num_linear; i++) {
2002 if (bx_guard.iaddr.lin[i].bpoint_id == handle) {
2003 // found breakpoint, delete it by shifting remaining entries left
2004 for (unsigned j=i; j<(bx_guard.iaddr.num_linear-1); j++) {
2005 bx_guard.iaddr.lin[j] = bx_guard.iaddr.lin[j+1];
2007 bx_guard.iaddr.num_linear--;
2008 return 1;
2011 #endif
2012 return 0;
2015 bx_bool bx_dbg_del_vbreak(unsigned handle)
2017 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
2018 // see if breakpoint is a virtual breakpoint
2019 for (unsigned i=0; i<bx_guard.iaddr.num_virtual; i++) {
2020 if (bx_guard.iaddr.vir[i].bpoint_id == handle) {
2021 // found breakpoint, delete it by shifting remaining entries left
2022 for (unsigned j=i; j<(bx_guard.iaddr.num_virtual-1); j++) {
2023 bx_guard.iaddr.vir[j] = bx_guard.iaddr.vir[j+1];
2025 bx_guard.iaddr.num_virtual--;
2026 return 1;
2029 #endif
2030 return 0;
2033 int bx_dbg_vbreakpoint_command(BreakpointKind bk, Bit32u cs, bx_address eip)
2035 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
2036 if (bk != bkRegular) {
2037 dbg_printf("Error: vbreak of this kind not implemented yet.\n");
2038 return -1;
2041 if (bx_guard.iaddr.num_virtual >= BX_DBG_MAX_VIR_BPOINTS) {
2042 dbg_printf("Error: no more virtual breakpoint slots left.\n");
2043 dbg_printf("Error: see BX_DBG_MAX_VIR_BPOINTS.\n");
2044 return -1;
2047 bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].cs = cs;
2048 bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].eip = eip;
2049 bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].bpoint_id = bx_debugger.next_bpoint_id++;
2050 int BpId = (int)bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].bpoint_id;
2051 bx_guard.iaddr.vir[bx_guard.iaddr.num_virtual].enabled=1;
2052 bx_guard.iaddr.num_virtual++;
2053 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_VIR;
2054 return BpId;
2056 #else
2057 dbg_printf("Error: virtual breakpoint support not compiled in.\n");
2058 dbg_printf("Error: make sure BX_DBG_MAX_VIR_BPOINTS > 0\n");
2059 return -1;
2060 #endif
2063 int bx_dbg_lbreakpoint_command(BreakpointKind bk, bx_address laddress)
2065 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
2066 if (bk == bkAtIP) {
2067 dbg_printf("Error: lbreak of this kind not implemented yet.\n");
2068 return -1;
2071 if (bx_guard.iaddr.num_linear >= BX_DBG_MAX_LIN_BPOINTS) {
2072 dbg_printf("Error: no more linear breakpoint slots left.\n");
2073 dbg_printf("Error: see BX_DBG_MAX_LIN_BPOINTS.\n");
2074 return -1;
2077 bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].addr = laddress;
2078 int BpId = (bk == bkStepOver) ? 0 : bx_debugger.next_bpoint_id++;
2079 bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].bpoint_id = BpId;
2080 bx_guard.iaddr.lin[bx_guard.iaddr.num_linear].enabled=1;
2081 bx_guard.iaddr.num_linear++;
2082 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_LIN;
2083 return BpId;
2085 #else
2086 dbg_printf("Error: linear breakpoint support not compiled in.\n");
2087 dbg_printf("Error: make sure BX_DBG_MAX_LIN_BPOINTS > 0\n");
2088 return -1;
2089 #endif
2092 int bx_dbg_pbreakpoint_command(BreakpointKind bk, bx_phy_address paddress)
2094 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
2095 if (bk != bkRegular) {
2096 dbg_printf("Error: pbreak of this kind not implemented yet.\n");
2097 return -1;
2100 if (bx_guard.iaddr.num_physical >= BX_DBG_MAX_PHY_BPOINTS) {
2101 dbg_printf("Error: no more physical breakpoint slots left.\n");
2102 dbg_printf("Error: see BX_DBG_MAX_PHY_BPOINTS.\n");
2103 return -1;
2106 bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].addr = paddress;
2107 bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].bpoint_id = bx_debugger.next_bpoint_id++;
2108 int BpId = (int)bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].bpoint_id;
2109 bx_guard.iaddr.phy[bx_guard.iaddr.num_physical].enabled=1;
2110 bx_guard.iaddr.num_physical++;
2111 bx_guard.guard_for |= BX_DBG_GUARD_IADDR_PHY;
2112 return BpId;
2113 #else
2114 dbg_printf("Error: physical breakpoint support not compiled in.\n");
2115 dbg_printf("Error: make sure BX_DBG_MAX_PHY_BPOINTS > 0\n");
2116 return -1;
2117 #endif
2120 void bx_dbg_info_bpoints_command(void)
2122 unsigned i;
2123 // Num Type Disp Enb Address What
2124 // 1 breakpoint keep y 0x00010664 in main at temp.c:7
2126 dbg_printf("Num Type Disp Enb Address\n");
2127 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
2128 for (i=0; i<bx_guard.iaddr.num_virtual; i++) {
2129 dbg_printf("%3u ", bx_guard.iaddr.vir[i].bpoint_id);
2130 dbg_printf("vbreakpoint ");
2131 dbg_printf("keep ");
2132 dbg_printf(bx_guard.iaddr.vir[i].enabled?"y ":"n ");
2133 dbg_printf("0x%04x:" FMT_ADDRX "\n",
2134 bx_guard.iaddr.vir[i].cs,
2135 bx_guard.iaddr.vir[i].eip);
2137 #endif
2139 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
2140 for (i=0; i<bx_guard.iaddr.num_linear; i++) {
2141 dbg_printf("%3u ", bx_guard.iaddr.lin[i].bpoint_id);
2142 dbg_printf("lbreakpoint ");
2143 dbg_printf("keep ");
2144 dbg_printf(bx_guard.iaddr.lin[i].enabled?"y ":"n ");
2145 dbg_printf("0x" FMT_ADDRX "\n", bx_guard.iaddr.lin[i].addr);
2147 #endif
2149 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
2150 for (i=0; i<bx_guard.iaddr.num_physical; i++) {
2151 dbg_printf("%3u ", bx_guard.iaddr.phy[i].bpoint_id);
2152 dbg_printf("pbreakpoint ");
2153 dbg_printf("keep ");
2154 dbg_printf(bx_guard.iaddr.phy[i].enabled?"y ":"n ");
2155 dbg_printf("0x"FMT_PHY_ADDRX"\n", bx_guard.iaddr.phy[i].addr);
2157 #endif
2160 void bx_dbg_set_auto_disassemble(bx_bool enable)
2162 bx_debugger.auto_disassemble = enable;
2165 void bx_dbg_set_disassemble_size(unsigned size)
2167 if ((size!=16) && (size!=32) && (size!=64) && (size!=0))
2169 dbg_printf("Error: disassemble size must be 16/32 or 64.\n");
2170 return;
2172 bx_debugger.disassemble_size = size;
2175 void bx_dbg_disassemble_switch_mode()
2177 bx_disassemble.toggle_syntax_mode();
2180 void bx_dbg_take_command(const char *what, unsigned n)
2182 if (! strcmp(what, "dma")) {
2183 if (n == 0) {
2184 dbg_printf("Error: take what n=0.\n");
2185 return;
2187 bx_dbg_post_dma_reports(); // in case there's some pending reports
2188 bx_dbg_batch_dma.this_many = n;
2190 for (unsigned i=0; i<n; i++) {
2191 BX_CPU(0)->dbg_take_dma();
2194 bx_dbg_batch_dma.this_many = 1; // reset to normal
2195 bx_dbg_post_dma_reports(); // print reports and flush
2196 if (bx_guard.report.dma)
2197 dbg_printf("done\n");
2199 else if (! strcmp(what, "irq")) {
2200 BX_CPU(0)->dbg_take_irq();
2202 if (bx_guard.report.irq)
2203 dbg_printf("done\n");
2205 else {
2206 dbg_printf("Error: Take '%s' not understood.\n", what);
2210 static void bx_print_char(Bit8u ch)
2212 if (ch < 10)
2213 dbg_printf(" \\%d ", ch);
2214 else if (isprint(ch))
2215 dbg_printf(" %c ", ch);
2216 else
2217 dbg_printf(" \\x%02X", ch);
2220 void dbg_printf_binary(char *format, Bit32u data, int bits)
2222 int b,len = 0;
2223 char num[33];
2225 for (b = 1 << (bits - 1); b; b >>= 1)
2226 num [len++] = (data & b) ? '1' : '0';
2227 num [len] = 0;
2228 dbg_printf (format, num);
2231 void bx_dbg_examine_command(char *command, char *format, bx_bool format_passed,
2232 bx_address addr, bx_bool addr_passed)
2234 unsigned repeat_count, i;
2235 char ch, display_format, unit_size;
2236 bx_bool iteration, memory_dump = false;
2237 unsigned data_size;
2238 Bit8u data8;
2239 Bit16u data16;
2240 Bit32u data32;
2241 unsigned columns, per_line, offset;
2242 bx_bool is_linear;
2243 unsigned char databuf[8];
2245 dbg_printf("[bochs]:\n");
2247 // If command was the extended "xp" command, meaning eXamine Physical memory,
2248 // then flag memory address as physical, rather than linear.
2249 if (strcmp(command, "xp") == 0) {
2250 is_linear = 0;
2252 else {
2253 is_linear = 1;
2256 if (addr_passed==0)
2257 addr = bx_debugger.default_addr;
2259 if (format_passed==0) {
2260 display_format = bx_debugger.default_display_format;
2261 unit_size = bx_debugger.default_unit_size;
2262 repeat_count = 1;
2264 else {
2265 if (format==NULL) {
2266 dbg_printf("dbg_examine: format NULL\n");
2267 bx_dbg_exit(1);
2270 if (strlen(format) < 2) {
2271 dbg_printf("dbg_examine: invalid format passed.\n");
2272 bx_dbg_exit(1);
2275 if (format[0] != '/') {
2276 dbg_printf("dbg_examine: '/' is not first char of format.\n");
2277 bx_dbg_exit(1);
2280 format++;
2281 repeat_count = 0;
2282 ch = *format;
2283 iteration = 0;
2285 while ((ch>='0') && (ch<='9')) {
2286 iteration = 1;
2287 repeat_count = 10*repeat_count + (ch-'0');
2288 format++;
2289 ch = *format;
2292 if (iteration==0) {
2293 // if no count given, use default
2294 repeat_count = 1;
2296 else if (repeat_count==0) {
2297 // count give, but zero is an error
2298 dbg_printf("dbg_examine: repeat count given but is zero.\n");
2299 return;
2302 // set up the default display format and unit size parameters
2303 display_format = bx_debugger.default_display_format;
2304 unit_size = bx_debugger.default_unit_size;
2306 for (i = 0; format [i]; i++) {
2307 switch (ch = format [i]) {
2308 case 'x': // hex
2309 case 'd': // signed decimal
2310 case 'u': // unsigned decimal
2311 case 'o': // octal
2312 case 't': // binary
2313 case 'c': // chars
2314 case 's': // null terminated string
2315 case 'i': // machine instruction
2316 display_format = ch;
2317 break;
2319 case 'b': // bytes
2320 case 'h': // halfwords (two bytes)
2321 case 'w': // words (4 bytes)
2322 case 'g': // giant words (8 bytes)
2323 unit_size = ch;
2324 break;
2326 case 'm': // memory dump
2327 memory_dump = true;
2328 break;
2330 default:
2331 dbg_printf("dbg_examine: invalid format passed. \'%c\'\n", ch);
2332 bx_dbg_exit(1);
2333 break;
2338 if ((display_format == 'i') || (display_format == 's')) {
2339 dbg_printf("error: dbg_examine: 'i' and 's' formats not supported.\n");
2340 return;
2343 if (unit_size == 'g') {
2344 dbg_printf("error: dbg_examine: 'g' (8-byte) unit size not supported.\n");
2345 return;
2348 if (format_passed) {
2349 // store current options as default
2350 bx_debugger.default_display_format = display_format;
2351 bx_debugger.default_unit_size = unit_size;
2354 data_size = 0;
2355 per_line = 0;
2356 offset = 0;
2358 if (memory_dump) {
2359 if (display_format == 'c') {
2360 // Display character dump in lines of 64 characters
2361 unit_size = 'b';
2362 data_size = 1;
2363 per_line = 64;
2365 else
2366 switch (unit_size) {
2367 case 'b': data_size = 1; per_line = 16; break;
2368 case 'h': data_size = 2; per_line = 8; break;
2369 case 'w': data_size = 4; per_line = 4; break;
2370 //case 'g': data_size = 8; per_line = 2; break;
2372 // binary format is quite large
2373 if (display_format == 't')
2374 per_line /= 4;
2376 else {
2377 switch (unit_size) {
2378 case 'b': data_size = 1; per_line = 8; break;
2379 case 'h': data_size = 2; per_line = 8; break;
2380 case 'w': data_size = 4; per_line = 4; break;
2381 //case 'g': data_size = 8; per_line = 2; break;
2385 columns = per_line + 1; // set current number columns past limit
2387 for (i=1; i<=repeat_count; i++) {
2388 if (columns > per_line) {
2389 // if not 1st run, need a newline from last line
2390 if (i!=1)
2391 dbg_printf("\n");
2392 if (memory_dump)
2393 dbg_printf("0x" FMT_ADDRX ":", addr);
2394 else
2395 dbg_printf("0x" FMT_ADDRX " <bogus+%8u>:", addr, offset);
2396 columns = 1;
2399 /* Put a space in the middle of dump, for readability */
2400 if ((columns - 1) == per_line / 2
2401 && memory_dump && display_format != 'c')
2402 dbg_printf(" ");
2404 if (is_linear) {
2405 if (! bx_dbg_read_linear(dbg_cpu, addr, data_size, databuf)) return;
2407 else {
2408 // address is already physical address
2409 BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), addr, data_size, databuf);
2412 //FIXME HanishKVC The char display for data to be properly integrated
2413 // so that repeat_count, columns, etc. can be set or used properly.
2414 // Also for data_size of 2 and 4 how to display the individual
2415 // characters i.e in which order to be decided.
2416 switch (data_size) {
2417 case 1:
2418 data8 = databuf[0];
2419 if (memory_dump)
2420 switch (display_format) {
2421 case 'd': dbg_printf("%03d ", data8); break;
2422 case 'u': dbg_printf("%03u ", data8); break;
2423 case 'o': dbg_printf("%03o ", data8); break;
2424 case 't': dbg_printf_binary ("%s ", data8, 8); break;
2425 case 'c': dbg_printf("%c", isprint(data8) ? data8 : '.'); break;
2426 default : dbg_printf("%02X ", data8); break;
2428 else
2429 switch (display_format) {
2430 case 'x': dbg_printf("\t0x%02x", (unsigned) data8); break;
2431 case 'd': dbg_printf("\t%d", (int) (Bit8s) data8); break;
2432 case 'u': dbg_printf("\t%u", (unsigned) data8); break;
2433 case 'o': dbg_printf("\t%o", (unsigned) data8); break;
2434 case 't': dbg_printf_binary("\t%s", data8, 8); break;
2435 case 'c': bx_print_char(data8); break;
2437 break;
2439 case 2:
2440 #ifdef BX_LITTLE_ENDIAN
2441 data16 = * (Bit16u *) databuf;
2442 #else
2443 data16 = (databuf[1]<<8) | databuf[0];
2444 #endif
2445 if (memory_dump)
2446 switch (display_format) {
2447 case 'd': dbg_printf("%05d ", data16); break;
2448 case 'u': dbg_printf("%05u ", data16); break;
2449 case 'o': dbg_printf("%06o ", data16); break;
2450 case 't': dbg_printf_binary ("%s ", data16, 16); break;
2451 default : dbg_printf("%04X ", data16); break;
2453 else
2454 switch (display_format) {
2455 case 'x': dbg_printf("\t0x%04x", (unsigned) data16); break;
2456 case 'd': dbg_printf("\t%d", (int) (Bit16s) data16); break;
2457 case 'u': dbg_printf("\t%u", (unsigned) data16); break;
2458 case 'o': dbg_printf("\t%o", (unsigned) data16); break;
2459 case 't': dbg_printf_binary("\t%s", data16, 16); break;
2460 case 'c':
2461 bx_print_char(data16>>8);
2462 bx_print_char(data16 & 0xff);
2463 break;
2465 break;
2467 case 4:
2468 #ifdef BX_LITTLE_ENDIAN
2469 data32 = * (Bit32u *) databuf;
2470 #else
2471 data32 = (databuf[3]<<24) | (databuf[2]<<16) |
2472 (databuf[1]<<8) | databuf[0];
2473 #endif
2474 if (memory_dump)
2475 switch (display_format) {
2476 case 'd': dbg_printf("%10d ", data32); break;
2477 case 'u': dbg_printf("%10u ", data32); break;
2478 case 'o': dbg_printf("%12o ", data32); break;
2479 case 't': dbg_printf_binary ("%s ", data32, 32); break;
2480 default : dbg_printf("%08X ", data32); break;
2482 else
2483 switch (display_format) {
2484 case 'x': dbg_printf("\t0x%08x", (unsigned) data32); break;
2485 case 'd': dbg_printf("\t%d", (int) (Bit32s) data32); break;
2486 case 'u': dbg_printf("\t%u", (unsigned) data32); break;
2487 case 'o': dbg_printf("\t%o", (unsigned) data32); break;
2488 case 't': dbg_printf_binary("\t%s", data32, 32); break;
2489 case 'c':
2490 bx_print_char(0xff & (data32>>24));
2491 bx_print_char(0xff & (data32>>16));
2492 bx_print_char(0xff & (data32>> 8));
2493 bx_print_char(0xff & (data32>> 0));
2494 break;
2496 break;
2499 addr += data_size;
2500 bx_debugger.default_addr = addr;
2501 columns++;
2502 offset += data_size;
2504 dbg_printf("\n");
2507 void bx_dbg_setpmem_command(bx_phy_address paddr, unsigned len, Bit32u val)
2509 Bit8u buf[4];
2511 switch (len) {
2512 case 1:
2513 buf[0] = (Bit8u) val;
2514 break;
2515 case 2:
2516 buf[0] = val & 0xff; val >>= 8;
2517 buf[1] = val & 0xff;
2518 break;
2519 case 4:
2520 buf[0] = val & 0xff; val >>= 8;
2521 buf[1] = val & 0xff; val >>= 8;
2522 buf[2] = val & 0xff; val >>= 8;
2523 buf[3] = val & 0xff;
2524 break;
2525 default:
2526 dbg_printf("Error: setpmem: bad length value = %u\n", len);
2527 return;
2530 if (! BX_MEM(0)->dbg_set_mem(paddr, len, buf)) {
2531 dbg_printf("Error: setpmem: could not set memory, out of physical bounds?\n");
2535 void bx_dbg_set_symbol_command(char *symbol, Bit32u val)
2537 bx_bool is_OK = false;
2538 symbol++; // get past '$'
2540 if (!strcmp(symbol, "eip")) {
2541 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EIP, val);
2543 else if (!strcmp(symbol, "eflags")) {
2544 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_EFLAGS, val);
2546 else if (!strcmp(symbol, "cs")) {
2547 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_CS, val);
2549 else if (!strcmp(symbol, "ss")) {
2550 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_SS, val);
2552 else if (!strcmp(symbol, "ds")) {
2553 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_DS, val);
2555 else if (!strcmp(symbol, "es")) {
2556 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_ES, val);
2558 else if (!strcmp(symbol, "fs")) {
2559 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_FS, val);
2561 else if (!strcmp(symbol, "gs")) {
2562 is_OK = BX_CPU(dbg_cpu)->dbg_set_reg(BX_DBG_REG_GS, val);
2564 else if (!strcmp(symbol, "cpu")) {
2565 if (val >= BX_SMP_PROCESSORS) {
2566 dbg_printf("invalid cpu id number %d\n", val);
2567 return;
2569 char cpu_param_name[10];
2570 sprintf(cpu_param_name, "cpu%d", val);
2571 dbg_cpu_list = (bx_list_c*) SIM->get_param(cpu_param_name, SIM->get_bochs_root());
2572 dbg_cpu = val;
2573 return;
2575 else if (!strcmp(symbol, "synchronous_dma")) {
2576 bx_guard.async.dma = !val;
2577 return;
2579 else if (!strcmp(symbol, "synchronous_irq")) {
2580 bx_guard.async.irq = !val;
2581 return;
2583 else if (!strcmp(symbol, "event_reports")) {
2584 bx_guard.report.irq = val;
2585 bx_guard.report.a20 = val;
2586 bx_guard.report.io = val;
2587 bx_guard.report.ucmem = val;
2588 bx_guard.report.dma = val;
2589 return;
2591 else if (!strcmp(symbol, "auto_disassemble")) {
2592 bx_dbg_set_auto_disassemble(val != 0);
2593 return;
2595 else {
2596 dbg_printf("Error: set: unrecognized symbol.\n");
2597 return;
2600 if (!is_OK) {
2601 dbg_printf("Error: could not set register '%s'.\n", symbol);
2605 void bx_dbg_query_command(const char *what)
2607 unsigned pending;
2609 if (! strcmp(what, "pending")) {
2610 pending = BX_CPU(0)->dbg_query_pending();
2612 if (pending & BX_DBG_PENDING_DMA)
2613 dbg_printf("pending DMA\n");
2615 if (pending & BX_DBG_PENDING_IRQ)
2616 dbg_printf("pending IRQ\n");
2618 if (!pending)
2619 dbg_printf("pending none\n");
2621 dbg_printf("done\n");
2623 else {
2624 dbg_printf("Error: Query '%s' not understood.\n", what);
2628 void bx_dbg_restore_command(const char *param_name, const char *restore_path)
2630 const char *path = (restore_path == NULL) ? "." : restore_path;
2631 dbg_printf("restoring param (%s) state from file (%s/%s)\n",
2632 param_name, path, param_name);
2633 if (! SIM->restore_bochs_param(SIM->get_bochs_root(), path, param_name)) {
2634 dbg_printf("Error: error occured during restore\n");
2636 else {
2637 bx_sr_after_restore_state();
2641 void bx_dbg_disassemble_current(const char *format)
2643 Bit64u addr = bx_dbg_get_laddr(bx_dbg_get_selector_value(BX_DBG_SREG_CS),
2644 BX_CPU(dbg_cpu)->get_instruction_pointer());
2645 bx_dbg_disassemble_command(format, addr, addr);
2648 void bx_dbg_disassemble_command(const char *format, Bit64u from, Bit64u to)
2650 int numlines = INT_MAX;
2652 if (from > to) {
2653 int temp = from;
2654 from = to;
2655 to = temp;
2658 if (format) {
2659 // format always begins with '/' (checked in lexer)
2660 // so we won't bother checking it here second time.
2661 numlines = atoi(format + 1);
2662 if (to == from)
2663 to = BX_MAX_BIT64U; // Disassemble just X lines
2666 unsigned dis_size = bx_debugger.disassemble_size;
2667 if (dis_size == 0) {
2668 dis_size = 16; // until otherwise proven
2669 if (BX_CPU(dbg_cpu)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b)
2670 dis_size = 32;
2671 if (BX_CPU(dbg_cpu)->get_cpu_mode() == BX_MODE_LONG_64)
2672 dis_size = 64;
2675 do {
2676 numlines--;
2678 if (! bx_dbg_read_linear(dbg_cpu, from, 16, bx_disasm_ibuf)) break;
2680 unsigned ilen = bx_disassemble.disasm(dis_size==32, dis_size==64,
2681 (bx_address)(-1), (bx_address)(-1), bx_disasm_ibuf, bx_disasm_tbuf);
2683 char *Sym=bx_dbg_disasm_symbolic_address((Bit32u)from, 0);
2685 dbg_printf("%08x: ", (unsigned) from);
2686 dbg_printf("(%20s): ", Sym?Sym:"");
2687 dbg_printf("%-25s ; ", bx_disasm_tbuf);
2689 for (unsigned j=0; j<ilen; j++)
2690 dbg_printf("%02x", (unsigned) bx_disasm_ibuf[j]);
2691 dbg_printf("\n");
2693 from += ilen;
2694 } while ((from < to) && numlines > 0);
2697 void bx_dbg_instrument_command(const char *comm)
2699 #if BX_INSTRUMENTATION
2700 if (!strcmp(comm, "start")) {
2701 BX_INSTR_START();
2703 else if (!strcmp(comm, "stop")) {
2704 BX_INSTR_STOP();
2706 else if (!strcmp(comm, "reset")) {
2707 BX_INSTR_RESET(dbg_cpu);
2709 else if (!strcmp(comm, "print")) {
2710 BX_INSTR_PRINT();
2712 else {
2713 dbg_printf("Error: command 'instrument %s' not recognized\n", comm);
2714 bx_dbg_exit(1);
2716 #else
2717 UNUSED(comm);
2719 dbg_printf("Error: instrumentation not enabled.\n");
2720 #endif
2723 void bx_dbg_doit_command(unsigned n)
2725 // generic command to add temporary hacks to
2726 // for debugging purposes
2727 UNUSED(n);
2729 bx_dbg.interrupts = n;
2730 bx_dbg.exceptions = n;
2733 void bx_dbg_crc_command(bx_phy_address addr1, bx_phy_address addr2)
2735 Bit32u crc1;
2737 if (addr1 >= addr2) {
2738 dbg_printf("Error: crc32: invalid range\n");
2739 return;
2742 if (!BX_MEM(0)->dbg_crc32(addr1, addr2, &crc1)) {
2743 dbg_printf("Error: could not crc32 memory\n");
2744 return;
2746 dbg_printf("0x%lx\n", crc1);
2749 void bx_dbg_info_dirty_command(void)
2751 unsigned char *page_tbl = BX_MEM(0)->dbg_dirty_pages;
2752 Bit32u page_tbl_size = BX_MEM(0)->get_num_allocated_pages();
2754 for (unsigned i=0; i<page_tbl_size; i++) {
2755 if (page_tbl[i]) {
2756 dbg_printf("0x%x\n", i);
2757 page_tbl[i] = 0; // reset to clean
2762 void bx_dbg_print_descriptor(unsigned char desc[8], int verbose)
2764 Bit32u lo = (desc[3] << 24) | (desc[2] << 16) | (desc[1] << 8) | (desc[0]);
2765 Bit32u hi = (desc[7] << 24) | (desc[6] << 16) | (desc[5] << 8) | (desc[4]);
2766 Bit32u base = ((lo >> 16) & 0xffff)
2767 | ((hi << 16) & 0xff0000)
2768 | (hi & 0xff000000);
2769 Bit32u limit = (hi & 0x000f0000) | (lo & 0xffff);
2770 Bit32u segment = (lo >> 16) & 0xffff;
2771 Bit32u offset = (lo & 0xffff) | (hi & 0xffff0000);
2772 unsigned type = (hi >> 8) & 0x0f;
2773 unsigned dpl = (hi >> 13) & 0x03;
2774 unsigned s = (hi >> 12) & 0x01;
2775 unsigned d_b = (hi >> 22) & 0x01;
2776 unsigned g = (hi >> 23) & 0x01;
2777 #if 0
2778 unsigned present = (hi >> 15) & 0x01;
2779 unsigned avl = (hi >> 20) & 0x01;
2780 unsigned base_is_jump_addr;
2781 if (s) {
2782 // either a code or a data segment. bit 11 (type file MSB) then says
2783 // 0=data segment, 1=code seg
2784 if (type&8) {
2785 dbg_printf("Segment type: Code, %s%s%s\n",
2786 (type&2)? "Execute/Read" : "Execute-Only",
2787 (type&4)? ", Conforming" : "",
2788 (type&1)? ", Accessed" : "");
2789 dbg_printf("D flag=%d (use %d-bit addresses, %d-bit or 8-bit operands)\n", d_b, d_b? 32 : 16);
2790 } else {
2791 dbg_printf("Segment type: Data, %s%s%s\n",
2792 (type&2)? "Read/Write" : "Read-Only",
2793 (type&4)? ", Expand-down" : "",
2794 (type&1)? ", Accessed" : "");
2796 } else {
2797 // types from IA32-devel-guide-3, page 3-15.
2798 static char *type_names[16] = { "Reserved", "16-Bit TSS (available)", "LDT", "16-Bit TSS (Busy)", "16-Bit Call Gate", "Task Gate", "16-Bit Interrupt Gate", "16-Bit Trap Gate", "Reserved", "32-Bit TSS (Available)", "Reserved", "32-Bit TSS (Busy)", "32-Bit Call Gate", "Reserved", "32-Bit Interrupt Gate", "32-Bit Trap Gate" };
2799 // some kind of gate?
2800 dbg_printf("System segment, type=0x%x=%s\n", type, type_names[type]);
2801 base_is_jump_addr = 1;
2802 // for call gates, print segment:offset and parameter count p.40-15
2803 // for task gate, only present,dpl,TSS segment selector exist. p.5-13
2804 // for interrupt gate, segment:offset,p,dpl
2805 // for trap gate, segment:offset,p,dpl
2807 dbg_printf("DPL=descriptor privilege level=%d\n", dpl);
2808 if (base_is_jump_addr) {
2809 dbg_printf("target address=%04x:%08x\n", segment, offset);
2810 } else {
2811 dbg_printf("base address=%08x\n", base);
2812 dbg_printf("G=granularity=%d\n", g);
2813 dbg_printf("limit=0x%05x %s (see G)\n", limit, g?"4K-byte units" : "bytes");
2814 dbg_printf("AVL=available to OS=%d\n", avl);
2816 dbg_printf("P=present=%d\n", present);
2817 #endif
2818 /* brief output */
2819 // 32-bit trap gate, target=0010:c0108ec4, DPL=0, present=1
2820 // code segment, base=0000:00cfffff, length=0xffff
2821 if (s) {
2822 // either a code or a data segment. bit 11 (type file MSB) then says
2823 // 0=data segment, 1=code seg
2824 if (type&8) {
2825 dbg_printf("Code segment, laddr=%08x, limit=%05x %s, %s%s%s, %d-bit\n",
2826 base, limit, g ? "* 4Kbytes" : "bytes",
2827 (type&2)? "Execute/Read" : "Execute-Only",
2828 (type&4)? ", Conforming" : "",
2829 (type&1)? ", Accessed" : "",
2830 d_b ? 32 : 16);
2831 } else {
2832 dbg_printf("Data segment, laddr=%08x, limit=%05x %s, %s%s%s\n",
2833 base, limit, g ? "* 4Kbytes" : "bytes",
2834 (type&2)? "Read/Write" : "Read-Only",
2835 (type&4)? ", Expand-down" : "",
2836 (type&1)? ", Accessed" : "");
2838 } else {
2839 // types from IA32-devel-guide-3, page 3-15.
2840 static char *undef = "???";
2841 static char *type_names[16] = { undef, "16-Bit TSS (available)", "LDT", "16-Bit TSS (Busy)", "16-Bit Call Gate", "Task Gate", "16-Bit Interrupt Gate", "16-Bit Trap Gate", undef, "32-Bit TSS (Available)", undef, "32-Bit TSS (Busy)", "32-Bit Call Gate", undef, "32-Bit Interrupt Gate", "32-Bit Trap Gate" };
2842 dbg_printf("%s ", type_names[type]);
2843 // only print more if type is valid
2844 if (type_names[type] == undef) {
2845 dbg_printf("descriptor hi=0x%08x, lo=0x%08x", hi, lo);
2846 } else {
2847 // for call gates, print segment:offset and parameter count p.4-15
2848 // for task gate, only present,dpl,TSS segment selector exist. p.5-13
2849 // for interrupt gate, segment:offset,p,dpl
2850 // for trap gate, segment:offset,p,dpl
2851 // for TSS, base address and segment limit
2852 switch (type) {
2853 case BX_SYS_SEGMENT_AVAIL_286_TSS:
2854 case BX_SYS_SEGMENT_BUSY_286_TSS:
2855 case BX_SYS_SEGMENT_AVAIL_386_TSS:
2856 case BX_SYS_SEGMENT_BUSY_386_TSS:
2857 dbg_printf("at 0x%08x, length 0x%05x", base, limit);
2858 break;
2859 case BX_SYS_SEGMENT_LDT:
2860 // it's an LDT. not much to print.
2861 break;
2862 default:
2863 // task, int, trap, or call gate.
2864 dbg_printf("target=0x%04x:0x%08x, DPL=%d", segment, offset, dpl);
2867 dbg_printf("\n");
2871 void bx_dbg_info_idt_command(unsigned from, unsigned to)
2873 bx_dbg_global_sreg_t idtr;
2874 BX_CPU(dbg_cpu)->dbg_get_idtr(&idtr);
2875 bx_bool all = 0;
2877 if (to == (unsigned) EMPTY_ARG) {
2878 to = from;
2879 if(from == (unsigned) EMPTY_ARG) { from = 0; to = 255; all = 1; }
2881 if (from > 255 || to > 255) {
2882 dbg_printf("IDT entry should be [0-255], 'info idt' command malformed\n");
2883 return;
2885 if (from > to) {
2886 unsigned temp = from;
2887 from = to;
2888 to = temp;
2891 dbg_printf("Interrupt Descriptor Table (base=0x" FMT_ADDRX ", limit=%d):\n", idtr.base, idtr.limit);
2892 for (unsigned n = from; n<=to; n++) {
2893 Bit8u entry[8];
2894 if (8*n + 7 > idtr.limit) break;
2895 if (bx_dbg_read_linear(dbg_cpu, idtr.base + 8*n, 8, entry)) {
2896 dbg_printf("IDT[0x%02x]=", n);
2897 bx_dbg_print_descriptor(entry, 0);
2899 else {
2900 dbg_printf("error: IDTR+8*%d points to invalid linear address 0x" FMT_ADDRX "\n",
2901 n, idtr.base);
2904 if (all)
2905 dbg_printf("You can list individual entries with 'info idt [NUM]' or groups with 'info idt [NUM] [NUM]'\n");
2908 void bx_dbg_info_gdt_command(unsigned from, unsigned to)
2910 bx_dbg_global_sreg_t gdtr;
2911 BX_CPU(dbg_cpu)->dbg_get_gdtr(&gdtr);
2912 bx_bool all = 0;
2914 if (to == (unsigned) EMPTY_ARG) {
2915 to = from;
2916 if(from == (unsigned) EMPTY_ARG) { from = 0; to = 0xffff; all = 1; }
2918 if (from > 0xffff || to > 0xffff) {
2919 dbg_printf("GDT entry should be [0-65535], 'info gdt' command malformed\n");
2920 return;
2922 if (from > to) {
2923 unsigned temp = from;
2924 from = to;
2925 to = temp;
2928 dbg_printf("Global Descriptor Table (base=0x" FMT_ADDRX ", limit=%d):\n", gdtr.base, gdtr.limit);
2929 for (unsigned n = from; n<=to; n++) {
2930 Bit8u entry[8];
2931 if (8*n + 7 > gdtr.limit) break;
2932 if (bx_dbg_read_linear(dbg_cpu, gdtr.base + 8*n, 8, entry)) {
2933 dbg_printf("GDT[0x%02x]=", n);
2934 bx_dbg_print_descriptor(entry, 0);
2936 else {
2937 dbg_printf("error: GDTR+8*%d points to invalid linear address 0x" FMT_ADDRX "\n",
2938 n, gdtr.base);
2941 if (all)
2942 dbg_printf("You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'\n");
2945 void bx_dbg_info_ldt_command(unsigned from, unsigned to)
2947 bx_address ldtr_base = SIM->get_param_num("LDTR.base", dbg_cpu_list)->get64();
2948 Bit32u ldtr_limit = SIM->get_param_num("LDTR.limit", dbg_cpu_list)->get();
2950 bx_bool all = 0;
2952 if (to == (unsigned) EMPTY_ARG) {
2953 to = from;
2954 if(from == (unsigned) EMPTY_ARG) { from = 0; to = 0xffff; all = 1; }
2956 if (from > 0xffff || to > 0xffff) {
2957 dbg_printf("LDT entry should be [0-65535], 'info ldt' command malformed\n");
2958 return;
2960 if (from > to) {
2961 unsigned temp = from;
2962 from = to;
2963 to = temp;
2966 dbg_printf("Local Descriptor Table (base=0x" FMT_ADDRX ", limit=%d):\n", ldtr_base, ldtr_limit);
2967 for (unsigned n = from; n<=to; n++) {
2968 Bit8u entry[8];
2969 if (8*n + 7 > ldtr_limit) break;
2970 if (bx_dbg_read_linear(dbg_cpu, ldtr_base + 8*n, 8, entry)) {
2971 dbg_printf("LDT[0x%02x]=", n);
2972 bx_dbg_print_descriptor(entry, 0);
2974 else {
2975 dbg_printf("error: LDTR+8*%d points to invalid linear address 0x" FMT_ADDRX "\n",
2976 n, ldtr_base);
2979 if (all)
2980 dbg_printf("You can list individual entries with 'info ldt [NUM]' or groups with 'info ldt [NUM] [NUM]'\n");
2983 /*form RB list*/
2984 static const char* bx_dbg_ivt_desc(int intnum)
2986 const char* ret;
2987 switch (intnum) {
2988 case 0x00: ret = "DIVIDE ERROR" ; break;
2989 case 0x01: ret = "SINGLE STEP" ; break;
2990 case 0x02: ret = "NON-MASKABLE INTERRUPT" ; break;
2991 case 0x03: ret = "BREAKPOINT" ; break;
2992 case 0x04: ret = "INT0 DETECTED OVERFLOW" ; break;
2993 case 0x05: ret = "BOUND RANGE EXCEED" ; break;
2994 case 0x06: ret = "INVALID OPCODE" ; break;
2995 case 0x07: ret = "PROCESSOR EXTENSION NOT AVAILABLE" ; break;
2996 case 0x08: ret = "IRQ0 - SYSTEM TIMER" ; break;
2997 case 0x09: ret = "IRQ1 - KEYBOARD DATA READY" ; break;
2998 case 0x0a: ret = "IRQ2 - LPT2" ; break;
2999 case 0x0b: ret = "IRQ3 - COM2" ; break;
3000 case 0x0c: ret = "IRQ4 - COM1" ; break;
3001 case 0x0d: ret = "IRQ5 - FIXED DISK" ; break;
3002 case 0x0e: ret = "IRQ6 - DISKETTE CONTROLLER" ; break;
3003 case 0x0f: ret = "IRQ7 - PARALLEL PRINTER" ; break;
3004 case 0x10: ret = "VIDEO" ; break;
3005 case 0x11: ret = "GET EQUIPMENT LIST" ; break;
3006 case 0x12: ret = "GET MEMORY SIZE" ; break;
3007 case 0x13: ret = "DISK" ; break;
3008 case 0x14: ret = "SERIAL" ; break;
3009 case 0x15: ret = "SYSTEM" ; break;
3010 case 0x16: ret = "KEYBOARD" ; break;
3011 case 0x17: ret = "PRINTER" ; break;
3012 case 0x18: ret = "CASETTE BASIC" ; break;
3013 case 0x19: ret = "BOOTSTRAP LOADER" ; break;
3014 case 0x1a: ret = "TIME" ; break;
3015 case 0x1b: ret = "KEYBOARD - CONTROL-BREAK HANDLER" ; break;
3016 case 0x1c: ret = "TIME - SYSTEM TIMER TICK" ; break;
3017 case 0x1d: ret = "SYSTEM DATA - VIDEO PARAMETER TABLES"; break;
3018 case 0x1e: ret = "SYSTEM DATA - DISKETTE PARAMETERS" ; break;
3019 case 0x1f: ret = "SYSTEM DATA - 8x8 GRAPHICS FONT" ; break;
3020 case 0x70: ret = "IRQ8 - CMOS REAL-TIME CLOCK" ; break;
3021 case 0x71: ret = "IRQ9 - REDIRECTED TO INT 0A BY BIOS" ; break;
3022 case 0x72: ret = "IRQ10 - RESERVED" ; break;
3023 case 0x73: ret = "IRQ11 - RESERVED" ; break;
3024 case 0x74: ret = "IRQ12 - POINTING DEVICE" ; break;
3025 case 0x75: ret = "IRQ13 - MATH COPROCESSOR EXCEPTION" ; break;
3026 case 0x76: ret = "IRQ14 - HARD DISK CONTROLLER OPERATION COMPLETE"; break;
3027 case 0x77: ret = "IRQ15 - SECONDARY IDE CONTROLLER OPERATION COMPLETE"; break;
3028 default : ret = "" ; break;
3030 return ret;
3033 void bx_dbg_info_ivt_command(unsigned from, unsigned to)
3035 unsigned char buff[4];
3036 Bit16u seg;
3037 Bit16u off;
3038 bx_bool all = 0;
3039 bx_dbg_global_sreg_t idtr;
3041 BX_CPU(dbg_cpu)->dbg_get_idtr(&idtr);
3043 if (! BX_CPU(dbg_cpu)->protected_mode())
3045 if (to == (unsigned) EMPTY_ARG) {
3046 to = from;
3047 if(from == (unsigned) EMPTY_ARG) { from = 0; to = 255; all = 1; }
3049 if (from > 255 || to > 255) {
3050 dbg_printf("IVT entry should be [0-255], 'info ivt' command malformed\n");
3051 return;
3053 if (from > to) {
3054 unsigned temp = from;
3055 from = to;
3056 to = temp;
3059 for (unsigned i = from; i <= to; i++)
3061 BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), idtr.base + i * 4, sizeof(buff), buff);
3062 #ifdef BX_LITTLE_ENDIAN
3063 seg = *(Bit16u*)(&buff[2]);
3064 off = *(Bit16u*)(&buff[0]);
3065 #else
3066 seg = (buff[3] << 8) | buff[2];
3067 off = (buff[1] << 8) | buff[0];
3068 #endif
3069 BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu), ((seg << 4) + off), sizeof(buff), buff);
3070 dbg_printf("INT# %02x > %04X:%04X (" FMT_ADDRX ") %s%s\n", i, seg, off,
3071 ((seg << 4) + off), bx_dbg_ivt_desc(i),
3072 (buff[0] == 0xcf) ? " ; dummy iret" : "");
3074 if (all) dbg_printf("You can list individual entries with 'info ivt [NUM]' or groups with 'info ivt [NUM] [NUM]'\n");
3076 else
3077 dbg_printf("cpu in protected mode, use info idt\n");
3080 static void bx_dbg_print_tss(Bit8u *tss, int len)
3082 if (len<104) {
3083 dbg_printf("Invalid tss length (limit must be greater then 103)\n");
3084 return;
3087 dbg_printf("ss:esp(0): 0x%04x:0x%08x\n",
3088 *(Bit16u*)(tss+8), *(Bit32u*)(tss+4));
3089 dbg_printf("ss:esp(1): 0x%04x:0x%08x\n",
3090 *(Bit16u*)(tss+0x10), *(Bit32u*)(tss+0xc));
3091 dbg_printf("ss:esp(2): 0x%04x:0x%08x\n",
3092 *(Bit16u*)(tss+0x18), *(Bit32u*)(tss+0x14));
3093 dbg_printf("cr3: 0x%08x\n", *(Bit32u*)(tss+0x1c));
3094 dbg_printf("eip: 0x%08x\n", *(Bit32u*)(tss+0x20));
3095 dbg_printf("eflags: 0x%08x\n", *(Bit32u*)(tss+0x24));
3097 dbg_printf("cs: 0x%04x ds: 0x%04x ss: 0x%04x\n",
3098 *(Bit16u*)(tss+76), *(Bit16u*)(tss+84), *(Bit16u*)(tss+80));
3099 dbg_printf("es: 0x%04x fs: 0x%04x gs: 0x%04x\n",
3100 *(Bit16u*)(tss+72), *(Bit16u*)(tss+88), *(Bit16u*)(tss+92));
3102 dbg_printf("eax: 0x%08x ebx: 0x%08x ecx: 0x%08x edx: 0x%08x\n",
3103 *(Bit32u*)(tss+0x28), *(Bit32u*)(tss+0x34), *(Bit32u*)(tss+0x2c), *(Bit32u*)(tss+0x30));
3104 dbg_printf("esi: 0x%08x edi: 0x%08x ebp: 0x%08x esp: 0x%08x\n",
3105 *(Bit32u*)(tss+0x40), *(Bit32u*)(tss+0x44), *(Bit32u*)(tss+0x3c), *(Bit32u*)(tss+0x38));
3107 dbg_printf("ldt: 0x%04x\n", *(Bit16u*)(tss+0x60));
3108 dbg_printf("i/o map: 0x%04x\n", *(Bit16u*)(tss+0x66));
3111 void bx_dbg_info_tss_command(void)
3113 bx_dbg_sreg_t tr;
3114 BX_CPU(dbg_cpu)->dbg_get_tr(&tr);
3116 Bit32u laddr = (tr.des_l>>16) |
3117 ((tr.des_h<<16)&0x00ff0000) | (tr.des_h & 0xff000000);
3118 Bit32u len = (tr.des_l & 0xffff) + 1;
3120 dbg_printf("tr:s=0x%x, base=0x%x, valid=%u\n",
3121 (unsigned) tr.sel, laddr, (unsigned) tr.valid);
3123 bx_phy_address paddr = 0;
3124 BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(laddr, &paddr);
3125 bx_dbg_print_tss(BX_MEM(0)->get_vector(paddr), len);
3129 * this function implements the info ne2k commands in the debugger
3130 * info ne2k - shows all registers
3131 * info ne2k page N - shows all registers in a page
3132 * info ne2k page N reg M - shows just one register
3134 void bx_dbg_info_ne2k(int page, int reg)
3136 #if BX_SUPPORT_NE2K
3137 DEV_ne2k_print_info(stderr, page, reg, 0);
3138 #else
3139 dbg_printf("NE2000 support is not compiled in\n");
3140 #endif
3144 * this implements the info pic command in the debugger.
3145 * info pic - shows pic registers
3147 void bx_dbg_info_pic()
3149 DEV_pic_show_pic_state();
3153 * this implements the info vga command in the debugger.
3154 * info vga - shows vga registers
3156 void bx_dbg_info_vga()
3158 DEV_vga_dump_status();
3162 * this implements the info pci command in the debugger.
3163 * info pci - shows i440fx state
3165 void bx_dbg_info_pci()
3167 #if BX_SUPPORT_PCI
3168 if (SIM->get_param_bool(BXPN_I440FX_SUPPORT)->get()) {
3169 DEV_pci_print_i440fx_state();
3171 else {
3172 dbg_printf("PCI support is disabled in .bochsrc\n");
3174 #else
3175 dbg_printf("PCI support is not compiled in\n");
3176 #endif
3180 // Reports from various events
3183 void bx_dbg_iac_report(unsigned vector, unsigned irq)
3185 if (bx_guard.report.irq) {
3186 dbg_printf("event at t=" FMT_LL "d IRQ irq=%u vec=%x\n",
3187 bx_pc_system.time_ticks(), irq, vector);
3191 void bx_dbg_a20_report(unsigned val)
3193 if (bx_guard.report.a20) {
3194 dbg_printf("event at t=" FMT_LL "d A20 val=%u\n",
3195 bx_pc_system.time_ticks(), val);
3199 void bx_dbg_io_report(Bit32u port, unsigned size, unsigned op, Bit32u val)
3201 if (bx_guard.report.io) {
3202 dbg_printf("event at t=" FMT_LL "d IO addr=0x%x size=%u op=%s val=0x%x\n",
3203 bx_pc_system.time_ticks(),
3204 port,
3205 size,
3206 (op==BX_READ) ? "read" : "write",
3207 (unsigned) val);
3211 void bx_dbg_ucmem_report(bx_address addr, unsigned size, unsigned op, Bit32u val)
3213 if (bx_guard.report.ucmem) {
3214 dbg_printf("event at t=" FMT_LL "d UCmem addr=0x" FMT_ADDRX " size=%u op=%s val=0x%x\n",
3215 bx_pc_system.time_ticks(),
3216 addr,
3217 size,
3218 (op==BX_READ) ? "read" : "write",
3219 (unsigned) val);
3223 void bx_dbg_dma_report(bx_phy_address addr, unsigned len, unsigned what, Bit32u val)
3225 if (bx_dbg_batch_dma.this_many == 0) {
3226 dbg_printf("%s: DMA batch this_many=0.\n", argv0);
3227 bx_dbg_exit(1);
3230 // if Q is full, post events (and flush)
3231 if (bx_dbg_batch_dma.Qsize >= bx_dbg_batch_dma.this_many) {
3232 dbg_printf("%s: DMA batch Q was not flushed.\n", argv0);
3233 bx_dbg_exit(1);
3236 // if Q already has MAX elements in it
3237 if (bx_dbg_batch_dma.Qsize >= BX_BATCH_DMA_BUFSIZE) {
3238 dbg_printf("%s: DMA batch buffer overrun.\n", argv0);
3239 bx_dbg_exit(1);
3242 bx_dbg_batch_dma.Qsize++;
3243 bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].addr = addr;
3244 bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].len = len;
3245 bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].what = what;
3246 bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].val = val;
3247 bx_dbg_batch_dma.Q[bx_dbg_batch_dma.Qsize-1].time = bx_pc_system.time_ticks();
3249 // if Q is full, post events (and flush)
3250 if (bx_dbg_batch_dma.Qsize >= bx_dbg_batch_dma.this_many)
3251 bx_dbg_post_dma_reports();
3254 void bx_dbg_post_dma_reports(void)
3256 unsigned i;
3257 unsigned addr, len, what, val;
3258 unsigned last_addr, last_len, last_what;
3259 unsigned print_header;
3260 unsigned first_iteration;
3262 if (bx_guard.report.dma) {
3263 if (bx_dbg_batch_dma.Qsize == 0) return; // nothing batched to print
3265 // compress output so all contiguous DMA ops of the same type and size
3266 // are printed on the same line
3267 last_addr = bx_dbg_batch_dma.Q[0].addr;
3268 last_len = bx_dbg_batch_dma.Q[0].len;
3269 last_what = bx_dbg_batch_dma.Q[0].what;
3270 first_iteration = 1;
3272 for (i=0; i<bx_dbg_batch_dma.Qsize; i++) {
3273 addr = bx_dbg_batch_dma.Q[i].addr;
3274 len = bx_dbg_batch_dma.Q[i].len;
3275 what = bx_dbg_batch_dma.Q[i].what;
3276 val = bx_dbg_batch_dma.Q[i].val;
3278 if (len != last_len)
3279 print_header = 1;
3280 else if (what != last_what)
3281 print_header = 1;
3282 else if (addr != (last_addr + last_len))
3283 print_header = 1;
3284 else
3285 print_header = 0;
3287 // now store current values for next iteration
3288 last_addr = addr;
3289 last_len = len;
3290 last_what = what;
3292 if (print_header) {
3293 if (!first_iteration) // need return from previous line
3294 dbg_printf("\n");
3295 else
3296 first_iteration = 0;
3297 // need to output the event header
3298 dbg_printf("event at t=" FMT_LL "d DMA addr=0x%x size=%u op=%s val=0x%x",
3299 bx_pc_system.time_ticks(),
3300 addr, len, (what==BX_READ) ? "read" : "write", val);
3301 print_header = 0;
3303 else {
3304 // *no* need to output the event header
3305 dbg_printf(" 0x%x", val);
3308 if (bx_dbg_batch_dma.Qsize)
3309 dbg_printf("\n");
3312 // empty Q, regardless of whether reports are printed
3313 bx_dbg_batch_dma.Qsize = 0;
3316 void bx_dbg_dump_table(void)
3318 Bit32u lin, start_lin; // show only low 32 bit
3319 bx_phy_address phy, start_phy; // start of a valid translation interval
3320 bx_bool valid;
3322 if (! BX_CPU(dbg_cpu)->cr0.get_PG()) {
3323 printf("paging off\n");
3324 return;
3327 printf("cr3: 0x"FMT_PHY_ADDRX"\n", BX_CPU(dbg_cpu)->cr3);
3329 lin = 0;
3330 phy = 0;
3332 start_lin = 1;
3333 start_phy = 2;
3334 while(1) {
3335 valid = BX_CPU(dbg_cpu)->dbg_xlate_linear2phy(lin, &phy);
3336 if(valid) {
3337 if((lin - start_lin) != (phy - start_phy)) {
3338 if(start_lin != 1)
3339 dbg_printf("0x%08x-0x%08x -> 0x"FMT_PHY_ADDRX"-0x"FMT_PHY_ADDRX"\n",
3340 start_lin, lin - 1, start_phy, start_phy + (lin-1-start_lin));
3341 start_lin = lin;
3342 start_phy = phy;
3344 } else {
3345 if(start_lin != 1)
3346 dbg_printf("0x%08x-0x%08x -> 0x"FMT_PHY_ADDRX"-0x"FMT_PHY_ADDRX"\n",
3347 start_lin, lin - 1, start_phy, start_phy + (lin-1-start_lin));
3348 start_lin = 1;
3349 start_phy = 2;
3352 if(lin == 0xfffff000) break;
3353 lin += 0x1000;
3355 if(start_lin != 1)
3356 dbg_printf("0x%08x-0x%08x -> 0x"FMT_PHY_ADDRX"-0x"FMT_PHY_ADDRX"\n",
3357 start_lin, 0xffffffff, start_phy, start_phy + (0xffffffff-start_lin));
3360 void bx_dbg_print_help(void)
3362 dbg_printf("h|help - show list of debugger commands\n");
3363 dbg_printf("h|help command - show short command description\n");
3364 dbg_printf("-*- Debugger control -*-\n");
3365 dbg_printf(" help, q|quit|exit, set, instrument, show, trace, trace-reg,\n");
3366 dbg_printf(" trace-mem, record, playback, ldsym, slist\n");
3367 dbg_printf("-*- Execution control -*-\n");
3368 dbg_printf(" c|cont|continue, s|step|stepi, p|n|next, modebp\n");
3369 dbg_printf("-*- Breakpoint management -*-\n");
3370 dbg_printf(" vb|vbreak, lb|lbreak, pb|pbreak|b|break, sb, sba, blist,\n");
3371 dbg_printf(" bpe, bpd, d|del|delete\n");
3372 dbg_printf("-*- CPU and memory contents -*-\n");
3373 dbg_printf(" x, xp, u|disasm|disassemble, setpmem, crc,\n");
3374 dbg_printf(" r|reg|regs|registers, fp|fpu, mmx, sse, sreg, creg, info,\n");
3375 dbg_printf(" page, set, ptime, print-stack, watch, unwatch, ?|calc\n");
3376 dbg_printf("-*- Working with bochs param tree -*-\n");
3377 dbg_printf(" show \"param\", restore\n");
3380 void bx_dbg_calc_command(Bit64u value)
3382 dbg_printf("0x" FMT_LL "x " FMT_LL "d\n", value, value);
3385 Bit8u bx_dbg_get_reg8l_value(unsigned reg)
3387 if (reg < BX_GENERAL_REGISTERS)
3388 return BX_CPU(dbg_cpu)->get_reg8l(reg);
3390 dbg_printf("Unknown 8BL register [%d] !!!\n", reg);
3391 return 0;
3394 Bit8u bx_dbg_get_reg8h_value(unsigned reg)
3396 if (reg < BX_GENERAL_REGISTERS)
3397 return BX_CPU(dbg_cpu)->get_reg8h(reg);
3399 dbg_printf("Unknown 8BH register [%d] !!!\n", reg);
3400 return 0;
3403 Bit16u bx_dbg_get_reg16_value(unsigned reg)
3405 if (reg < BX_GENERAL_REGISTERS)
3406 return BX_CPU(dbg_cpu)->get_reg16(reg);
3408 dbg_printf("Unknown 16B register [%d] !!!\n", reg);
3409 return 0;
3412 Bit32u bx_dbg_get_reg32_value(unsigned reg)
3414 if (reg < BX_GENERAL_REGISTERS)
3415 return BX_CPU(dbg_cpu)->get_reg32(reg);
3417 dbg_printf("Unknown 32B register [%d] !!!\n", reg);
3418 return 0;
3421 Bit64u bx_dbg_get_reg64_value(unsigned reg)
3423 #if BX_SUPPORT_X86_64
3424 if (reg < BX_GENERAL_REGISTERS)
3425 return BX_CPU(dbg_cpu)->get_reg64(reg);
3426 #endif
3428 dbg_printf("Unknown 64B register [%d] !!!\n", reg);
3429 return 0;
3432 void bx_dbg_set_reg8l_value(unsigned reg, Bit8u value)
3434 if (reg < BX_GENERAL_REGISTERS)
3435 BX_CPU(dbg_cpu)->set_reg8l(reg, value);
3436 else
3437 dbg_printf("Unknown 8BL register [%d] !!!\n", reg);
3440 void bx_dbg_set_reg8h_value(unsigned reg, Bit8u value)
3442 if (reg < BX_GENERAL_REGISTERS)
3443 BX_CPU(dbg_cpu)->set_reg8h(reg, value);
3444 else
3445 dbg_printf("Unknown 8BH register [%d] !!!\n", reg);
3448 void bx_dbg_set_reg16_value(unsigned reg, Bit16u value)
3450 if (reg < BX_GENERAL_REGISTERS)
3451 BX_CPU(dbg_cpu)->set_reg16(reg, value);
3452 else
3453 dbg_printf("Unknown 16B register [%d] !!!\n", reg);
3456 void bx_dbg_set_reg32_value(unsigned reg, Bit32u value)
3458 if (reg < BX_GENERAL_REGISTERS)
3459 BX_CPU(dbg_cpu)->set_reg32(reg, value);
3460 else
3461 dbg_printf("Unknown 32B register [%d] !!!\n", reg);
3464 void bx_dbg_set_reg64_value(unsigned reg, Bit64u value)
3466 #if BX_SUPPORT_X86_64
3467 if (reg < BX_GENERAL_REGISTERS)
3468 BX_CPU(dbg_cpu)->set_reg64(reg, value);
3469 else
3470 #endif
3471 dbg_printf("Unknown 64B register [%d] !!!\n", reg);
3474 Bit16u bx_dbg_get_selector_value(unsigned int seg_no)
3476 bx_dbg_sreg_t sreg;
3478 if (seg_no > 5) {
3479 dbg_printf("Error: seg_no out of bounds\n");
3480 return 0;
3482 BX_CPU(dbg_cpu)->dbg_get_sreg(&sreg, seg_no);
3483 if (!sreg.valid) {
3484 dbg_printf("Error: segment valid bit cleared\n");
3485 return 0;
3487 return sreg.sel;
3490 Bit16u bx_dbg_get_ip(void)
3492 return BX_CPU(dbg_cpu)->get_ip();
3495 Bit32u bx_dbg_get_eip(void)
3497 return BX_CPU(dbg_cpu)->get_eip();
3500 bx_address bx_dbg_get_instruction_pointer(void)
3502 return BX_CPU(dbg_cpu)->get_instruction_pointer();
3505 Bit32u bx_dbg_get_laddr(Bit16u sel, Bit32u ofs)
3507 Bit32u laddr;
3509 if (BX_CPU(dbg_cpu)->protected_mode()) {
3510 bx_descriptor_t descriptor;
3511 bx_selector_t selector;
3512 Bit32u dword1, dword2;
3514 /* if selector is NULL, error */
3515 if ((sel & 0xfffc) == 0) {
3516 dbg_printf("ERROR: Dereferencing a NULL selector!\n");
3517 return 0;
3520 /* parse fields in selector */
3521 BX_CPU(dbg_cpu)->parse_selector(sel, &selector);
3523 Bit32u desc_base;
3524 if (selector.ti) {
3525 // LDT
3526 if (((Bit32u)selector.index*8 + 7) > BX_CPU(dbg_cpu)->ldtr.cache.u.system.limit) {
3527 dbg_printf("ERROR: selector (%04x) > GDT size limit\n", selector.index*8);
3528 return 0;
3530 desc_base = BX_CPU(dbg_cpu)->ldtr.cache.u.system.base;
3532 else {
3533 // GDT
3534 if (((Bit32u)selector.index*8 + 7) > BX_CPU(dbg_cpu)->gdtr.limit) {
3535 dbg_printf("ERROR: selector (%04x) > GDT size limit\n", selector.index*8);
3536 return 0;
3538 desc_base = BX_CPU(dbg_cpu)->gdtr.base;
3541 if (! bx_dbg_read_linear(dbg_cpu, desc_base + selector.index * 8, 4, (Bit8u*) &dword1)) {
3542 dbg_printf("ERROR: cannot read selector (0x%04x)\n", selector.index);
3543 return 0;
3545 if (! bx_dbg_read_linear(dbg_cpu, desc_base + selector.index * 8 + 4, 4, (Bit8u*) &dword2)) {
3546 dbg_printf("ERROR: cannot read selector (0x%04x)\n", selector.index);
3547 return 0;
3550 memset (&descriptor, 0, sizeof (descriptor));
3551 BX_CPU(dbg_cpu)->parse_descriptor(dword1, dword2, &descriptor);
3553 if (!descriptor.segment) {
3554 dbg_printf("ERROR: selector %04x points to a system descriptor and is not supported!\n", sel);
3555 return 0;
3558 /* #NP(selector) if descriptor is not present */
3559 if (descriptor.p==0) {
3560 dbg_printf("ERROR: descriptor %04x not present!\n", sel);
3561 return 0;
3564 Bit32u lowaddr, highaddr;
3566 // expand-down
3567 if (IS_DATA_SEGMENT(descriptor.type) && IS_DATA_SEGMENT_EXPAND_DOWN(descriptor.type)) {
3568 lowaddr = descriptor.u.segment.limit_scaled;
3569 highaddr = descriptor.u.segment.g ? 0xffffffff : 0xffff;
3571 else {
3572 lowaddr = 0;
3573 highaddr = descriptor.u.segment.limit_scaled;
3576 if ((ofs < lowaddr) || (ofs > highaddr)) {
3577 dbg_printf("WARNING: Offset %08X is out of selector %04x limit (%08x...%08x)!\n",
3578 ofs, sel, lowaddr, highaddr);
3581 laddr = descriptor.u.segment.base + ofs;
3583 else {
3584 laddr = sel * 16 + ofs;
3587 return laddr;
3590 void bx_dbg_step_over_command()
3592 bx_address Laddr = BX_CPU(dbg_cpu)->guard_found.laddr;
3594 if (! bx_dbg_read_linear(dbg_cpu, Laddr, 16, bx_disasm_ibuf))
3596 return;
3599 x86_insn insn = bx_disassemble.decode(BX_CPU(dbg_cpu)->guard_found.is_32bit_code,
3600 BX_CPU(dbg_cpu)->guard_found.is_64bit_code,
3601 BX_CPU(dbg_cpu)->get_segment_base(BX_SEG_REG_CS),
3602 BX_CPU(dbg_cpu)->guard_found.eip, bx_disasm_ibuf, bx_disasm_tbuf);
3604 unsigned b1 = insn.b1;
3606 switch(b1) {
3607 // Jcc short
3608 case 0x70:
3609 case 0x71:
3610 case 0x72:
3611 case 0x73:
3612 case 0x74:
3613 case 0x75:
3614 case 0x76:
3615 case 0x77:
3616 case 0x78:
3617 case 0x79:
3618 case 0x7A:
3619 case 0x7B:
3620 case 0x7C:
3621 case 0x7D:
3622 case 0x7E:
3623 case 0x7F:
3625 // Jcc near
3626 case 0x180:
3627 case 0x181:
3628 case 0x182:
3629 case 0x183:
3630 case 0x184:
3631 case 0x185:
3632 case 0x186:
3633 case 0x187:
3634 case 0x188:
3635 case 0x189:
3636 case 0x18A:
3637 case 0x18B:
3638 case 0x18C:
3639 case 0x18D:
3640 case 0x18E:
3641 case 0x18F:
3643 // jcxz
3644 case 0xE3:
3646 // retn n
3647 case 0xC2:
3648 // retn
3649 case 0xC3:
3650 // retf n
3651 case 0xCA:
3652 // retf
3653 case 0xCB:
3654 // iret
3655 case 0xCF:
3657 // jmp near
3658 case 0xE9:
3659 // jmp far
3660 case 0xEA:
3661 // jmp short
3662 case 0xEB:
3663 bx_dbg_stepN_command(1);
3664 return;
3665 // jmp absolute indirect
3666 case 0xFF:
3667 switch (insn.nnn) {
3668 // near
3669 case 4:
3670 // far
3671 case 5:
3672 bx_dbg_stepN_command (1);
3673 return;
3677 // calls, ints, loops and so on
3678 int BpId = bx_dbg_lbreakpoint_command(bkStepOver, Laddr + insn.ilen);
3679 if (BpId == -1) {
3680 dbg_printf("bx_dbg_step_over_command:: Failed to set lbreakpoint !\n");
3681 return;
3684 bx_dbg_continue_command();
3686 if (bx_dbg_del_lbreak (BpId))
3687 bx_dbg_breakpoint_changed();
3690 #endif /* if BX_DEBUGGER */