Add debug panel (#108)

This commit is contained in:
copy 2017-04-02 11:03:50 -05:00
parent a0258079a0
commit 9e4b2c5ace
5 changed files with 89 additions and 77 deletions

View file

@ -61,6 +61,11 @@
<td><input type="file" id="hd_image"><br></td>
</tr>
<tr>
<td>Multiboot kernel image</td>
<td><input type="file" id="multiboot_image"><br></td>
</tr>
<tr>
<td colspan="2"><hr></td>
</tr>
@ -233,6 +238,9 @@
</label>
</div>
<div id="debug_panel" style="display: none">
</div>
<br style="clear:both"><br>
<textarea readonly id="log" style="display:none"></textarea>

View file

@ -1264,9 +1264,20 @@
}
};
var cpu = emulator.v86.cpu;
$("debug_panel").style.display = "block";
setInterval(function()
{
$("debug_panel").textContent =
cpu.debug.get_regs_short().join("\n") + "\n"
+ cpu.debug.get_state();
}, 1000);
// helps debugging
window.emulator = emulator;
window.cpu = emulator.v86.cpu;
window.cpu = cpu;
window.dump_file = dump_file;
}
function onpopstate(e)

View file

@ -1427,8 +1427,9 @@ CPU.prototype.get_real_eip = function()
CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, error_code)
{
//dbg_log("int " + h(interrupt_nr, 2) + " (" + (is_software_int ? "soft" : "hard") + "ware)", LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("int " + h(interrupt_nr) + " start");
//this.debug.dump_regs_short();
CPU_LOG_VERBOSE && this.debug.dump_state("int " + h(interrupt_nr) + " start" +
" (" + (is_software_int ? "soft" : "hard") + "ware)");
CPU_LOG_VERBOSE && this.debug.dump_regs();
this.debug.debug_interrupt(interrupt_nr);
@ -1546,7 +1547,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er
// interrupt from vm86 mode
//dbg_log("Inter privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) + " trap=" + is_trap + " 16bit=" + is_16, LOG_CPU);
//this.debug.dump_regs_short();
//this.debug.dump_regs();
var tss_stack_addr = this.get_tss_stack_addr(info.dpl);
var new_esp = this.read32s(tss_stack_addr);
@ -1583,7 +1584,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er
if(old_flags & flag_vm)
{
//dbg_log("return from vm86 mode");
//this.debug.dump_regs_short();
//this.debug.dump_regs();
dbg_assert(info.dpl === 0, "switch to non-0 dpl from vm86 mode");
}
@ -1639,7 +1640,7 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er
//dbg_log("Intra privilege interrupt gate=" + h(selector, 4) + ":" + h(base >>> 0, 8) +
// " trap=" + is_trap + " 16bit=" + is_16 +
// " cpl=" + this.cpl + " dpl=" + info.dpl + " conforming=" + +info.dc_bit, LOG_CPU);
//this.debug.dump_regs_short();
//this.debug.dump_regs();
if(this.flags & flag_vm)
{
@ -1692,7 +1693,6 @@ CPU.prototype.call_interrupt_vector = function(interrupt_nr, is_software_int, er
this.switch_seg(reg_es, 0);
}
this.sreg[reg_cs] = selector & ~3 | this.cpl;
dbg_assert((this.sreg[reg_cs] & 3) === this.cpl);
@ -1755,7 +1755,7 @@ CPU.prototype.iret = function(is_16)
{
//dbg_log("iret is_16=" + is_16, LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("iret" + (is_16 ? "16" : "32") + " start");
//this.debug.dump_regs_short();
//this.debug.dump_regs();
if(this.vm86_mode() && this.getiopl() < 3)
{
@ -1862,7 +1862,7 @@ CPU.prototype.iret = function(is_16)
//dbg_log("iret32 to:", LOG_CPU);
CPU_LOG_VERBOSE && this.debug.dump_state("iret end");
//this.debug.dump_regs_short();
//this.debug.dump_regs();
return;
}
@ -2164,6 +2164,7 @@ CPU.prototype.far_return = function(eip, selector, stack_adjust)
this.segment_offsets[reg_cs] = info.base;
this.sreg[reg_cs] = selector;
dbg_assert((selector & 3) === this.cpl);
this.instruction_pointer = this.get_seg(reg_cs) + eip | 0;
@ -2687,7 +2688,7 @@ CPU.prototype.raise_exception = function(interrupt_nr)
// // show interesting exceptions
// dbg_log("Exception " + h(interrupt_nr) + " at " + h(this.previous_ip >>> 0, 8) + " (cs=" + h(this.sreg[reg_cs], 4) + ")", LOG_CPU);
// dbg_trace(LOG_CPU);
// this.debug.dump_regs_short();
// this.debug.dump_regs();
// this.debug.dump_state();
//}
@ -2703,7 +2704,7 @@ CPU.prototype.raise_exception_with_code = function(interrupt_nr, error_code)
//{
// dbg_log("Exception " + h(interrupt_nr) + " err=" + h(error_code) + " at " + h(this.previous_ip >>> 0, 8) + " (cs=" + h(this.sreg[reg_cs], 4) + ")", LOG_CPU);
// dbg_trace(LOG_CPU);
// this.debug.dump_regs_short();
// this.debug.dump_regs();
//}
this.call_interrupt_vector(interrupt_nr, false, error_code);
@ -3487,7 +3488,7 @@ CPU.prototype.switch_seg = function(reg, selector)
) {
dbg_log("#GP for loading invalid in seg " + reg + " sel=" + h(selector, 4), LOG_CPU);
this.debug.dump_state();
this.debug.dump_regs_short();
this.debug.dump_regs();
dbg_trace(LOG_CPU);
this.trigger_gp(selector & ~3);
}

View file

@ -67,10 +67,11 @@ CPU.prototype.debug_init = function()
}
};
debug.dump_regs = dump_regs;
debug.get_regs_short = get_regs_short;
debug.dump_regs = dump_regs_short;
debug.dump_instructions = dump_instructions;
debug.get_instructions = get_instructions;
debug.dump_regs_short = dump_regs_short;
debug.get_state = get_state;
debug.dump_state = dump_state;
debug.dump_stack = dump_stack;
@ -130,7 +131,6 @@ CPU.prototype.debug_init = function()
cpu.running = false;
var a = parseInt(prompt("input hex", ""), 16);
if(a) while(cpu.instruction_pointer != a) step();
dump_regs();
}
// http://ref.x86asm.net/x86reference.xml
@ -213,12 +213,11 @@ CPU.prototype.debug_init = function()
}
}
function dump_state(where)
function get_state(where)
{
if(!DEBUG) return;
var mode = cpu.protected_mode ? "prot" : "real";
var vm = (cpu.flags & flag_vm) ? 1 : 0;
var mode = cpu.protected_mode ? vm ? "vm86" : "prot" : "real";
var flags = cpu.get_eflags();
var iopl = cpu.getiopl();
var cpl = cpu.cpl;
var cs_eip = h(cpu.sreg[reg_cs], 4) + ":" + h(cpu.get_real_eip() >>> 0, 8);
@ -226,19 +225,52 @@ CPU.prototype.debug_init = function()
var op_size = cpu.is_32 ? "32" : "16";
var if_ = (cpu.flags & flag_interrupt) ? 1 : 0;
dbg_log("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging) + " vm=" + vm +
var flag_names = {
[flag_carry]: "c",
[flag_parity]: "p",
[flag_adjust]: "a",
[flag_zero]: "z",
[flag_sign]: "s",
[flag_trap]: "t",
[flag_interrupt]: "i",
[flag_direction]: "d",
[flag_overflow]: "o",
};
var flag_string = "";
for(var i = 0; i < 16; i++)
{
if(flag_names[1 << i])
{
if(flags & 1 << i)
{
flag_string += flag_names[1 << i];
}
else
{
flag_string += " ";
}
}
}
return ("mode=" + mode + "/" + op_size + " paging=" + (+cpu.paging) +
" iopl=" + iopl + " cpl=" + cpl + " if=" + if_ + " cs:eip=" + cs_eip +
" cs_off=" + h(cpu.get_seg(reg_cs) >>> 0, 8) +
" flgs=" + h(cpu.get_eflags() >>> 0) +
" flgs=" + h(cpu.get_eflags() >>> 0, 6) + " (" + flag_string + ")" +
" ss:esp=" + ss_esp +
" ssize=" + (+cpu.stack_size_32) +
(where ? " in " + where : ""), LOG_CPU);
(where ? " in " + where : ""));
}
function dump_regs_short()
function dump_state(where)
{
if(!DEBUG) return;
dbg_log(get_state(where), LOG_CPU);
}
function get_regs_short()
{
var
r32 = { "eax": reg_eax, "ecx": reg_ecx, "edx": reg_edx, "ebx": reg_ebx,
"esp": reg_esp, "ebp": reg_ebp, "esi": reg_esi, "edi": reg_edi },
@ -255,67 +287,23 @@ CPU.prototype.debug_init = function()
line2 += r32_names[i+4] + "=" + h(cpu.reg32[r32[r32_names[i+4]]], 8) + " ";
}
line1 += " eip=" + h(cpu.get_real_eip() >>> 0, 8);
line2 += " flg=" + h(cpu.get_eflags(), 8);
//line1 += " eip=" + h(cpu.get_real_eip() >>> 0, 8);
//line2 += " flg=" + h(cpu.get_eflags(), 8);
line1 += " ds=" + h(cpu.sreg[reg_ds], 4) + " es=" + h(cpu.sreg[reg_es], 4) + " fs=" + h(cpu.sreg[reg_fs], 4);
line2 += " gs=" + h(cpu.sreg[reg_gs], 4) + " cs=" + h(cpu.sreg[reg_cs], 4) + " ss=" + h(cpu.sreg[reg_ss], 4);
line1 += " ds=" + h(cpu.sreg[reg_ds], 4) + " es=" + h(cpu.sreg[reg_es], 4) + " fs=" + h(cpu.sreg[reg_fs], 4);
line2 += " gs=" + h(cpu.sreg[reg_gs], 4) + " cs=" + h(cpu.sreg[reg_cs], 4) + " ss=" + h(cpu.sreg[reg_ss], 4);
dbg_log(line1, LOG_CPU);
dbg_log(line2, LOG_CPU);
return [line1, line2];
}
function dump_regs()
function dump_regs_short()
{
if(!DEBUG) return;
var
r32 = { "eax": reg_eax, "ecx": reg_ecx, "edx": reg_edx, "ebx": reg_ebx,
"esp": reg_esp, "ebp": reg_ebp, "esi": reg_esi, "edi": reg_edi },
s = { "cs": reg_cs, "ds": reg_ds, "es": reg_es,
"fs": reg_fs, "gs": reg_gs, "ss": reg_ss },
out;
dbg_log("----- DUMP (ip = " + h(cpu.instruction_pointer >>> 0) + ") ----------")
dbg_log("protected mode: " + cpu.protected_mode);
for(var i in r32)
{
dbg_log(i + " = " + h(cpu.reg32[r32[i]], 8));
}
dbg_log("eip = " + h(cpu.get_real_eip() >>> 0, 8));
for(i in s)
{
dbg_log(i + " = " + h(cpu.sreg[s[i]], 4));
}
out = "";
var flg = { "cf": cpu.getcf, "pf": cpu.getpf, "zf": cpu.getzf, "sf": cpu.getsf,
"of": cpu.getof, "df": flag_direction, "if": flag_interrupt };
for(var i in flg)
{
if(+flg[i])
{
out += i + "=" + Number(!!(cpu.flags & flg[i])) + " | ";
}
else
{
out += i + "=" + Number(!!flg[i]()) + " | ";
}
}
out += "iopl=" + cpu.getiopl();
dbg_log(out);
//dbg_log("last operation: " + h(last_op1 | 0) + ", " + h(last_op2 | 0) + " = " +
//h(last_result | 0) + " (" + last_op_size + " bit)")
var lines = get_regs_short();
dbg_log(lines[0], LOG_CPU);
dbg_log(lines[1], LOG_CPU);
}
function get_instructions()

View file

@ -1,4 +1,4 @@
#log, #runtime_infos, #serial, #filesystem_panel {
#log, #runtime_infos, #serial, #filesystem_panel, #debug_panel {
font-family: DejaVu Sans Mono, monospace;
font-size: 13px;
border: 1px solid #333;
@ -17,6 +17,10 @@
height: 100px;
width: 550px;
}
#debug_panel {
white-space: pre;
float: left;
}
#serial {
margin: 0px;
}