mirror of
https://github.com/ksherlock/mpw.git
synced 2024-11-25 19:30:50 +00:00
244 lines
5.5 KiB
C++
244 lines
5.5 KiB
C++
|
|
#include <cstdint>
|
|
#include <ctime>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
|
|
#include <toolbox/os.h>
|
|
#include <macos/errors.h>
|
|
|
|
#include <cpu/defs.h>
|
|
#include <cpu/CpuModule.h>
|
|
|
|
#include "debugger.h"
|
|
#include "debugger_internal.h"
|
|
#include "loader.h" // Flags
|
|
|
|
|
|
namespace Debug {
|
|
|
|
using namespace Internal;
|
|
|
|
|
|
void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0)
|
|
{
|
|
const char *HexMap = "0123456789abcdef";
|
|
|
|
char buffer1[16 * 3 + 1 + 1];
|
|
char buffer2[16 + 1];
|
|
ssize_t offset = 0;
|
|
unsigned i, j;
|
|
|
|
|
|
while(size > 0)
|
|
{
|
|
std::memset(buffer1, ' ', sizeof(buffer1));
|
|
std::memset(buffer2, ' ', sizeof(buffer2));
|
|
|
|
unsigned linelen = (unsigned)std::min(size, (ssize_t)16);
|
|
|
|
|
|
for (i = 0, j = 0; i < linelen; i++)
|
|
{
|
|
unsigned x = data[i];
|
|
buffer1[j++] = HexMap[x >> 4];
|
|
buffer1[j++] = HexMap[x & 0x0f];
|
|
j++;
|
|
if (i == 7) j++;
|
|
|
|
// isascii not part of std:: and may be a macro.
|
|
buffer2[i] = isascii(x) && std::isprint(x) ? x : '.';
|
|
|
|
}
|
|
|
|
buffer1[sizeof(buffer1)-1] = 0;
|
|
buffer2[sizeof(buffer2)-1] = 0;
|
|
|
|
|
|
std::printf("%06x: %s %s\n", address + (unsigned)offset, buffer1, buffer2);
|
|
offset += 16;
|
|
data += 16;
|
|
size -= 16;
|
|
}
|
|
std::printf("\n");
|
|
}
|
|
|
|
|
|
|
|
void PrintError(uint32_t value)
|
|
{
|
|
/* expr ; error -- interpret expr as an OSErr */
|
|
|
|
|
|
// errors are signed 16-bit values.
|
|
|
|
if ((int32_t)value > UINT16_MAX) return;
|
|
if ((int32_t)value < INT16_MIN) return;
|
|
|
|
|
|
uint16_t error = value;
|
|
printf("%d\n", (int16_t)error);
|
|
|
|
if (error)
|
|
{
|
|
bool found = false;
|
|
const char *cp = ErrorName(error);
|
|
if (cp)
|
|
{
|
|
printf("%s\n", cp);
|
|
found = true;
|
|
}
|
|
|
|
|
|
for (auto iter = ErrorTableInvert.find(error); iter != ErrorTableInvert.end(); ++iter) {
|
|
|
|
// multimap - continue until error doesn't match.
|
|
if (iter->first != error) break;
|
|
|
|
printf("%s\n", iter->second.c_str());
|
|
found = true;
|
|
}
|
|
|
|
if (!found) printf("Unknown error\n");
|
|
}
|
|
else
|
|
{
|
|
printf("noErr\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void PrintDate(uint32_t value)
|
|
{
|
|
/* expr ; date -- interpret expr as a macos date */
|
|
|
|
char buffer[64];
|
|
struct tm *tm;
|
|
time_t t = OS::MacToUnix(value);
|
|
|
|
// localtime vs gmtime?
|
|
tm = ::localtime(&t);
|
|
strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M:%S %p", tm);
|
|
puts(buffer);
|
|
}
|
|
|
|
|
|
void Moof(void)
|
|
{
|
|
|
|
puts("");
|
|
puts(" ## ");
|
|
puts(" ## ## #### ");
|
|
puts(" ## #### ## ");
|
|
puts(" ## ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ## ## #### ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ######## #### ## ## ");
|
|
puts(" ## #################### ## ");
|
|
puts(" ## ############## ## ");
|
|
puts(" #### ############ ## ");
|
|
puts(" ###### ###### ## ");
|
|
puts(" ###### ## ");
|
|
puts(" #### ## ");
|
|
puts(" ## ## ");
|
|
puts(" ## ################ ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ## ## ## ## ");
|
|
puts(" ###### ###### ");
|
|
puts("");
|
|
|
|
}
|
|
|
|
|
|
void StackCrawl(void)
|
|
{
|
|
// stack crawl based on a6 frame pointers. (link/unlink)
|
|
// start with current a6.
|
|
|
|
uint32_t a6 = cpuGetAReg(6);
|
|
|
|
/*
|
|
* a6: previous a6
|
|
* a6+4 return pc
|
|
* .... parameters, locals, stack data
|
|
* previous a6
|
|
* return pc
|
|
* ....
|
|
*/
|
|
// todo -- need a function to verify address is w/in stack range.
|
|
|
|
// todo print in reverse order so newest frame doesn't scroll away.
|
|
|
|
if (!a6) return;
|
|
printf("a6: %08x\n", a6);
|
|
|
|
while(a6)
|
|
{
|
|
|
|
uint32_t prevA6 = ReadLong(a6);
|
|
if (prevA6 <= a6) break;
|
|
|
|
uint32_t pc = ReadLong(a6+4); //
|
|
|
|
|
|
|
|
// hexdump contents between pc and previous....
|
|
ssize_t size = prevA6 - a6 - 8;
|
|
hexdump(Flags.memory + a6 + 8, size);
|
|
|
|
|
|
|
|
puts("------------");
|
|
printf("a6: %08x\n", prevA6);
|
|
printf("pc: %08x", pc);
|
|
|
|
// find the routine name...
|
|
for (const auto &kv : SymbolTable)
|
|
{
|
|
const auto &name = kv.first;
|
|
auto range = kv.second;
|
|
|
|
// range end may be 0
|
|
if ((pc == range.first) || (pc >= range.first && pc < range.second))
|
|
{
|
|
uint32_t offset = pc - range.first;
|
|
if (offset)
|
|
printf(" %s+$%x", name.c_str(), offset);
|
|
else
|
|
printf(" %s", name.c_str());
|
|
break;
|
|
}
|
|
}
|
|
puts("");
|
|
|
|
a6 = prevA6;
|
|
}
|
|
}
|
|
|
|
void Dump(uint32_t start, int size)
|
|
{
|
|
// TODO -- if no address, use previous address.
|
|
// TODO -- support range?
|
|
|
|
|
|
if (size <= 0) return;
|
|
|
|
uint32_t end = start + size;
|
|
|
|
if (start >= Flags.memorySize) return;
|
|
|
|
end = std::min(end, Flags.memorySize);
|
|
size = end - start;
|
|
|
|
hexdump(Flags.memory + start, size, start);
|
|
}
|
|
|
|
|
|
}
|