|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
1.1.1.2 root 6:
7: //
8: // メモリダンプ/逆アセンブル
1.1 root 9: //
10:
11: #include "memdump.h"
1.1.1.2 root 12: #include "debugger_memory.h"
13: #include "debugger_private.h"
14: #include "hd64180disasm.h"
15: #include "m68030disasm.h"
16: #include "m88100disasm.h"
1.1.1.3 ! root 17: #include "mainbus.h"
1.1 root 18:
19: //
1.1.1.2 root 20: // メモリダンプ (基本クラス)
1.1 root 21: //
1.1.1.2 root 22:
23: // コンストラクタ
24: Memdump::Memdump(int objid_)
25: : inherited(objid_)
26: {
27: // ログは不要
28: ClearAlias();
29:
30: // 初期値
1.1.1.3 ! root 31: saddr = busaddr::Read | busaddr::S | busaddr::Physical;
1.1.1.2 root 32: SetFormat(Word);
33: }
34:
35: // コンストラクタ (メモリダンプ用にデバッガから呼ばれるほう)
36: Memdump::Memdump(DebuggerMD *md_)
37: : Memdump(OBJ_NONE) // 移譲
38: {
39: InitMD(md_);
40: }
41:
42: // コンストラクタ (逆アセンブル用にデバッガから呼ばれるほう)
43: Memdump::Memdump(DebuggerMD *md_, CPUArch asm_arch)
44: : Memdump(OBJ_NONE) // 移譲
1.1 root 45: {
1.1.1.2 root 46: InitMD(md_);
1.1 root 47:
1.1.1.2 root 48: // asm_arch を Format に変換してセット
49: Format fmt_;
50: switch (asm_arch) {
51: case CPUArch::M680x0:
52: fmt_ = M68030Disasm;
53: break;
54: case CPUArch::M88xx0:
55: fmt_ = M88100Disasm;
56: break;
57: case CPUArch::HD64180:
58: fmt_ = HD64180Disasm;
59: break;
60: default:
61: PANIC("corrupted asm_arch=%d", (int)asm_arch);
62: }
63: SetFormat(fmt_);
64: }
65:
66: // デストラクタ
67: Memdump::~Memdump()
68: {
69: }
1.1 root 70:
1.1.1.2 root 71: // md を初期化(代入)する。
72: void
73: Memdump::InitMD(DebuggerMD *md_)
74: {
75: md = md_;
76: bus = md->GetBus();
1.1 root 77: }
78:
1.1.1.3 ! root 79: // busaddr を設定する。
1.1.1.2 root 80: void
1.1.1.3 ! root 81: Memdump::SetAddr(busaddr saddr_)
1.1.1.2 root 82: {
1.1.1.3 ! root 83: saddr = saddr_;
! 84: MaskAddr();
1.1.1.2 root 85: }
86:
87: // アドレスを設定する。
88: void
89: Memdump::SetAddr(uint32 laddr_)
90: {
91: saddr.SetAddr(laddr_);
1.1.1.3 ! root 92: MaskAddr();
1.1.1.2 root 93: }
94:
1.1.1.3 ! root 95: // 今の表示形式での境界に揃える。
1.1.1.2 root 96: void
1.1.1.3 ! root 97: Memdump::MaskAddr()
1.1.1.2 root 98: {
1.1.1.3 ! root 99: saddr &= ~(GetStride() - 1);
1.1.1.2 root 100: }
101:
102: // アドレスをバイト単位で加算(減算)する。
103: void
104: Memdump::Offset(int bytes)
105: {
106: saddr += (uint32)bytes;
107: }
108:
109: // 表示フォーマットを設定する。
110: void
111: Memdump::SetFormat(Memdump::Format fmt_)
112: {
113: fmt = fmt_;
114:
115: line.reset();
116: fixed = 0;
117: inst_bytes = 0;
118:
119: switch (fmt) {
120: case Byte:
121: case Word:
122: case Long:
123: fixed = 16;
124: break;
125: case M68030PageShort:
126: case M88200Page:
127: fixed = 4;
128: break;
129: case M68030PageLong:
130: fixed = 8;
131: break;
132:
133: case M68030Disasm:
134: line.reset(new m680x0disasm());
135: inst_bytes = 2;
136: break;
137: case M88100Disasm:
138: line.reset(new m88100disasm());
139: inst_bytes = 4;
140: fixed = 4; // 固定長フォーマットでもある
141: break;
142: case HD64180Disasm:
143: line.reset(new hd64180disasm());
144: inst_bytes = 1;
145: break;
146: }
147:
148: // 表示形式を切り替えたことによってアドレスに端数が出るのを防ぐ
1.1.1.3 ! root 149: MaskAddr();
1.1.1.2 root 150: }
151:
152: // 物理メモリ paddr 以降の内容を越権的に読み出す。bytes は 1, 2, 4 を想定。
153: // バスエラーなら負数を返す。
154: uint64
155: Memdump::Peek(uint32 paddr, int bytes) const
156: {
1.1.1.3 ! root 157: uint32 data = 0;
1.1.1.2 root 158:
159: while (--bytes >= 0) {
1.1.1.3 ! root 160: busdata bd = bus->Peek8(paddr++);
! 161: if (__predict_false(bd.IsBusErr())) {
! 162: return bd;
! 163: }
! 164: data = (data << 8) | bd.Data();
1.1.1.2 root 165: }
166: return data;
167: }
168:
169: // 物理メモリ paddr 以降の内容を越権的に書き換える。
170: // bytes は 1, 2, 4 を想定しており、paddr はこれに整列しているはず。
1.1.1.3 ! root 171: // バスエラーが起きたらその場で処理を中止して false を返す。
! 172: bool
1.1.1.2 root 173: Memdump::Poke(uint32 paddr, uint32 data, int bytes)
174: {
175: while (--bytes >= 0) {
176: uint32 d = data >> (bytes * 8);
1.1.1.3 ! root 177: if (bus->Poke8(paddr++, d & 0xff) == false) {
! 178: return false;
1.1.1.2 root 179: }
180: }
181:
1.1.1.3 ! root 182: return true;
1.1.1.2 root 183: }
184:
185: // この paddr が Poke() 可能なら true を返す。
186: bool
187: Memdump::CanPoke(uint32 paddr) const
188: {
1.1.1.3 ! root 189: return bus->Poke8(paddr, -1);
1.1.1.2 root 190: }
191:
192: // コンソールに出力。
193: // 出力後 saddr は更新されている。
194: void
195: Memdump::Print(FILE *cons, int row)
196: {
1.1.1.3 ! root 197: DebuggerMemoryStream mem(md, saddr);
1.1.1.2 root 198:
199: for (int y = 0; y < row; y++) {
200: std::string addrbuf;
201: bool accessible;
202:
203: accessible = mem.FormatAddr(addrbuf);
204: if (accessible == false) {
205: fprintf(cons, "%s\n", addrbuf.c_str());
206: mem.Offset(GetStride());
207: continue;
208: }
209: // addrbuf は "VA:" もしくは "VA:PA:" の形式で返ってくる。
210: // 本来は、どちらの形式であってもダンプは同じ桁から始めたいが、
211: // バイト表示では 80桁に収まらない。
212: // VA!=PA の場合はどうやっても 80桁に収まらないので諦めてそのまま
213: // 出力するが、VA==PA の時は PA 用の空き地を削れば 80桁に収められる
214: // ので、その努力はしてみる。
215: if (fmt == Byte) {
216: fprintf(cons, "%s ", addrbuf.c_str());
217: } else {
218: fprintf(cons, "%-18s ", addrbuf.c_str());
219: }
220:
221: switch (fmt) {
222: case Byte:
223: case Word:
224: case Long:
225: {
226: std::vector<int> vec = Read(mem, fixed);
227: std::string dumpbuf = DumpHex(vec);
228: std::string charbuf = DumpChar(vec);
229: // 左詰めでいいか
230: fprintf(cons, "%s %s\n", dumpbuf.c_str(), charbuf.c_str());
231: break;
232: }
233:
234: case M68030PageShort:
235: {
236: std::vector<int> vec = Read(mem, fixed);
237: std::string dumpbuf = Dump68030PageShort(vec);
238: // 文字ダンプどうすべ
239: fprintf(cons, "%s\n", dumpbuf.c_str());
240: break;
241: }
242: case M88200Page:
243: {
244: std::vector<int> vec = Read(mem, fixed);
245: std::string dumpbuf = Dump88200Page(vec);
246: // 文字ダンプどうすべ
247: fprintf(cons, "%s\n", dumpbuf.c_str());
248: break;
249: }
250:
251: case M68030Disasm:
252: case M88100Disasm:
253: case HD64180Disasm:
254: line->Exec(&mem);
255: fprintf(cons, "%s%s\n", line->dump.c_str(), line->text.c_str());
256: break;
257:
258: default:
259: fprintf(cons, "fmt=%d not supported\n", (int)fmt);
260: mem.Offset(GetStride());
261: break;
262: }
263: }
264:
265: // アドレスを更新
266: saddr = mem.laddr;
267: }
268:
269: // メモリストリームから bytes バイト分読み込んでベクタにして返す。
270: // 各要素はバイトデータで、バスエラーは -1 になる。
271: std::vector<int>
272: Memdump::Read(DebuggerMemoryStream& mem, int bytes)
273: {
274: std::vector<int> vec(bytes);
275:
276: for (int i = 0; i < bytes; i++) {
277: vec[i] = mem.Read8();
278: }
279:
280: return vec;
281: }
282:
283: // vec[] の文字ダンプ文字列を返す。
1.1 root 284: std::string
1.1.1.2 root 285: Memdump::DumpChar(const std::vector<int>& vec)
1.1 root 286: {
1.1.1.2 root 287: std::string charbuf;
1.1 root 288:
1.1.1.2 root 289: for (auto c : vec) {
290: if (c < 0) {
291: charbuf += ' ';
292: } else {
293: charbuf += (0x20 <= c && c <= 0x7e) ? c : '.';
1.1 root 294: }
295: }
296:
1.1.1.2 root 297: return charbuf;
298: }
299:
300: // vec[] の HEX ダンプ文字列を返す。
301: // CLI, GUI 共通。
302: std::string
303: Memdump::DumpHex(const std::vector<int>& vec)
304: {
305: std::string dumpbuf;
306: int span;
307:
308: switch (fmt) {
309: case Byte: span = 1; break;
310: case Word: span = 2; break;
311: case Long: span = 4; break;
312: default:
313: PANIC("corrupted fmt=%d", (int)fmt);
1.1 root 314: }
315:
1.1.1.2 root 316: int s = span;
317: for (auto c : vec) {
318: if (c < 0) {
319: dumpbuf += "--";
320: } else {
321: dumpbuf += strhex(c, 2);
322: }
323:
324: if (--s == 0) {
325: dumpbuf += ' ';
326: s = span;
327: }
328: }
329:
330: return dumpbuf;
331: }
332:
333: // 68030 のショートフォーマットディスクリプタのダンプ文字列を返す。
334: std::string
335: Memdump::Dump68030PageShort(const std::vector<int>& vec)
336: {
337: std::string dumpbuf;
338:
339: // 2 3 4 5 6 7
340: // 9012345678901234567890123456789012345678901234567890123
341: // 00000000 DT=0(Invalid)
342: // ffffff00 DT=1(Page) $00000000 CI M U WP
343: // fffffff0 DT=2(Next Short) $00000000 U WP
344:
345: uint32 data = 0;
346: for (auto b : vec) {
347: if (b < 0) {
348: return "BusErr";
349: }
350: data = (data << 8) | (uint8)b;
1.1 root 351: }
352:
1.1.1.2 root 353: uint32 dt = (data & 0x03);
354: dumpbuf = string_format("%08x DT=%d%s", data, dt, dtname[dt]);
355:
356: if (dt != 0) {
357: if (dt == 1) {
358: dumpbuf += string_format(" $%08x %s %c",
359: (data & 0xffff'ff00),
360: (data & 0x40) ? "CI" : "- ",
361: (data & 0x10) ? 'M' : '-');
362: } else {
363: dumpbuf += string_format(" $%08x ", data & 0xffff'fff0);
364: }
365: dumpbuf += string_format(" %c %s",
366: (data & 0x08) ? 'U' : '-',
367: (data & 0x04) ? "WP" : "- ");
368: }
369:
370: return dumpbuf;
1.1 root 371: }
372:
1.1.1.2 root 373: // 88200 のセグメントディスクリプタとページディスクリプタ
374: std::string
375: Memdump::Dump88200Page(const std::vector<int>& vec)
376: {
377: std::string dumpbuf;
378:
379: // 2 3 4 5 6 7
380: // 9012345678901234567890123456789012345678901234567890123
381: // 00000000 $00000'000 WT SP G CI M U WP V
382:
383: uint32 data = 0;
384: for (auto b : vec) {
385: if (b < 0) {
386: return "BusErr";
387: }
388: data = (data << 8) | (uint8)b;
389: }
390:
391: dumpbuf = string_format("%08x $%05x'000 %s %s %c %s %c %c %s %c",
392: data,
393: (data >> 12),
394: (data & 0x200) ? "WT" : "- ",
395: (data & 0x100) ? "SP" : "- ",
396: (data & 0x080) ? 'G' : '-',
397: (data & 0x040) ? "CI" : "- ",
398: (data & 0x010) ? 'M' : '-',
399: (data & 0x008) ? 'U' : '-',
400: (data & 0x004) ? "WP" : "- ",
401: (data & 0x001) ? 'V' : '-');
402:
403: return dumpbuf;
404: }
405:
406: /*static*/ const char * const
407: Memdump::dtname[4] = {
408: "(Invalid) ",
409: "(Page) ",
410: "(Next Short)",
411: "(Next Long) ",
412: };
413:
1.1 root 414:
415: //
1.1.1.2 root 416: // メモリダンプモニタ
1.1 root 417: //
418:
419: // コンストラクタ
1.1.1.2 root 420: MemdumpMonitor::MemdumpMonitor(int objid_, int monid_)
421: : inherited(objid_)
1.1 root 422: {
1.1.1.2 root 423: monitor.func = ToMonitorCallback(&MemdumpMonitor::MonitorUpdate);
424: monitor.SetSize(84, 16);
425: monitor.Regist(monid_);
426: }
1.1 root 427:
1.1.1.2 root 428: // デストラクタ
429: MemdumpMonitor::~MemdumpMonitor()
430: {
431: }
1.1 root 432:
1.1.1.2 root 433: // モニタ更新
434: void
435: MemdumpMonitor::MonitorUpdate(Monitor *, TextScreen& screen)
436: {
1.1.1.3 ! root 437: DebuggerMemoryStream mem(md, saddr);
1.1.1.2 root 438:
439: screen.Clear();
440:
441: switch (fmt) {
442: case Byte:
443: case Word:
444: case Long:
445: case M68030PageShort:
446: case M88200Page:
447: MonitorUpdateMemdump(screen, mem);
448: break;
449:
450: case M68030PageLong:
451: screen.Puts(0, 0, "68030PageLong not supported");
452: break;
453:
454: case M68030Disasm:
455: case M88100Disasm:
456: case HD64180Disasm:
457: MonitorUpdateDisasm(screen, mem);
458: break;
459: }
1.1 root 460: }
461:
1.1.1.2 root 462: // モニタ更新 (メモリダンプ、ディスクリプタの場合)
463: void
464: MemdumpMonitor::MonitorUpdateMemdump(TextScreen& screen,
465: DebuggerMemoryStream& mem)
1.1 root 466: {
1.1.1.2 root 467: // モニタでは 80桁を超えて必要サイズ確保してあるので
468: // "VA:" も "VA:PA:" も同じ幅を占有し、
469: // ダンプフィールドは常に 19桁目から開始する。(see Print())
470: int dx = 19;
471:
472: // 文字列ダンプは桁数によらず右詰め
473: int cx = screen.GetCol() - GetStride();
474:
475: int row = screen.GetRow();
476: for (int y = 0; y < row; y++) {
477: std::string addrbuf;
478: bool accessible;
479:
480: // アドレス欄
481: accessible = mem.FormatAddr(addrbuf);
482: screen.Puts(0, y, addrbuf.c_str());
483: if (accessible == false) {
484: mem.Offset(GetStride());
485: continue;
486: }
487:
488: // 文字ダンプ
489: std::vector<int> vec = Read(mem, GetStride());
490: std::string charbuf = DumpChar(vec);
491: screen.Puts(cx, y, charbuf.c_str());
492:
493: // ダンプ本体
494: switch (fmt) {
495: case Byte:
496: case Word:
497: case Long:
498: {
499: std::string dumpbuf = DumpHex(vec);
500: screen.Puts(dx, y, dumpbuf.c_str());
501: break;
502: }
503: case M68030PageShort:
504: Update68030PageShort(screen, dx, y, vec);
505: break;
506: case M88200Page:
507: Update88200Page(screen, dx, y, vec);
508: break;
509: default:
510: PANIC("corrupted fmt=%d", (int)fmt);
511: }
512: }
513: }
514:
515: // (x, y) に 68030 ページディスクリプタのダンプを出力する。
516: void
517: MemdumpMonitor::Update68030PageShort(TextScreen& screen, int x, int y,
518: const std::vector<int>& vec)
519: {
520: // 2 3 4 5 6 7
521: // 9012345678901234567890123456789012345678901234567890123
522: // 00000000 $00000000 CI M U WP DT=1(Page)
523: // 00000000 $00000000 U WP DT=2(Next Short)
524:
525: uint32 data = 0;
526: for (auto b : vec) {
527: if (b < 0) {
528: screen.Puts(x, y, "BusErr");
529: return;
530: }
531: data = (data << 8) | (uint8)b;
532: }
533:
534: screen.Puts(x, y, strhex(data).c_str());
535:
536: uint32 dt = (data & 0x03);
537: TA attr = (dt != 0) ? TA::Normal : TA::Disable;
538:
539: if (dt == 1) {
540: screen.Putc(x + 10, y, attr, '$');
541: screen.Puts(x + 11, y, attr, strhex(data & 0xffff'ff00).c_str());
542: screen.Puts(x + 20, y, attr, (data & 0x40) ? "CI" : "-");
543: screen.Putc(x + 23, y, attr, (data & 0x10) ? 'M' : '-');
544: } else {
545: screen.Putc(x + 10, y, attr, '$');
546: screen.Puts(x + 11, y, attr, strhex(data & 0xffff'fff0).c_str());
547: }
548: screen.Putc(x + 25, y, attr, (data & 0x08) ? 'U' : '-');
549: screen.Puts(x + 27, y, attr, (data & 0x04) ? "WP" : "-");
550: screen.Print(x + 30, y, attr, "DT=%d%s", dt, dtname[dt]);
551: }
552:
553: // (x, y) に 88200 ページディスクリプタのダンプを出力する。
554: void
555: MemdumpMonitor::Update88200Page(TextScreen& screen, int x, int y,
556: const std::vector<int>& vec)
557: {
558: // 2 3 4 5 6 7
559: // 9012345678901234567890123456789012345678901234567890123
560: // 00000000 $00000'000 WT SP G CI M U WP V
561:
562: uint32 data = 0;
563: for (auto b : vec) {
564: if (b < 0) {
565: screen.Puts(x, y, "BusErr");
566: return;
567: }
568: data = (data << 8) | (uint8)b;
569: }
570:
571: screen.Puts(x, y, strhex(data).c_str());
572:
573: TA attr = (data & 0x001) ? TA::Normal : TA::Disable;
574: screen.Print(x + 10, y, attr, "$%05x'000 %s %s %c %s %c %c %s %c",
575: (data >> 12),
576: (data & 0x200) ? "WT" : "- ",
577: (data & 0x100) ? "SP" : "- ",
578: (data & 0x080) ? 'G' : '-',
579: (data & 0x040) ? "CI" : "- ",
580: (data & 0x010) ? 'M' : '-',
581: (data & 0x008) ? 'U' : '-',
582: (data & 0x004) ? "WP" : "- ",
583: (data & 0x001) ? 'V' : '-');
584: }
585:
586: // モニタ更新 (逆アセンブルの場合)
587: void
588: MemdumpMonitor::MonitorUpdateDisasm(TextScreen& screen,
589: DebuggerMemoryStream& mem)
590: {
591: // モニタでは 80桁を超えて必要サイズ確保してあるので
592: // "VA:" も "VA:PA:" も同じ幅を占有し、
593: // ダンプフィールドは常に 19桁目から開始する。(see Print())
594: int dx = 19;
595:
596: int row = screen.GetRow();
597:
598: // 逆アセンブラ用の次行アドレスバッファを必要ならリサイズ
1.1.1.3 ! root 599: if ((row + 1) != nextaddr.size()) {
! 600: nextaddr.resize(row + 1);
1.1.1.2 root 601: }
602:
1.1.1.3 ! root 603: nextaddr[0] = mem.laddr.Addr();
1.1.1.2 root 604: for (int y = 0; y < row; y++) {
605: std::string addrbuf;
606: bool accessible;
607: TA attr;
608:
609: // PC のいる行をボールドに
610: if (__predict_false((uint32)mem.laddr == md->GetPC())) {
611: attr = TA::Em;
612: } else {
613: attr = TA::Normal;
614: }
615:
616: // アドレス欄
617: accessible = mem.FormatAddr(addrbuf);
618: screen.Puts(0, y, attr, addrbuf.c_str());
619: if (accessible == false) {
620: mem.Offset(GetStride());
621: continue;
622: }
623:
624: line->Exec(&mem);
625: screen.Print(dx, y, attr, "%s%s",
626: line->dump.c_str(), line->text.c_str());
627:
628: // 次行の開始アドレスを覚えておく。
629: // 逆アセンブラで n 行下へ移動する時のため。
1.1.1.3 ! root 630: nextaddr[y + 1] = mem.laddr.Addr();
1.1.1.2 root 631: }
632: }
633:
634: // n 行下の行までのバイトオフセットを返す。
635: int
636: MemdumpMonitor::GetLineOffset(int n) const
637: {
638: if (fixed) {
639: // 固定長フォーマットなら fixed 倍するだけで求まる。
640: return n * fixed;
641: } else {
642: // 可変長フォーマット
1.1.1.3 ! root 643: if (0 <= n && n < nextaddr.size()) {
! 644: return nextaddr[n] - nextaddr[0];
1.1.1.2 root 645: } else {
646: // なければ仕方ないので適当に返す
647: return n * inst_bytes;
648: }
649: }
650: }
651:
652: // 前ページ位置(-1)、次ページ位置(1) までのバイトオフセットを返す。
653: int
654: MemdumpMonitor::GetPageOffset(int n) const
655: {
656: // 前ページ/次ページ開始位置は、メモリダンプと逆アセンブルで動作を変える。
657: // メモリダンプならきっちり次のページを表示してほしい。例えば 1画面が
658: // 16行(256バイト) で、現在 $100 にいて次ページに飛ぶ時は $200 になって
659: // ほしい。
660: // 逆アセンブルでは実際にこの動作をすると連続性が失われて読みにくいので
661: // 1行だぶらせることにする。
662:
663: int row = monitor.GetSize().height;
664: if (inst_bytes) {
665: // 逆アセンブルの場合
666: if (n < 0) {
667: // 戻る時は、(最短)命令長分ずつ戻るしかない。
668: return -inst_bytes * (row - 1);
669: } else {
670: return GetLineOffset(row - 1);
671: }
672: } else {
673: // メモリダンプ系の場合は単純に row 分前か後ろというだけ
674: return GetLineOffset(row * n);
675: }
1.1 root 676: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.