Add debug panel (#108)
This commit is contained in:
parent
a0258079a0
commit
9e4b2c5ace
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
23
src/cpu.js
23
src/cpu.js
|
@ -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);
|
||||
}
|
||||
|
|
116
src/debug.js
116
src/debug.js
|
@ -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()
|
||||
|
|
6
v86.css
6
v86.css
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue