1 /////////////////////////////////////////////////////////////////////////
2 // $Id: dbg_main.cc,v 1.165 2008/12/08 20:20:30 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
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 /////////////////////////////////////////////////////////////////////////
34 #include "iodev/iodev.h"
37 #define LOG_THIS genlog->
42 #include <readline/readline.h>
43 #if HAVE_READLINE_HISTORY_H
44 #include <readline/history.h>
49 // default CPU in the debugger. For commands like "dump_cpu" it will
50 // use the default instead of always dumping all cpus.
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
;
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
;
73 unsigned next_bpoint_id
;
74 unsigned next_wpoint_id
;
79 char fname
[BX_MAX_PATH
];
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);
98 void bx_dbg_post_dma_reports(void);
99 #define BX_BATCH_DMA_BUFSIZE 512
102 unsigned this_many
; // batch this many max before posting events
103 unsigned Qsize
; // this many have been batched
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
];
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
, ...)
130 char *buf
= new char[DBG_PRINTF_BUFFER_LEN
+1];
131 vsnprintf(buf
, DBG_PRINTF_BUFFER_LEN
, fmt
, 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");
184 BX_PANIC(("Can not open debugger log file '%s'", debugger_log_filename
));
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
,
200 "Simulation is running", "", 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
);
233 return(0); // keep compiler happy
236 void bx_dbg_interpret_line(char *cmd
)
238 bx_add_lex_input(cmd
);
242 void bx_dbg_user_input_loop(void)
245 unsigned include_cmd_len
= strlen(BX_INCLUDE_CMD
);
249 SIM
->set_display_mode(DISP_MODE_CONFIG
);
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
));
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')
267 int len
= strlen(ptr
);
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
);
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
);
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
);
297 void bx_get_command(void)
301 bx_infile_stack
[bx_infile_stack_index
].lineno
++;
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();
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];
318 // if debug_get_next_command returned NULL, probably the GUI is
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");
331 charptr_ret
= &tmp_buf
[0];
334 charptr_ret
= fgets(tmp_buf
, sizeof(tmp_buf
),
335 bx_infile_stack
[bx_infile_stack_index
].fp
);
337 #else /* !HAVE_LIBREADLINE */
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
);
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
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"));
364 // error was not EOF, see if it was from a Ctrl-C
365 if (bx_guard
.interrupt_requested
) {
368 tmp_buf_ptr
= &tmp_buf
[0];
369 bx_guard
.interrupt_requested
= 0;
373 dbg_printf("fgets() returned ERROR.\n");
374 dbg_printf("intr request was %u\n", bx_guard
.interrupt_requested
);
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))
392 int bx_nest_infile(char *path
)
396 tmp_fp
= fopen(path
, "r");
398 dbg_printf("%s: can not open file '%s' for reading.\n", argv0
, path
);
402 if ((bx_infile_stack_index
+1) >= BX_INFILE_DEPTH
) {
403 dbg_printf("%s: source files nested too deeply\n", argv0
);
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;
415 void bx_unnest_infile(void)
417 if (bx_infile_stack_index
<= 0) {
418 dbg_printf("%s: ERROR: unnest_infile(): nesting level = 0.\n",
423 fclose(bx_infile_stack
[bx_infile_stack_index
].fp
);
424 bx_infile_stack_index
--;
429 dbg_printf("%s: ERROR: bxwrap() called.\n", argv0
);
431 return(0); // keep compiler quiet
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
,
445 if (bx_infile_stack_index
> 0) {
446 dbg_printf("%s: ERROR in source file causes exit.\n", argv0
);
451 void bx_debug_ctrlc_handler(int 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
));
466 BX_INFO(("Ctrl-C detected in signal handler."));
468 signal(SIGINT
, bx_debug_ctrlc_handler
);
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",
483 "(#BP) breakpoint match",
485 "(#BR) boundary check",
486 "(#UD) undefined opcode",
487 "(#NM) device not available",
488 "(#DF) double fault",
489 "(#CO) coprocessor overrun",
491 "(#NP) segment not present",
493 "(#GP) general protection fault",
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
);
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
)
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
;
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
;
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
)
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)",
567 (write
) ? "WR" : "RD",
573 dbg_printf(": 0x%02X", (unsigned) val8
);
576 Bit16u val16
= *((Bit16u
*) data
);
577 dbg_printf(": 0x%04X", (unsigned) val16
);
580 Bit32u val32
= *((Bit32u
*) data
);
581 dbg_printf(": 0x%08X", (unsigned) val32
);
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));
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
)
605 bx_bool write
= rw
& 1;
607 dbg_printf("[CPU%d %s]: PHY 0x" FMT_PHY_ADDRX
" (len=%d)",
609 (write
) ? "WR" : "RD",
615 dbg_printf(": 0x%02X", (unsigned) val8
);
618 Bit16u val16
= *((Bit16u
*) data
);
619 dbg_printf(": 0x%04X", (unsigned) val16
);
622 Bit32u val32
= *((Bit32u
*) data
);
623 dbg_printf(": 0x%08X", (unsigned) val32
);
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));
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();
652 // functions for browsing of cpu state
655 void bx_dbg_print_sse_state(void)
658 Bit32u mxcsr
= SIM
->get_param_num("SSE.mxcsr", dbg_cpu_list
)->get();
659 dbg_printf("MXCSR: 0x%08x\n", mxcsr
);
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
));
671 dbg_printf("The CPU doesn't support SSE state !\n");
675 void bx_dbg_print_mmx_state(void)
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
));
685 dbg_printf("The CPU doesn't support MMX state !\n");
689 void bx_dbg_print_fpu_state(void)
692 BX_CPU(dbg_cpu
)->print_state_FPU();
694 dbg_printf("The CPU doesn't support FPU state !\n");
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");
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");
767 void bx_dbg_info_segment_regs_command(void)
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
)
825 if (which_regs_mask
& BX_INFO_GENERAL_PURPOSE_REGS
) {
827 dbg_printf("%s:\n", BX_CPU(dbg_cpu
)->name
);
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
);
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
));
884 reg
= BX_CPU(dbg_cpu
)->read_eflags();
885 dbg_printf("eflags 0x%08x\n", (unsigned) reg
);
890 if (which_regs_mask
& BX_INFO_FPU_REGS
) {
891 bx_dbg_print_fpu_state();
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"));
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");
953 if (timebp_queue_size
== MAX_CONCURRENT_BPS
) {
954 dbg_printf("Too many time break points\n");
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]) {
963 for (int i
= timebp_queue_size
; i
>= 0; i
--)
964 timebp_queue
[i
+1] = timebp_queue
[i
];
965 timebp_queue
[0] = abs_time
;
967 bx_pc_system
.activate_timer_ticks(timebp_timer
, diff
, 1);
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");
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
;
982 timebp_queue
[timebp_queue_size
] = abs_time
;
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
)
998 for (int i
= 0; i
< 4; i
++) {
999 ret
|= (buf
[i
] << (8 * i
));
1004 void bx_dbg_record_command(char* path_quoted
)
1006 // skip beginning double quote
1007 if (path_quoted
[0] == '"')
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
);
1019 dbg_printf("Error opening '%s' for writing\n", path_quoted
);
1022 static FILE* playback_file
= 0;
1024 struct playback_entry_t
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
))
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
);
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();
1062 if (playback_timer_index
>= 0)
1063 bx_pc_system
.activate_timer_ticks(playback_timer_index
, diff
, 0);
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
);
1074 dbg_printf("Unknown playback command '%s'\n", command
);
1077 enter_playback_entry();
1080 void bx_dbg_playback_command(char* path_quoted
)
1082 // skip beginning double quote
1083 if (path_quoted
[0] == '"')
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();
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
;
1116 bx_bool paddr_valid
;
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
);
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
);
1130 dbg_printf("bx_dbg_read_linear: physical address not available for linear 0x" FMT_ADDRX
"\n", laddr
);
1134 /* check for access across multiple pages */
1135 if (remainsInPage
< len
)
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");
1155 if (BX_CPU(dbg_cpu
)->get_segment_base(BX_SEG_REG_SS
) != 0) {
1156 dbg_printf("non-zero stack base\n");
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
++) {
1164 bx_phy_address paddr
;
1168 bx_bool paddr_valid
= BX_CPU(dbg_cpu
)->dbg_xlate_linear2phy(bp
, &paddr
);
1170 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu
), paddr
, 4, buf
)) {
1171 bp
= conv_4xBit8u_to_Bit32u(buf
);
1173 dbg_printf("(%d) Physical memory read error (BP)\n", i
);
1177 dbg_printf("(%d) Could not translate linear address (BP)\n", i
);
1182 paddr_valid
= BX_CPU(dbg_cpu
)->dbg_xlate_linear2phy(bp
+ 4, &paddr
);
1184 if (BX_MEM(0)->dbg_fetch_mem(BX_CPU(dbg_cpu
), paddr
, 4, buf
)) {
1185 ip
= conv_4xBit8u_to_Bit32u(buf
);
1187 dbg_printf("(%d) Physical memory read error (IP)\n", i
);
1191 dbg_printf("(%d) Could not translate linear address (IP)\n", i
);
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
++) {
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
);
1210 dbg_printf("\\%d", buf
);
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
);
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
);
1237 dbg_printf("linear page 0x" FMT_ADDRX
" maps to physical page 0x" FMT_PHY_ADDRX
"\n", laddr
, paddr
);
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
)
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");
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");
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");
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");
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");
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");
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")) {
1309 bx_dbg
.keyboard
= 1;
1317 bx_dbg
.interrupts
= 1;
1318 bx_dbg
.exceptions
= 1;
1321 bx_dbg
.debugger
= 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");
1327 } else if(!strcmp(arg
,"dbg-none")) {
1329 bx_dbg
.keyboard
= 0;
1337 bx_dbg
.interrupts
= 0;
1338 bx_dbg
.exceptions
= 0;
1341 bx_dbg
.debugger
= 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");
1347 } else if(!strcmp(arg
,"vga")){
1351 dbg_printf("Unrecognized arg: %s (only 'mode', 'int', 'softint', 'extint', 'iret', 'call', 'off', 'dbg-all' and 'dbg-none' are valid)\n", arg
);
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");
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());
1380 print_tree(node
, 0);
1383 node
= SIM
->get_param(param
, dbg_cpu_list
);
1385 print_tree(node
, 0);
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
);
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
);
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
);
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
);
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");
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
));
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;
1470 void bx_dbg_print_stack_command(unsigned nwords
)
1472 bx_address linear_sp
;
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
);
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;
1494 linear_sp
= BX_CPU(dbg_cpu
)->get_reg16(BX_16BIT_REG_SP
);
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
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
));
1516 dbg_printf(" | STACK 0x%08x [0x%08x]\n",
1517 (unsigned) linear_sp
, (unsigned) conv_4xBit8u_to_Bit32u(buf
));
1520 dbg_printf(" | STACK 0x%04x [0x%04x]\n",
1521 (unsigned) linear_sp
, (unsigned) conv_4xBit8u_to_Bit32u(buf
));
1529 void bx_dbg_watch(int type
, bx_phy_address address
)
1532 // print watch point info
1533 for (unsigned i
= 0; i
< num_read_watchpoints
; i
++) {
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));
1539 dbg_printf("rd 0x"FMT_PHY_ADDRX
" (read error)\n", read_watchpoint
[i
]);
1541 for (unsigned i
= 0; i
< num_write_watchpoints
; i
++) {
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));
1547 dbg_printf("wr 0x"FMT_PHY_ADDRX
" (read error)\n", write_watchpoint
[i
]);
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
);
1555 read_watchpoint
[num_read_watchpoints
++] = address
;
1556 dbg_printf("read watchpoint at 0x" FMT_PHY_ADDRX
" inserted\n", address
);
1559 if (num_write_watchpoints
== BX_DBG_MAX_WATCHPONTS
) {
1560 dbg_printf("Too many write watchpoints (%d)\n", BX_DBG_MAX_WATCHPONTS
);
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) {
1573 num_read_watchpoints
= num_write_watchpoints
= 0;
1574 dbg_printf("All watchpoints removed\n");
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
--;
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
--;
1603 void bx_dbg_continue_command(void)
1607 // continue executing, until a guard found
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);
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;
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
)) {
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.
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
);
1674 sim_running
->set(0);
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
))
1688 void bx_dbg_stepN_command(Bit32u count
)
1691 dbg_printf("Error: stepN: count=0\n");
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
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
))
1720 // when (BX_SMP_PROCESSORS == 1) ticks are handled inside the cpu loop
1721 if (BX_SMP_PROCESSORS
> 1) BX_TICK1();
1725 BX_INSTR_DEBUG_PROMPT();
1726 bx_dbg_print_guard_results();
1729 void bx_dbg_disassemble_current(int which_cpu
, int print_time
)
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
);
1740 bx_bool phy_valid
= BX_CPU(which_cpu
)->dbg_xlate_linear2phy(BX_CPU(which_cpu
)->guard_found
.laddr
, &phy
);
1742 dbg_printf("(%u).[" FMT_LL
"d] ??? (physical address not available)\n", which_cpu
, bx_pc_system
.time_ticks());
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
1757 if(BX_CPU(dbg_cpu
)->trace_reg
)
1758 bx_dbg_info_registers_command(BX_INFO_GENERAL_PURPOSE_REGS
);
1761 dbg_printf("(%u).[" FMT_LL
"d] ", which_cpu
, bx_pc_system
.time_ticks());
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
]);
1788 void bx_dbg_print_guard_results(void)
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
);
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",
1811 bx_guard
.iaddr
.lin
[i
].bpoint_id
,
1812 BX_CPU(cpu
)->guard_found
.laddr
);
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",
1820 bx_guard
.iaddr
.phy
[i
].bpoint_id
,
1821 BX_CPU(cpu
)->guard_found
.laddr
);
1824 switch(BX_CPU(cpu
)->stop_reason
) {
1825 case STOP_NO_REASON
:
1826 case STOP_CPU_HALTED
:
1828 case STOP_TIME_BREAK_POINT
:
1829 dbg_printf("(%u) Caught time breakpoint\n", cpu
);
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
);
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
);
1837 case STOP_MAGIC_BREAK_POINT
:
1838 dbg_printf("(%u) Magic breakpoint\n", cpu
);
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()));
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
) {
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
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
);
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
;
1871 bx_guard
.guard_for
&= ~BX_DBG_GUARD_IADDR_VIR
;
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
;
1878 bx_guard
.guard_for
&= ~BX_DBG_GUARD_IADDR_LIN
;
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
;
1885 bx_guard
.guard_for
&= ~BX_DBG_GUARD_IADDR_PHY
;
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
))
1896 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1897 if (bx_dbg_en_dis_lbreak(handle
, enable
))
1901 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1902 if (bx_dbg_en_dis_pbreak(handle
, enable
))
1906 dbg_printf("Error: breakpoint %u not found.\n", handle
);
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
;
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
;
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
;
1955 void bx_dbg_del_breakpoint_command(unsigned handle
)
1957 #if (BX_DBG_MAX_VIR_BPOINTS > 0)
1958 if (bx_dbg_del_vbreak(handle
))
1962 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
1963 if (bx_dbg_del_lbreak(handle
))
1967 #if (BX_DBG_MAX_PHY_BPOINTS > 0)
1968 if (bx_dbg_del_pbreak(handle
))
1972 dbg_printf("Error: breakpoint %u not found.\n", handle
);
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
--;
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
--;
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
--;
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");
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");
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
;
2057 dbg_printf("Error: virtual breakpoint support not compiled in.\n");
2058 dbg_printf("Error: make sure BX_DBG_MAX_VIR_BPOINTS > 0\n");
2063 int bx_dbg_lbreakpoint_command(BreakpointKind bk
, bx_address laddress
)
2065 #if (BX_DBG_MAX_LIN_BPOINTS > 0)
2067 dbg_printf("Error: lbreak of this kind not implemented yet.\n");
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");
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
;
2086 dbg_printf("Error: linear breakpoint support not compiled in.\n");
2087 dbg_printf("Error: make sure BX_DBG_MAX_LIN_BPOINTS > 0\n");
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");
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");
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
;
2114 dbg_printf("Error: physical breakpoint support not compiled in.\n");
2115 dbg_printf("Error: make sure BX_DBG_MAX_PHY_BPOINTS > 0\n");
2120 void bx_dbg_info_bpoints_command(void)
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
);
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
);
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
);
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");
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")) {
2184 dbg_printf("Error: take what n=0.\n");
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");
2206 dbg_printf("Error: Take '%s' not understood.\n", what
);
2210 static void bx_print_char(Bit8u ch
)
2213 dbg_printf(" \\%d ", ch
);
2214 else if (isprint(ch
))
2215 dbg_printf(" %c ", ch
);
2217 dbg_printf(" \\x%02X", ch
);
2220 void dbg_printf_binary(char *format
, Bit32u data
, int bits
)
2225 for (b
= 1 << (bits
- 1); b
; b
>>= 1)
2226 num
[len
++] = (data
& b
) ? '1' : '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;
2241 unsigned columns
, per_line
, offset
;
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) {
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
;
2266 dbg_printf("dbg_examine: format NULL\n");
2270 if (strlen(format
) < 2) {
2271 dbg_printf("dbg_examine: invalid format passed.\n");
2275 if (format
[0] != '/') {
2276 dbg_printf("dbg_examine: '/' is not first char of format.\n");
2285 while ((ch
>='0') && (ch
<='9')) {
2287 repeat_count
= 10*repeat_count
+ (ch
-'0');
2293 // if no count given, use default
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");
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
]) {
2309 case 'd': // signed decimal
2310 case 'u': // unsigned decimal
2314 case 's': // null terminated string
2315 case 'i': // machine instruction
2316 display_format
= ch
;
2320 case 'h': // halfwords (two bytes)
2321 case 'w': // words (4 bytes)
2322 case 'g': // giant words (8 bytes)
2326 case 'm': // memory dump
2331 dbg_printf("dbg_examine: invalid format passed. \'%c\'\n", ch
);
2338 if ((display_format
== 'i') || (display_format
== 's')) {
2339 dbg_printf("error: dbg_examine: 'i' and 's' formats not supported.\n");
2343 if (unit_size
== 'g') {
2344 dbg_printf("error: dbg_examine: 'g' (8-byte) unit size not supported.\n");
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
;
2359 if (display_format
== 'c') {
2360 // Display character dump in lines of 64 characters
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')
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
2393 dbg_printf("0x" FMT_ADDRX
":", addr
);
2395 dbg_printf("0x" FMT_ADDRX
" <bogus+%8u>:", addr
, offset
);
2399 /* Put a space in the middle of dump, for readability */
2400 if ((columns
- 1) == per_line
/ 2
2401 && memory_dump
&& display_format
!= 'c')
2405 if (! bx_dbg_read_linear(dbg_cpu
, addr
, data_size
, databuf
)) return;
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
) {
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;
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;
2440 #ifdef BX_LITTLE_ENDIAN
2441 data16
= * (Bit16u
*) databuf
;
2443 data16
= (databuf
[1]<<8) | databuf
[0];
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;
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;
2461 bx_print_char(data16
>>8);
2462 bx_print_char(data16
& 0xff);
2468 #ifdef BX_LITTLE_ENDIAN
2469 data32
= * (Bit32u
*) databuf
;
2471 data32
= (databuf
[3]<<24) | (databuf
[2]<<16) |
2472 (databuf
[1]<<8) | databuf
[0];
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;
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;
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));
2500 bx_debugger
.default_addr
= addr
;
2502 offset
+= data_size
;
2507 void bx_dbg_setpmem_command(bx_phy_address paddr
, unsigned len
, Bit32u val
)
2513 buf
[0] = (Bit8u
) val
;
2516 buf
[0] = val
& 0xff; val
>>= 8;
2517 buf
[1] = val
& 0xff;
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;
2526 dbg_printf("Error: setpmem: bad length value = %u\n", len
);
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
);
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());
2575 else if (!strcmp(symbol
, "synchronous_dma")) {
2576 bx_guard
.async
.dma
= !val
;
2579 else if (!strcmp(symbol
, "synchronous_irq")) {
2580 bx_guard
.async
.irq
= !val
;
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
;
2591 else if (!strcmp(symbol
, "auto_disassemble")) {
2592 bx_dbg_set_auto_disassemble(val
!= 0);
2596 dbg_printf("Error: set: unrecognized symbol.\n");
2601 dbg_printf("Error: could not set register '%s'.\n", symbol
);
2605 void bx_dbg_query_command(const char *what
)
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");
2619 dbg_printf("pending none\n");
2621 dbg_printf("done\n");
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");
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
;
2659 // format always begins with '/' (checked in lexer)
2660 // so we won't bother checking it here second time.
2661 numlines
= atoi(format
+ 1);
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
)
2671 if (BX_CPU(dbg_cpu
)->get_cpu_mode() == BX_MODE_LONG_64
)
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
]);
2694 } while ((from
< to
) && numlines
> 0);
2697 void bx_dbg_instrument_command(const char *comm
)
2699 #if BX_INSTRUMENTATION
2700 if (!strcmp(comm
, "start")) {
2703 else if (!strcmp(comm
, "stop")) {
2706 else if (!strcmp(comm
, "reset")) {
2707 BX_INSTR_RESET(dbg_cpu
);
2709 else if (!strcmp(comm
, "print")) {
2713 dbg_printf("Error: command 'instrument %s' not recognized\n", comm
);
2719 dbg_printf("Error: instrumentation not enabled.\n");
2723 void bx_dbg_doit_command(unsigned n
)
2725 // generic command to add temporary hacks to
2726 // for debugging purposes
2729 bx_dbg
.interrupts
= n
;
2730 bx_dbg
.exceptions
= n
;
2733 void bx_dbg_crc_command(bx_phy_address addr1
, bx_phy_address addr2
)
2737 if (addr1
>= addr2
) {
2738 dbg_printf("Error: crc32: invalid range\n");
2742 if (!BX_MEM(0)->dbg_crc32(addr1
, addr2
, &crc1
)) {
2743 dbg_printf("Error: could not crc32 memory\n");
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
++) {
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;
2778 unsigned present
= (hi
>> 15) & 0x01;
2779 unsigned avl
= (hi
>> 20) & 0x01;
2780 unsigned base_is_jump_addr
;
2782 // either a code or a data segment. bit 11 (type file MSB) then says
2783 // 0=data segment, 1=code seg
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);
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" : "");
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
);
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
);
2819 // 32-bit trap gate, target=0010:c0108ec4, DPL=0, present=1
2820 // code segment, base=0000:00cfffff, length=0xffff
2822 // either a code or a data segment. bit 11 (type file MSB) then says
2823 // 0=data segment, 1=code seg
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" : "",
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" : "");
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
);
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
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
);
2859 case BX_SYS_SEGMENT_LDT
:
2860 // it's an LDT. not much to print.
2863 // task, int, trap, or call gate.
2864 dbg_printf("target=0x%04x:0x%08x, DPL=%d", segment
, offset
, dpl
);
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
);
2877 if (to
== (unsigned) EMPTY_ARG
) {
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");
2886 unsigned temp
= from
;
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
++) {
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);
2900 dbg_printf("error: IDTR+8*%d points to invalid linear address 0x" FMT_ADDRX
"\n",
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
);
2914 if (to
== (unsigned) EMPTY_ARG
) {
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");
2923 unsigned temp
= from
;
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
++) {
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);
2937 dbg_printf("error: GDTR+8*%d points to invalid linear address 0x" FMT_ADDRX
"\n",
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();
2952 if (to
== (unsigned) EMPTY_ARG
) {
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");
2961 unsigned temp
= from
;
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
++) {
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);
2975 dbg_printf("error: LDTR+8*%d points to invalid linear address 0x" FMT_ADDRX
"\n",
2980 dbg_printf("You can list individual entries with 'info ldt [NUM]' or groups with 'info ldt [NUM] [NUM]'\n");
2984 static const char* bx_dbg_ivt_desc(int 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;
3033 void bx_dbg_info_ivt_command(unsigned from
, unsigned to
)
3035 unsigned char buff
[4];
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
) {
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");
3054 unsigned temp
= from
;
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]);
3066 seg
= (buff
[3] << 8) | buff
[2];
3067 off
= (buff
[1] << 8) | buff
[0];
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");
3077 dbg_printf("cpu in protected mode, use info idt\n");
3080 static void bx_dbg_print_tss(Bit8u
*tss
, int len
)
3083 dbg_printf("Invalid tss length (limit must be greater then 103)\n");
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)
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
)
3137 DEV_ne2k_print_info(stderr
, page
, reg
, 0);
3139 dbg_printf("NE2000 support is not compiled in\n");
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()
3168 if (SIM
->get_param_bool(BXPN_I440FX_SUPPORT
)->get()) {
3169 DEV_pci_print_i440fx_state();
3172 dbg_printf("PCI support is disabled in .bochsrc\n");
3175 dbg_printf("PCI support is not compiled in\n");
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(),
3206 (op
==BX_READ
) ? "read" : "write",
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(),
3218 (op
==BX_READ
) ? "read" : "write",
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
);
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
);
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
);
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)
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
)
3280 else if (what
!= last_what
)
3282 else if (addr
!= (last_addr
+ last_len
))
3287 // now store current values for next iteration
3293 if (!first_iteration
) // need return from previous line
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
);
3304 // *no* need to output the event header
3305 dbg_printf(" 0x%x", val
);
3308 if (bx_dbg_batch_dma
.Qsize
)
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
3322 if (! BX_CPU(dbg_cpu
)->cr0
.get_PG()) {
3323 printf("paging off\n");
3327 printf("cr3: 0x"FMT_PHY_ADDRX
"\n", BX_CPU(dbg_cpu
)->cr3
);
3335 valid
= BX_CPU(dbg_cpu
)->dbg_xlate_linear2phy(lin
, &phy
);
3337 if((lin
- start_lin
) != (phy
- start_phy
)) {
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
));
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
));
3352 if(lin
== 0xfffff000) break;
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
);
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
);
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
);
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
);
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
);
3428 dbg_printf("Unknown 64B register [%d] !!!\n", reg
);
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
);
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
);
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
);
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
);
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
);
3471 dbg_printf("Unknown 64B register [%d] !!!\n", reg
);
3474 Bit16u
bx_dbg_get_selector_value(unsigned int seg_no
)
3479 dbg_printf("Error: seg_no out of bounds\n");
3482 BX_CPU(dbg_cpu
)->dbg_get_sreg(&sreg
, seg_no
);
3484 dbg_printf("Error: segment valid bit cleared\n");
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
)
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");
3520 /* parse fields in selector */
3521 BX_CPU(dbg_cpu
)->parse_selector(sel
, &selector
);
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);
3530 desc_base
= BX_CPU(dbg_cpu
)->ldtr
.cache
.u
.system
.base
;
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);
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
);
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
);
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
);
3558 /* #NP(selector) if descriptor is not present */
3559 if (descriptor
.p
==0) {
3560 dbg_printf("ERROR: descriptor %04x not present!\n", sel
);
3564 Bit32u lowaddr
, highaddr
;
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;
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
;
3584 laddr
= sel
* 16 + ofs
;
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
))
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
;
3663 bx_dbg_stepN_command(1);
3665 // jmp absolute indirect
3672 bx_dbg_stepN_command (1);
3677 // calls, ints, loops and so on
3678 int BpId
= bx_dbg_lbreakpoint_command(bkStepOver
, Laddr
+ insn
.ilen
);
3680 dbg_printf("bx_dbg_step_over_command:: Failed to set lbreakpoint !\n");
3684 bx_dbg_continue_command();
3686 if (bx_dbg_del_lbreak (BpId
))
3687 bx_dbg_breakpoint_changed();
3690 #endif /* if BX_DEBUGGER */