void test_c64_vice_basic_breakpoint(void**) { Session_action(s_session, PDAction_step); uint64_t breakAddress = 0x0813; stepToPC(0x080e); // Add a breakpoint at 0x0814 PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_setBreakpoint); PDWrite_u64(writer, "address", breakAddress); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); Session_action(s_session, PDAction_run); waitForBreak(breakAddress, 0, 0); stepToPC(0x080e); // Update the breakpoint to different address breakAddress = 0x0816; writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_setBreakpoint); PDWrite_u64(writer, "address", breakAddress); PDWrite_u64(writer, "id", 1); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); Session_action(s_session, PDAction_run); waitForBreak(breakAddress, 0, 0); // Delete the breakpoint stepToPC(0x080e); writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_deleteBreakpoint); PDWrite_u32(writer, "id", 2); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); Session_action(s_session, PDAction_run); }
void test_c64_vice_breakpoint_cond(void**) { CPUState state = { 0 }; Session_action(s_session, PDAction_step); const uint64_t breakAddress = 0x0816; stepToPC(0x080e); // Add a breakpoint at 0x0814 PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_setBreakpoint); PDWrite_u64(writer, "address", breakAddress); PDWrite_string(writer, "condition", ".y == 0"); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); Session_action(s_session, PDAction_run); waitForBreak(breakAddress, &state, CPUState_maskY); }
static void setExceptionLocation(PDWriter* writer) { PDWrite_eventBegin(writer,PDEventType_setExceptionLocation); PDWrite_u16(writer, "address", pc); PDWrite_u8(writer, "address_size", 2); PDWrite_eventEnd(writer); }
static void setExceptionLocation(LLDBPlugin* plugin, PDWriter* writer) { char filename[2048]; memset(filename, 0, sizeof(filename)); // Get the filename & line of the exception/breakpoint // \todo: Right now we assume that we only got the break/exception at the first thread. lldb::SBThread thread(plugin->process.GetThreadByID(plugin->selectedThreadId)); uint32_t frameIndex = getThreadFrame(plugin, plugin->selectedThreadId); lldb::SBFrame frame(thread.GetFrameAtIndex(frameIndex)); lldb::SBCompileUnit compileUnit = frame.GetCompileUnit(); lldb::SBFileSpec filespec(plugin->process.GetTarget().GetExecutable()); if (compileUnit.GetNumSupportFiles() > 0) { lldb::SBFileSpec fileSpec = compileUnit.GetSupportFileAtIndex(0); fileSpec.GetPath(filename, sizeof(filename)); } lldb::SBSymbolContext context(frame.GetSymbolContext(lldb::eSymbolContextEverything)); lldb::SBLineEntry entry(context.GetLineEntry()); uint32_t line = entry.GetLine(); PDWrite_eventBegin(writer, PDEventType_setExceptionLocation); PDWrite_string(writer, "filename", filename); PDWrite_u32(writer, "line", line); PDWrite_eventEnd(writer); }
static int update(void* userData, PDUI* uiFuncs, PDReader* inEvents, PDWriter* outEvents) { uint32_t event = 0; while ((event = PDRead_getEvent(inEvents)) != 0) { switch (event) { case PDEventType_setLocals: { showInUI((LocalsData*)userData, inEvents, uiFuncs); break; } } } // Request callstack data // TODO: Dont' request locals all the time PDWrite_eventBegin(outEvents, PDEventType_getLocals); PDWrite_u8(outEvents, "dummy_remove", 0); // TODO: Remove me PDWrite_eventEnd(outEvents); return 0; }
void test_c64_vice_get_disassembly(void**) { static Assembly assembly[] = { { 0x080e, "A9 22 LDA #$22" }, { 0x0810, "A2 32 LDX #$32" }, { 0x0812, "C8 INY" }, { 0x0813, "EE 20 D0 INC $D020" }, { 0x0816, "EE 21 D0 INC $D021" }, { 0x0819, "4C 0E 08 JMP $080E" }, { 0, 0 }, }; PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getDisassembly); PDWrite_u64(writer, "address_start", 0x80e); PDWrite_u32(writer, "instruction_count", (uint32_t)4); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); PDReader* reader = s_session->reader; PDBinaryReader_initStream(reader, PDBinaryWriter_getData(s_session->currentWriter), PDBinaryWriter_getSize(s_session->currentWriter)); uint32_t event; while ((event = PDRead_getEvent(reader)) != 0) { if (event != PDEventType_setDisassembly) continue; PDReaderIterator it; assert_false(PDRead_findArray(reader, &it, "disassembly", 0) == PDReadStatus_notFound); int i = 0; while (PDRead_getNextEntry(reader, &it)) { uint64_t address; const char* text; PDRead_findU64(reader, &address, "address", it); PDRead_findString(reader, &text, "line", it); assert_non_null(assembly[i].text); assert_int_equal((int)assembly[i].address, (int)address); assert_string_equal(assembly[i].text, text); i++; } return; } }
void test_c64_vice_callstack(void**) { uint32_t event; PDReaderIterator it; uint16_t refCallstack[] = { 0xe112 + 2, // (2) e112 0xa562 + 4, // (4) a562 0xa483 + 6, // (6) a483 0xa677 + 8, // (8) a677 0xe39a + 10, // (10) e39a }; PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getCallstack); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); PDReader* reader = s_session->reader; PDBinaryReader_initStream(reader, PDBinaryWriter_getData(s_session->currentWriter), PDBinaryWriter_getSize(s_session->currentWriter)); while ((event = PDRead_getEvent(reader)) != 0) { switch (event) { case PDEventType_setCallstack: { if (PDRead_findArray(reader, &it, "callstack", 0) == PDReadStatus_notFound) return; int callstackSize = sizeof_array(refCallstack); int count = 0; while (PDRead_getNextEntry(reader, &it)) { uint16_t address; PDRead_findU16(reader, &address, "address", it); assert_true(count < callstackSize); assert_int_equal(refCallstack[count], address); count++; } return; } } } fail(); }
static int update(void* userData, PDUI* uiFuncs, PDReader* inEvents, PDWriter* writer) { uint32_t event; DissassemblyData* data = (DissassemblyData*)userData; data->requestDisassembly = false; while ((event = PDRead_getEvent(inEvents)) != 0) { switch (event) { case PDEventType_setDisassembly: { setDisassemblyCode(data, inEvents); break; } case PDEventType_setExceptionLocation: { uint64_t location = 0; PDRead_findU64(inEvents, &location, "address", 0); if (location != data->location) { data->location = location; data->requestDisassembly = true; } PDRead_findU8(inEvents, &data->locationSize, "address_size", 0); break; } case PDEventType_setRegisters: { updateRegisters(data, inEvents); break; } } } renderUI(data, uiFuncs); if (data->requestDisassembly) { int pc = (int)(data->pc) & ~(BlockSize - 1); PDWrite_eventBegin(writer, PDEventType_getDisassembly); PDWrite_u64(writer, "address_start", (uint64_t)pc); PDWrite_u32(writer, "instruction_count", (uint32_t)BlockSize / 3); PDWrite_eventEnd(writer); } return 0; }
void test_c64_vice_step_cpu(void**) { CPUState state; Session_action(s_session, PDAction_step); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); assert_int_equal(state.a, 0x22); assert_int_equal(state.x, 0x32); Session_action(s_session, PDAction_step); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); Session_action(s_session, PDAction_step); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); // Get registers after some stepping PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getRegisters); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getRegisters); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); }
static void setCallstack(LLDBPlugin* plugin, PDWriter* writer) { lldb::SBThread thread(plugin->process.GetThreadByID(plugin->selectedThreadId)); printf("set callstack\n"); int frameCount = (int)thread.GetNumFrames(); if (frameCount == 0) return; // TODO: Write type of callstack PDWrite_eventBegin(writer, PDEventType_setCallstack); PDWrite_arrayBegin(writer, "callstack"); for (int i = 0; i < frameCount; ++i) { char fileLine[2048]; char moduleName[2048]; lldb::SBFrame frame = thread.GetFrameAtIndex((uint32_t)i); lldb::SBModule module = frame.GetModule(); lldb::SBCompileUnit compileUnit = frame.GetCompileUnit(); lldb::SBSymbolContext context(frame.GetSymbolContext(0x0000006e)); lldb::SBLineEntry entry(context.GetLineEntry()); uint64_t address = (uint64_t)frame.GetPC(); module.GetFileSpec().GetPath(moduleName, sizeof(moduleName)); PDWrite_arrayEntryBegin(writer); if (compileUnit.GetNumSupportFiles() > 0) { char filename[2048]; lldb::SBFileSpec fileSpec = compileUnit.GetSupportFileAtIndex(0); fileSpec.GetPath(filename, sizeof(filename)); sprintf(fileLine, "%s:%d", filename, entry.GetLine()); printf("callstack %s:%d\n", fileLine, entry.GetLine()); PDWrite_string(writer, "filename", filename); PDWrite_u32(writer, "line", entry.GetLine()); } PDWrite_string(writer, "module_name", moduleName); PDWrite_u64(writer, "address", address); PDWrite_arrayEntryEnd(writer); } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static int update(void* userData, PDUI* uiFuncs, PDReader* inEvents, PDWriter* outEvents) { ConsoleData* consoleData = (ConsoleData*)userData; uint32_t event = 0; (void)event; // test working build /*while ((event = PDRead_getEvent(inEvents)) != 0) { switch (event) { case PDEventType_setConsole: { //showInUI((ConsoleData*)userData, inEvents, uiFuncs); break; } } }*/ showInUI(consoleData, inEvents, uiFuncs); for (size_t i = 0; i < consoleData->scripts.size(); ++i) { PDWrite_eventBegin(outEvents, PDEventType_executeConsole); PDWrite_string(outEvents, "command", consoleData->scripts[i]); // TODO: Remove me PDWrite_eventEnd(outEvents); //free(consoleData->scripts[i]); } consoleData->scripts.clear(); // Request console data PDWrite_eventBegin(outEvents, PDEventType_getConsole); PDWrite_u8(outEvents, "dummy_remove", 0); // TODO: Remove me PDWrite_eventEnd(outEvents); return 0; }
static void parseForCallstack(PDWriter* writer, const char* data, int length) { uint16_t callStackEntries[256 * 2]; int callStackCount = 0; memcpy(s_tempBuffer, data, length); s_tempBuffer[length] = 0; char* pch = strtok(s_tempBuffer, "\n"); while (pch) { // expected format of each line: // xxx.. .C:080e A9 22 LDA #$22 if (pch[0] == '(' && pch[1] != 'C') { uint32_t offset = (uint32_t)atoi(&pch[2]); char* endOffset = strstr(&pch[2], ") "); if (endOffset) { endOffset += 2; uint16_t address = (uint16_t)strtol(endOffset, 0, 16); callStackEntries[(callStackCount * 2) + 0] = address; callStackEntries[(callStackCount * 2) + 1] = (uint16_t)offset; callStackCount++; } } pch = strtok(0, "\n"); } if (callStackCount == 0) return; PDWrite_eventBegin(writer, PDEventType_setCallstack); PDWrite_arrayBegin(writer, "callstack"); for (int i = 0; i < callStackCount; ++i) { PDWrite_arrayEntryBegin(writer); PDWrite_u16(writer, "address", callStackEntries[(i * 2) + 0] + callStackEntries[(i * 2) + 1]); PDWrite_arrayEntryEnd(writer); } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static void setDisassembly(PDWriter* writer, int start, int instCount) { char temp[65536]; disassembleToBuffer(temp, &start, &instCount); PDWrite_eventBegin(writer, PDEventType_setDisassembly); PDWrite_u16(writer, "address_start", (uint16_t)start); PDWrite_u16(writer, "instruction_count", (uint16_t)instCount); PDWrite_string(writer, "string_buffer", temp); PDWrite_eventEnd(writer); }
static PDDebugState update(void* userData, PDAction action, PDReader* reader, PDWriter* writer) { PluginData* plugin = (PluginData*)userData; plugin->hasUpdatedRegistes = false; plugin->hasUpdatedExceptionLocation = false; onAction(plugin, action); processEvents(plugin, reader, writer); updateEvents(plugin, writer); if (plugin->hasUpdatedRegistes) { PDWrite_eventBegin(writer, PDEventType_setRegisters); PDWrite_arrayBegin(writer, "registers"); writeStatusRegister(writer, "flags", plugin->regs.flags); writeRegister(writer, "pc", 2, plugin->regs.pc, 1); writeRegister(writer, "sp", 1, plugin->regs.sp, 0); writeRegister(writer, "a", 1, plugin->regs.a, 0); writeRegister(writer, "x", 1, plugin->regs.x, 0); writeRegister(writer, "y", 1, plugin->regs.y, 0); PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); } if (plugin->hasUpdatedExceptionLocation) { PDWrite_eventBegin(writer, PDEventType_setExceptionLocation); PDWrite_u64(writer, "address", plugin->regs.pc); PDWrite_u8(writer, "address_size", 2); PDWrite_eventEnd(writer); } return plugin->state; }
static void test_c64_vice_connect(void**) { int count = 0; PluginData* pluginData; pluginData = PluginHandler_getBackendPlugins(&count)[0]; // Lanuch C64 VICE // TODO: Fix hardcoded path #ifdef PRODBG_MAC //const char* viceLaunchPath = "../../vice/x64.app/Contents/MacOS/x64"; const char* viceLaunchPath = "/Applications/VICE/x64.app/Contents/MacOS/x64"; #elif PRODBG_WIN const char* viceLaunchPath = "..\\..\\vice\\x64.exe"; #else // Not supported on Linux yet const char* viceLaunchPath = 0; #endif assert_non_null(viceLaunchPath); //const char* argv[] = { viceLaunchPath, "-remotemonitor", "-console", "examples/c64_vice/test.prg", 0 }; const char* argv[] = { viceLaunchPath, "-remotemonitor", "-console", 0 }; s_viceHandle = Process_spawn(viceLaunchPath, argv); assert_non_null(s_viceHandle); // Wait 3 sec for VICE to launch Time_sleepMs(3000); // TODO: Non hard-coded path s_session = Session_createLocal((PDBackendPlugin*)pluginData->plugin, 0); // make sure we attach to VICE PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_menuEvent); PDWrite_u32(writer, "menu_id", 0); PDWrite_eventEnd(writer); Session_update(s_session); // We haven't setup vice at this point so no connect assert_int_not_equal(s_session->state, PDDebugState_noTarget); }
void test_c64_vice_get_registers(void**) { CPUState state; PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getRegisters); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); assert_true(handleEvents(&state, s_session)); assert_true(state.pc >= 0x80e && state.pc <= 0x81a); }
static void setTty(LLDBPlugin* plugin, PDWriter* writer) { const int bufferSize = 4 * 1024; char buffer[bufferSize]; size_t amountRead = plugin->process.GetSTDOUT(buffer, bufferSize); if (amountRead > 0) { PDWrite_eventBegin(writer, PDEventType_setTty); PDWrite_string(writer, "tty", buffer); PDWrite_eventEnd(writer); } }
static void setRegisters(PDWriter* writer) { PDWrite_eventBegin(writer, PDEventType_setRegisters); PDWrite_arrayBegin(writer, "registers"); writeRegister(writer, "pc", 2, pc, 1); writeRegister(writer, "sp", 1, sp, 0); writeRegister(writer, "a", 1, a, 0); writeRegister(writer, "x", 1, x, 0); writeRegister(writer, "y", 1, y, 0); writeRegister(writer, "status", 1, status, 1); PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static bool delBreakpoint(PluginData* data, PDReader* reader, PDWriter* writer) { int32_t id; if (PDRead_findS32(reader, &id, "id", 0) == PDReadStatus_notFound) { PDWrite_eventBegin(writer, PDEventType_replyBreakpoint); PDWrite_string(writer, "error", "No ID being sent for breakpoint"); PDWrite_eventEnd(writer); return false; } printf("deleting breakpoint with id %d\n", id); return delBreakpointById(data, id); }
void test_c64_vice_start_executable(void**) { const char* prgFile = "/Users/danielcollin/code/ProDBG/examples/c64_vice/test.prg"; PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_setExecutable); PDWrite_string(writer, "filename", prgFile); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); // Annoying to da anything about this as VICE doesn't reply back anything // when doing <g $xxx> Time_sleepMs(200); }
static void setSourceFiles(LLDBPlugin* plugin, PDWriter* writer) { if (!plugin->hasValidTarget) return; PDWrite_eventBegin(writer, PDEventType_setSourceFiles); PDWrite_arrayBegin(writer, "files"); const uint32_t moduleCount = plugin->target.GetNumModules(); for (uint32_t im = 0; im < moduleCount; ++im) { lldb::SBModule module(plugin->target.GetModuleAtIndex(im)); const uint32_t compileUnitCount = module.GetNumCompileUnits(); for (uint32_t ic = 0; ic < compileUnitCount; ++ic) { lldb::SBCompileUnit compileUnit(module.GetCompileUnitAtIndex(ic)); const uint32_t supportFileCount = compileUnit.GetNumSupportFiles(); for (uint32_t is = 0; is < supportFileCount; ++is) { char filename[4096]; lldb::SBFileSpec fileSpec(compileUnit.GetSupportFileAtIndex(is)); filename[0] = 0; fileSpec.GetPath(filename, sizeof(filename)); if (filename[0] == 0) continue; PDWrite_arrayEntryBegin(writer); PDWrite_string(writer, "file", filename); PDWrite_arrayEntryEnd(writer); } } } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static void parseBreakpoint(PluginData* data, const char* res, PDWriter* writer) { Breakpoint* bp = 0; // TODO: loop, look for more breakpoints const char* breakStrOffset = strstr(res, "BREAK:"); if (!breakStrOffset) return; int id = atoi(breakStrOffset + 7); const char* address = strstr(breakStrOffset, "C:$"); if (!findBreakpointById(data, &bp, id)) { bp = createBreakpoint(); addBreakpoint(data, bp); } bp->id = id; if (address) bp->address = (uint16_t)strtol(address + 3, 0, 16); // add data or update existing PDWrite_eventBegin(writer, PDEventType_replyBreakpoint); PDWrite_u64(writer, "address", bp->address); PDWrite_u32(writer, "id", (uint32_t)id); PDWrite_eventEnd(writer); printf("sending reply back: breakpoint %x - %d\n", bp->address, id); // TODO: Condition //if (bp->condition) // free(bp->condition); //if (condition) // bp->condition = strdup(condition); // else // bp->condition = 0; }
static void setThreads(LLDBPlugin* plugin, PDWriter* writer) { uint32_t threadCount = plugin->process.GetNumThreads(); if (threadCount == 0) return; PDWrite_eventBegin(writer, PDEventType_setThreads); PDWrite_arrayBegin(writer, "threads"); for (uint32_t i = 0; i < threadCount; ++i) { lldb::SBThread thread = plugin->process.GetThreadAtIndex(i); lldb::SBFrame frame = thread.GetFrameAtIndex(0); uint64_t threadId = thread.GetThreadID(); const char* threadName = thread.GetName(); const char* queueName = thread.GetQueueName(); const char* functionName = frame.GetFunctionName(); PDWrite_arrayEntryBegin(writer); PDWrite_u64(writer, "id", threadId); if (threadName) PDWrite_string(writer, "name", threadName); else if (queueName) PDWrite_string(writer, "name", queueName); else PDWrite_string(writer, "name", "unknown_thread"); if (functionName) PDWrite_string(writer, "function", functionName); else PDWrite_string(writer, "function", "unknown_function"); PDWrite_arrayEntryEnd(writer); } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static void selectThread(LLDBPlugin* plugin, PDReader* reader, PDWriter* writer) { uint64_t threadId; PDRead_findU64(reader, &threadId, "thread_id", 0); printf("trying te set thread %llu\n", threadId); if (plugin->selectedThreadId == threadId) return; printf("selecting thread %llu\n", threadId); plugin->selectedThreadId = threadId; setCallstack(plugin, writer); PDWrite_eventBegin(writer, PDEventType_selectFrame); PDWrite_u32(writer, "frame", getThreadFrame(plugin, threadId)); PDWrite_eventEnd(writer); }
static int update(void* userData, PDUI* uiFuncs, PDReader* inEvents, PDWriter* writer) { uint32_t event; DissassemblyData* data = (DissassemblyData*)userData; while ((event = PDRead_getEvent(inEvents)) != 0) { switch (event) { case PDEventType_setDisassembly: { setDisassemblyCode(data, inEvents); break; } case PDEventType_setExceptionLocation: { PDRead_findU64(inEvents, &data->location, "address", 0); PDRead_findU8(inEvents, &data->locationSize, "address_size", 0); break; } case PDEventType_setRegisters: updateRegisters(data, inEvents); break; } } renderUI(data, uiFuncs); // Temporary req PDWrite_eventBegin(writer, PDEventType_getDisassembly); PDWrite_u64(writer, "address_start", 0); PDWrite_u32(writer, "instruction_count", (uint32_t)10); PDWrite_eventEnd(writer); return 0; }
bool getMemory(void* dest, int* len, uint16_t inAddress, int readLength) { PDWriter* writer = s_session->currentWriter; PDWrite_eventBegin(writer, PDEventType_getMemory); PDWrite_u64(writer, "address_start", inAddress); PDWrite_u64(writer, "size", (uint32_t)readLength); PDWrite_eventEnd(writer); PDBinaryWriter_finalize(writer); Session_update(s_session); PDReader* reader = s_session->reader; PDBinaryReader_initStream(reader, PDBinaryWriter_getData(s_session->currentWriter), PDBinaryWriter_getSize(s_session->currentWriter)); uint32_t event; while ((event = PDRead_getEvent(reader)) != 0) { uint8_t* data; uint64_t dataSize; uint64_t address; if (event != PDEventType_setMemory) continue; assert_true(PDRead_findU64(reader, &address, "address", 0) & PDReadStatus_ok); assert_true((PDRead_findData(reader, (void**)&data, &dataSize, "data", 0) & PDReadStatus_typeMask) == PDReadType_data); memcpy(dest, data, dataSize); *len = (int)dataSize; return true; } return false; }
static void setLocals(LLDBPlugin* plugin, PDWriter* writer) { lldb::SBThread thread(plugin->process.GetThreadByID(plugin->selectedThreadId)); lldb::SBFrame frame = thread.GetSelectedFrame(); lldb::SBValueList variables = frame.GetVariables(true, true, true, false); uint32_t count = variables.GetSize(); if (count <= 0) return; PDWrite_eventBegin(writer, PDEventType_setLocals); PDWrite_arrayBegin(writer, "locals"); for (uint32_t i = 0; i < count; ++i) { lldb::SBValue value = variables.GetValueAtIndex(i); PDWrite_arrayEntryBegin(writer); PDWrite_u64(writer, "address", value.GetAddress().GetFileAddress()); if (value.GetValue()) PDWrite_string(writer, "value", value.GetValue()); if (value.GetTypeName()) PDWrite_string(writer, "type", value.GetTypeName()); if (value.GetName()) PDWrite_string(writer, "name", value.GetName()); PDWrite_arrayEntryEnd(writer); } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static void getMemory(PluginData* data, PDReader* reader, PDWriter* writer) { uint64_t address; uint64_t size; size_t readSize = 0; PDRead_findU64(reader, &address, "address_start", 0); PDRead_findU64(reader, &size, "size", 0); // so this is a bit of a hack. If we request memory d000 we switch to io and then back // this isn't really correct but will do for now if (address == 0xdd00) sendCommand(data, "bank io\n"); uint8_t* memory = getMemoryInternal(data, data->tempFileFull, &readSize, (uint16_t)(address), (uint16_t)(address + size)); if (address == 0xdd00) sendCommand(data, "bank ram\n"); if (memory) { // Lets do this! // + 2 is because VICE writes address at the start of the block and at the end // printf("c64_vice: sending memory\n"); PDWrite_eventBegin(writer, PDEventType_setMemory); PDWrite_u64(writer, "address", address); PDWrite_data(writer, "data", memory + 2, (uint32_t)(readSize - 3)); PDWrite_eventEnd(writer); // writer takes a copy free(memory); } }
static void parseDisassembly(PDWriter* writer, const char* data, int length) { memcpy(s_tempBuffer, data, length); s_tempBuffer[length] = 0; // parse the buffer char* pch = strtok(s_tempBuffer, "\n"); PDWrite_eventBegin(writer, PDEventType_setDisassembly); PDWrite_arrayBegin(writer, "disassembly"); while (pch) { // expected format of each line: // xxx.. .C:080e A9 22 LDA #$22 char* line = strstr(pch, ".C"); if (!line) break; uint16_t address = (uint16_t)strtol(&line[3], 0, 16); PDWrite_arrayEntryBegin(writer); PDWrite_u16(writer, "address", address); PDWrite_string(writer, "line", parseDisassemblyLine(&line[9])); PDWrite_arrayEntryEnd(writer); pch = strtok(0, "\n"); } PDWrite_arrayEnd(writer); PDWrite_eventEnd(writer); }
static int update(void* userData, PDUI* uiFuncs, PDReader* inEvents, PDWriter* writer) { uint32_t event; (void)uiFuncs; (void)writer; BreakpointsData* data = (BreakpointsData*)userData; while ((event = PDRead_getEvent(inEvents)) != 0) { switch (event) { case PDEventType_setBreakpoint: { toogleBreakpointFileLine(data, inEvents); break; } case PDEventType_replyBreakpoint: { uint64_t address = 0; uint32_t id = (uint32_t) ~0; PDRead_findU64(inEvents, &address, "address", 0); PDRead_findU32(inEvents, &id, "id", 0); for (Breakpoint* bp : data->breakpoints) { if ((uint64_t)strtol(bp->location.address, 0, 16) == address) { bp->pendingCount = 0; // breakpoint accepted printf("bp view: updated breakpoint with id %d (was %d)\n", id, bp->id); bp->id = (int)id; break; } } break; } } } uiFuncs->text(""); if (uiFuncs->button("Add Breakpoint", { 0.0f, 0.0f } )) { Breakpoint* bp = createBreakpoint(data); data->breakpoints.push_back(bp); } uiFuncs->columns(4, "", true); //uiFuncs->text(""); uiFuncs->nextColumn(); uiFuncs->text("Name/Address"); uiFuncs->nextColumn(); uiFuncs->text("Label"); uiFuncs->nextColumn(); uiFuncs->text("Condition"); uiFuncs->nextColumn(); uiFuncs->text(""); uiFuncs->nextColumn(); for (auto& i : data->breakpoints) { Breakpoint* bp = i; bool needUpdate = false; uiFuncs->pushIdPtr(bp); //if (uiFuncs->checkbox("Enabled", &bp->enabled)) // needUpdate = true; if (bp->location.filename) { uiFuncs->inputText("##filename", bp->location.filename, (int)data->maxPath, 0, 0, 0); } else { if (uiFuncs->inputText("##address", bp->location.address, (int)data->maxPath, PDUIInputTextFlags_CharsHexadecimal | PDUIInputTextFlags_EnterReturnsTrue, 0, 0)) needUpdate = true; } uiFuncs->nextColumn(); uiFuncs->text(""); uiFuncs->nextColumn(); uiFuncs->text(""); // no condition for now //if (uiFuncs->inputText("##condition", bp->condition, (int)data->maxPath, PDInputTextFlags_EnterReturnsTrue, 0, 0)) // needUpdate = true; uiFuncs->nextColumn(); if (needUpdate) { // TODO: Add support for file/line PDWrite_eventBegin(writer, PDEventType_setBreakpoint); PDWrite_u64(writer, "address", (uint64_t)strtol(bp->location.address, 0, 16)); //if (bp->condition[0] != 0) // PDWrite_string(writer, "condition", bp->condition); if (bp->id != -1) PDWrite_u32(writer, "id", (uint32_t)bp->id); PDWrite_eventEnd(writer); printf("Sending breakpint\n"); } if (uiFuncs->button("Delete", {0.0f, 0.0f})) { PDWrite_eventBegin(writer, PDEventType_deleteBreakpoint); PDWrite_u32(writer, "id", (uint32_t)bp->id); PDWrite_eventEnd(writer); bp->markDelete = true; } uiFuncs->nextColumn(); uiFuncs->popId(); } // Delete breakpoints that have been marked delete for (auto i = data->breakpoints.begin(); i != data->breakpoints.end(); ++i) { Breakpoint* bp = *i; if (bp->pendingCount > 1) bp->pendingCount++; if (bp->markDelete || bp->pendingCount >= 10) i = data->breakpoints.erase(i); } return 0; }