SandboXP

Форк
0
/
debug.js 
662 строки · 18.4 Кб
1
"use strict";
2

3
CPU.prototype.debug_init = function()
4
{
5
    var cpu = this;
6
    var debug = {};
7
    this.debug = debug;
8

9
    debug.init = function()
10
    {
11
        if(!DEBUG) return;
12

13
        if(cpu.io)
14
        {
15
            // write seabios debug output to console
16
            var seabios_debug = "";
17

18
            cpu.io.register_write(0x402, this, handle); // seabios
19
            cpu.io.register_write(0x500, this, handle); // vgabios
20
        }
21

22
        function handle(out_byte)
23
        {
24
            if(out_byte === 10)
25
            {
26
                dbg_log(seabios_debug, LOG_BIOS);
27
                seabios_debug = "";
28
            }
29
            else
30
            {
31
                seabios_debug += String.fromCharCode(out_byte);
32
            }
33
        }
34
    };
35

36
    debug.get_regs_short = get_regs_short;
37
    debug.dump_regs = dump_regs_short;
38
    debug.get_state = get_state;
39
    debug.dump_state = dump_state;
40
    debug.dump_stack = dump_stack;
41

42
    debug.dump_page_structures = dump_page_structures;
43
    debug.dump_gdt_ldt = dump_gdt_ldt;
44
    debug.dump_idt = dump_idt;
45

46
    debug.get_memory_dump = get_memory_dump;
47
    debug.memory_hex_dump = memory_hex_dump;
48
    debug.used_memory_dump = used_memory_dump;
49

50
    function dump_stack(start, end)
51
    {
52
        if(!DEBUG) return;
53

54
        var esp = cpu.reg32[REG_ESP];
55
        dbg_log("========= STACK ==========");
56

57
        if(end >= start || end === undefined)
58
        {
59
            start = 5;
60
            end = -5;
61
        }
62

63
        for(var i = start; i > end; i--)
64
        {
65
            var line = "    ";
66

67
            if(!i) line = "=>  ";
68

69
            line += h(i, 2) + " | ";
70

71
            dbg_log(line + h(esp + 4 * i, 8) + " | " + h(cpu.read32s(esp + 4 * i) >>> 0));
72
        }
73
    }
74

75
    function get_state(where)
76
    {
77
        if(!DEBUG) return;
78

79
        var mode = cpu.protected_mode[0] ? "prot" : "real";
80
        var vm = (cpu.flags[0] & FLAG_VM) ? 1 : 0;
81
        var flags = cpu.get_eflags();
82
        var iopl = cpu.getiopl();
83
        var cpl = cpu.cpl[0];
84
        var cs_eip = h(cpu.sreg[REG_CS], 4) + ":" + h(cpu.get_real_eip() >>> 0, 8);
85
        var ss_esp = h(cpu.sreg[REG_SS], 4) + ":" + h(cpu.reg32[REG_ES] >>> 0, 8);
86
        var op_size = cpu.is_32[0] ? "32" : "16";
87
        var if_ = (cpu.flags[0] & FLAG_INTERRUPT) ? 1 : 0;
88

89
        var flag_names = {
90
            [FLAG_CARRY]: "c",
91
            [FLAG_PARITY]: "p",
92
            [FLAG_ADJUST]: "a",
93
            [FLAG_ZERO]: "z",
94
            [FLAG_SIGN]: "s",
95
            [FLAG_TRAP]: "t",
96
            [FLAG_INTERRUPT]: "i",
97
            [FLAG_DIRECTION]: "d",
98
            [FLAG_OVERFLOW]: "o",
99
        };
100
        var flag_string = "";
101

102
        for(var i = 0; i < 16; i++)
103
        {
104
            if(flag_names[1 << i])
105
            {
106
                if(flags & 1 << i)
107
                {
108
                    flag_string += flag_names[1 << i];
109
                }
110
                else
111
                {
112
                    flag_string += " ";
113
                }
114
            }
115
        }
116

117
        return ("mode=" + mode + "/" + op_size + " paging=" + (+((cpu.cr[0] & CR0_PG) !== 0)) +
118
                " pae=" + (+((cpu.cr[4] & CR4_PAE) !== 0)) +
119
                " iopl=" + iopl + " cpl=" + cpl + " if=" + if_ + " cs:eip=" + cs_eip +
120
                " cs_off=" + h(cpu.get_seg_cs() >>> 0, 8) +
121
                " flgs=" + h(cpu.get_eflags() >>> 0, 6) + " (" + flag_string + ")" +
122
                " ss:esp=" + ss_esp +
123
                " ssize=" + (+cpu.stack_size_32[0]) +
124
                (where ? " in " + where : ""));
125
    }
126

127
    function dump_state(where)
128
    {
129
        if(!DEBUG) return;
130

131
        dbg_log(get_state(where), LOG_CPU);
132
    }
133

134
    function get_regs_short()
135
    {
136
        var
137
            r32 = { "eax": REG_EAX, "ecx": REG_ECX, "edx": REG_EDX, "ebx": REG_EBX,
138
                    "esp": REG_ESP, "ebp": REG_EBP, "esi": REG_ESI, "edi": REG_EDI },
139
            r32_names = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"],
140
            s = { "cs": REG_CS, "ds": REG_DS, "es": REG_ES, "fs": REG_FS, "gs": REG_GS, "ss": REG_SS },
141
            line1 = "",
142
            line2 = "";
143

144

145

146
        for(var i = 0; i < 4; i++)
147
        {
148
            line1 += r32_names[i] + "="  + h(cpu.reg32[r32[r32_names[i]]] >>> 0, 8) + " ";
149
            line2 += r32_names[i+4] + "="  + h(cpu.reg32[r32[r32_names[i+4]]] >>> 0, 8) + " ";
150
        }
151

152
        //line1 += " eip=" + h(cpu.get_real_eip() >>> 0, 8);
153
        //line2 += " flg=" + h(cpu.get_eflags(), 8);
154

155
        line1 += "  ds=" + h(cpu.sreg[REG_DS], 4) + " es=" + h(cpu.sreg[REG_ES], 4) + " fs=" + h(cpu.sreg[REG_FS], 4);
156
        line2 += "  gs=" + h(cpu.sreg[REG_GS], 4) + " cs=" + h(cpu.sreg[REG_CS], 4) + " ss=" + h(cpu.sreg[REG_SS], 4);
157

158
        return [line1, line2];
159
    }
160

161
    function dump_regs_short()
162
    {
163
        if(!DEBUG) return;
164

165
        var lines = get_regs_short();
166

167
        dbg_log(lines[0], LOG_CPU);
168
        dbg_log(lines[1], LOG_CPU);
169
    }
170

171
    function dump_gdt_ldt()
172
    {
173
        if(!DEBUG) return;
174

175
        dbg_log("gdt: (len = " + h(cpu.gdtr_size[0]) + ")");
176
        dump_table(cpu.translate_address_system_read(cpu.gdtr_offset[0]), cpu.gdtr_size[0]);
177

178
        dbg_log("\nldt: (len = " + h(cpu.segment_limits[REG_LDTR]) + ")");
179
        dump_table(cpu.translate_address_system_read(cpu.segment_offsets[REG_LDTR]), cpu.segment_limits[REG_LDTR]);
180

181
        function dump_table(addr, size)
182
        {
183
            for(var i = 0; i < size; i += 8, addr += 8)
184
            {
185
                var base = cpu.read16(addr + 2) |
186
                        cpu.read8(addr + 4) << 16 |
187
                        cpu.read8(addr + 7) << 24,
188

189
                    limit = cpu.read16(addr) | (cpu.read8(addr + 6) & 0xF) << 16,
190
                    access = cpu.read8(addr + 5),
191
                    flags = cpu.read8(addr + 6) >> 4,
192
                    flags_str = "",
193
                    dpl = access >> 5 & 3;
194

195
                if(!(access & 128))
196
                {
197
                    // present bit not set
198
                    //continue;
199
                    flags_str += "NP ";
200
                }
201
                else
202
                {
203
                    flags_str += " P ";
204
                }
205

206
                if(access & 16)
207
                {
208
                    if(flags & 4)
209
                    {
210
                        flags_str += "32b ";
211
                    }
212
                    else
213
                    {
214
                        flags_str += "16b ";
215
                    }
216

217
                    if(access & 8)
218
                    {
219
                        // executable
220
                        flags_str += "X ";
221

222
                        if(access & 4)
223
                        {
224
                            flags_str += "C ";
225
                        }
226
                    }
227
                    else
228
                    {
229
                        // data
230
                        flags_str += "R ";
231
                    }
232

233
                    flags_str += "RW ";
234
                }
235
                else
236
                {
237
                    // system
238
                    flags_str += "sys: " + h(access & 15);
239
                }
240

241
                if(flags & 8)
242
                {
243
                    limit = limit << 12 | 0xFFF;
244
                }
245

246
                dbg_log(h(i & ~7, 4) + " " + h(base >>> 0, 8) + " (" + h(limit >>> 0, 8) + " bytes) " +
247
                        flags_str + ";  dpl = " + dpl + ", a = " + access.toString(2) +
248
                        ", f = " + flags.toString(2));
249
            }
250
        }
251
    }
252

253
    function dump_idt()
254
    {
255
        if(!DEBUG) return;
256

257
        for(var i = 0; i < cpu.idtr_size[0]; i += 8)
258
        {
259
            var addr = cpu.translate_address_system_read(cpu.idtr_offset[0] + i),
260
                base = cpu.read16(addr) | cpu.read16(addr + 6) << 16,
261
                selector = cpu.read16(addr + 2),
262
                type = cpu.read8(addr + 5),
263
                line,
264
                dpl = type >> 5 & 3;
265

266
            if((type & 31) === 5)
267
            {
268
                line = "task gate ";
269
            }
270
            else if((type & 31) === 14)
271
            {
272
                line = "intr gate ";
273
            }
274
            else if((type & 31) === 15)
275
            {
276
                line = "trap gate ";
277
            }
278
            else
279
            {
280
                line = "invalid   ";
281
            }
282

283

284
            if(type & 128)
285
            {
286
                line += " P";
287
            }
288
            else
289
            {
290
                // present bit not set
291
                //continue;
292
                line += "NP";
293
            }
294

295

296
            dbg_log(h(i >> 3, 4) + " " + h(base >>> 0, 8) + ", " +
297
                    h(selector, 4) + "; " + line + ";  dpl = " + dpl + ", t = " + type.toString(2));
298
        }
299
    }
300

301
    function load_page_entry(dword_entry, pae, is_directory)
302
    {
303
        if(!DEBUG) return;
304

305
        if(!(dword_entry & 1))
306
        {
307
            // present bit not set
308
            return false;
309
        }
310

311
        var size = (dword_entry & 128) === 128,
312
            address;
313

314
        if(size && !is_directory)
315
        {
316
            address = dword_entry & (pae ? 0xFFE00000 : 0xFFC00000);
317
        }
318
        else
319
        {
320
            address = dword_entry & 0xFFFFF000;
321
        }
322

323
        return {
324
            size: size,
325
            global: (dword_entry & 256) === 256,
326
            accessed: (dword_entry & 0x20) === 0x20,
327
            dirty: (dword_entry & 0x40) === 0x40,
328
            cache_disable : (dword_entry & 16) === 16,
329
            user : (dword_entry & 4) === 4,
330
            read_write : (dword_entry & 2) === 2,
331
            address : address >>> 0
332
        };
333
    }
334

335
    function dump_page_structures() {
336
        var pae = !!(cpu.cr[4] & CR4_PAE);
337
        if (pae)
338
        {
339
            dbg_log("PAE enabled");
340

341
            for (var i = 0; i < 4; i++) {
342
                var addr = cpu.cr[3] + 8 * i;
343
                var dword = cpu.read32s(addr);
344
                if (dword & 1)
345
                {
346
                    dump_page_directory(dword & 0xFFFFF000, true, i << 30);
347
                }
348
            }
349
        }
350
        else
351
        {
352
            dbg_log("PAE disabled");
353
            dump_page_directory(cpu.cr[3], false, 0);
354
        }
355
    }
356

357
    /* NOTE: PAE entries are 64-bits, we ignore the high half here. */
358
    function dump_page_directory(pd_addr, pae, start)
359
    {
360
        if(!DEBUG) return;
361

362
        var n = pae ? 512 : 1024;
363
        var entry_size = pae ? 8 : 4;
364
        var pd_shift = pae ? 21 : 22;
365

366
        for(var i = 0; i < n; i++)
367
        {
368
            var addr = pd_addr + i * entry_size,
369
                dword = cpu.read32s(addr),
370
                entry = load_page_entry(dword, pae, true);
371

372
            if(!entry)
373
            {
374
                continue;
375
            }
376

377
            var flags = "";
378

379
            flags += entry.size ? "S " : "  ";
380
            flags += entry.accessed ? "A " : "  ";
381
            flags += entry.cache_disable ? "Cd " : "  ";
382
            flags += entry.user ? "U " : "  ";
383
            flags += entry.read_write ? "Rw " : "   ";
384

385
            if(entry.size)
386
            {
387
                dbg_log("=== " + h(start + (i << pd_shift) >>> 0, 8) + " -> " +
388
                    h(entry.address >>> 0, 8) + " | " + flags);
389
                continue;
390
            }
391
            else
392
            {
393
                dbg_log("=== " + h(start + (i << pd_shift) >>> 0, 8) + " | " + flags);
394
            }
395

396
            for(var j = 0; j < n; j++)
397
            {
398
                var sub_addr = entry.address + j * entry_size;
399
                dword = cpu.read32s(sub_addr);
400

401
                var subentry = load_page_entry(dword, pae, false);
402

403
                if(subentry)
404
                {
405
                    flags = "";
406

407
                    flags += subentry.cache_disable ? "Cd " : "   ";
408
                    flags += subentry.user ? "U " : "  ";
409
                    flags += subentry.read_write ? "Rw " : "   ";
410
                    flags += subentry.global ? "G " : "  ";
411
                    flags += subentry.accessed ? "A " : "  ";
412
                    flags += subentry.dirty ? "Di " : "   ";
413

414
                    dbg_log("# " + h(start + (i << pd_shift | j << 12) >>> 0, 8) + " -> " +
415
                            h(subentry.address, 8) + " | " + flags + "        (at " + h(sub_addr, 8) + ")");
416
                }
417
            }
418
        }
419
    }
420

421

422
    function get_memory_dump(start, count)
423
    {
424
        if(!DEBUG) return;
425

426
        if(start === undefined)
427
        {
428
            start = 0;
429
            count = cpu.memory_size[0];
430
        }
431
        else if(count === undefined)
432
        {
433
            count = start;
434
            start = 0;
435
        }
436

437
        return cpu.mem8.slice(start, start + count).buffer;
438
    }
439

440

441
    function memory_hex_dump(addr, length)
442
    {
443
        if(!DEBUG) return;
444

445
        length = length || 4 * 0x10;
446
        var line, byt;
447

448
        for(var i = 0; i < length >> 4; i++)
449
        {
450
            line = h(addr + (i << 4), 5) + "   ";
451

452
            for(var j = 0; j < 0x10; j++)
453
            {
454
                byt = cpu.read8(addr + (i << 4) + j);
455
                line += h(byt, 2) + " ";
456
            }
457

458
            line += "  ";
459

460
            for(j = 0; j < 0x10; j++)
461
            {
462
                byt = cpu.read8(addr + (i << 4) + j);
463
                line += (byt < 33 || byt > 126) ? "." : String.fromCharCode(byt);
464
            }
465

466
            dbg_log(line);
467
        }
468
    }
469

470
    function used_memory_dump()
471
    {
472
        if(!DEBUG) return;
473

474
        var width = 0x80,
475
            height = 0x10,
476
            block_size = cpu.memory_size[0] / width / height | 0,
477
            row;
478

479
        for(var i = 0; i < height; i++)
480
        {
481
            row = h(i * width * block_size, 8) + " | ";
482

483
            for(var j = 0; j < width; j++)
484
            {
485
                var used = cpu.mem32s[(i * width + j) * block_size] > 0;
486

487
                row += used ? "X" : " ";
488
            }
489

490
            dbg_log(row);
491
        }
492
    }
493

494

495
    debug.debug_interrupt = function(interrupt_nr)
496
    {
497
        //if(interrupt_nr === 0x20)
498
        //{
499
        //    //var vxd_device = cpu.safe_read16(cpu.instruction_pointer + 2);
500
        //    //var vxd_sub = cpu.safe_read16(cpu.instruction_pointer + 0);
501
        //    //var service = "";
502
        //    //if(vxd_device === 1)
503
        //    //{
504
        //    //    service = vxd_table1[vxd_sub];
505
        //    //}
506
        //    //dbg_log("vxd: " + h(vxd_device, 4) + " " + h(vxd_sub, 4) + " " + service);
507
        //}
508

509
        //if(interrupt_nr >= 0x21 && interrupt_nr < 0x30)
510
        //{
511
        //    dbg_log("dos: " + h(interrupt_nr, 2) + " ah=" + h(this.reg8[reg_ah], 2) + " ax=" + h(this.reg16[reg_ax], 4));
512
        //}
513

514
        //if(interrupt_nr === 0x13 && (this.reg8[reg_ah] | 1) === 0x43)
515
        //{
516
        //    this.debug.memory_hex_dump(this.get_seg(reg_ds) + this.reg16[reg_si], 0x18);
517
        //}
518

519
        //if(interrupt_nr == 0x10)
520
        //{
521
        //    dbg_log("int10 ax=" + h(this.reg16[reg_ax], 4) + " '" + String.fromCharCode(this.reg8[reg_al]) + "'");
522
        //    this.debug.dump_regs_short();
523
        //    if(this.reg8[reg_ah] == 0xe) vga.tt_write(this.reg8[reg_al]);
524
        //}
525

526
        //if(interrupt_nr === 0x13)
527
        //{
528
        //    this.debug.dump_regs_short();
529
        //}
530

531
        //if(interrupt_nr === 6)
532
        //{
533
        //    this.instruction_pointer += 2;
534
        //    dbg_log("BUG()", LOG_CPU);
535
        //    dbg_log("line=" + this.read_imm16() + " " +
536
        //            "file=" + this.read_string(this.translate_address_read(this.read_imm32s())), LOG_CPU);
537
        //    this.instruction_pointer -= 8;
538
        //    this.debug.dump_regs_short();
539
        //}
540

541
        //if(interrupt_nr === 0x80)
542
        //{
543
        //    dbg_log("linux syscall");
544
        //    this.debug.dump_regs_short();
545
        //}
546

547
        //if(interrupt_nr === 0x40)
548
        //{
549
        //    dbg_log("kolibri syscall");
550
        //    this.debug.dump_regs_short();
551
        //}
552
    };
553

554
    let cs;
555
    let capstone_decoder;
556

557
    debug.dump_code = function(is_32, buffer, start)
558
    {
559
        if(!capstone_decoder)
560
        {
561
            if(cs === undefined)
562
            {
563
                if(typeof require === "function")
564
                {
565
                    cs = require("./capstone-x86.min.js");
566
                }
567
                else
568
                {
569
                    cs = window.cs;
570
                }
571

572
                if(cs === undefined)
573
                {
574
                    dbg_log("Warning: Missing capstone library, disassembly not available");
575
                    return;
576
                }
577
            }
578

579
            capstone_decoder = [
580
                new cs.Capstone(cs.ARCH_X86, cs.MODE_16),
581
                new cs.Capstone(cs.ARCH_X86, cs.MODE_32),
582
            ];
583
        }
584

585
        try
586
        {
587
            const instructions = capstone_decoder[is_32].disasm(buffer, start);
588

589
            instructions.forEach(function (instr) {
590
                dbg_log(h(instr.address >>> 0) + ": " +
591
                    v86util.pads(instr.bytes.map(x => h(x, 2).slice(-2)).join(" "), 20) + " " +
592
                    instr.mnemonic + " " + instr.op_str);
593
            });
594
            dbg_log("");
595
        }
596
        catch(e)
597
        {
598
            dbg_log("Could not disassemble: " + Array.from(buffer).map(x => h(x, 2)).join(" "));
599
        }
600
    };
601

602
    function dump_file(ab, name)
603
    {
604
        var blob = new Blob([ab]);
605

606
        var a = document.createElement("a");
607
        a["download"] = name;
608
        a.href = window.URL.createObjectURL(blob);
609
        a.dataset["downloadurl"] = ["application/octet-stream", a["download"], a.href].join(":");
610

611
        a.click();
612
        window.URL.revokeObjectURL(a.src);
613
    }
614

615
    let wabt;
616

617
    debug.dump_wasm = function(buffer)
618
    {
619
        if(wabt === undefined)
620
        {
621
            if(typeof require === "function")
622
            {
623
                wabt = require("./libwabt.js");
624
            }
625
            else
626
            {
627
                wabt = new window.WabtModule;
628
            }
629

630
            if(wabt === undefined)
631
            {
632
                dbg_log("Warning: Missing libwabt, wasm dump not available");
633
                return;
634
            }
635
        }
636

637
        // Need to make a small copy otherwise libwabt goes nuts trying to copy
638
        // the whole underlying buffer
639
        buffer = buffer.slice();
640

641
        try
642
        {
643
            var module = wabt.readWasm(buffer, { readDebugNames: false });
644
            module.generateNames();
645
            module.applyNames();
646
            const result = module.toText({ foldExprs: true, inlineExport: true });
647
            dbg_log(result);
648
        }
649
        catch(e)
650
        {
651
            dump_file(buffer, "failed.wasm");
652
            console.log(e.toString());
653
        }
654
        finally
655
        {
656
            if(module)
657
            {
658
                module.destroy();
659
            }
660
        }
661
    };
662
};
663

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.