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_event_begin(writer, PDEventType_SetExceptionLocation); PDWrite_string(writer, "filename", filename); PDWrite_u32(writer, "line", line); PDWrite_event_end(writer); }
static void setExceptionLocation(PDWriter* writer) { PDWrite_event_begin(writer,PDEventType_SetExceptionLocation); PDWrite_u16(writer, "address", pc); PDWrite_u8(writer, "address_size", 2); PDWrite_event_end(writer); }
static void setCallstack(DbgEngPlugin* plugin, PDWriter* writer) { const ULONG maxFrames = 1024; DEBUG_STACK_FRAME frames[maxFrames]; ULONG frameSize = sizeof(frames[0]); ULONG framesFilled = 0; plugin->debugControl->GetStackTrace(0, 0, 0, frames, frameSize, &framesFilled); printf("DbgEngPlugin: setCallstack\n"); if (framesFilled == 0) return; PDWrite_event_begin(writer, PDEventType_setCallstack); PDWrite_array_begin(writer, "callstack"); for (ULONG i = 0; i < framesFilled; ++i) { const DEBUG_STACK_FRAME& frame = frames[i]; PDWrite_array_entry_begin(writer); PDWrite_u64(writer, "address", frame.InstructionOffset); PDWrite_entry_end(writer); } PDWrite_array_end(writer); PDWrite_event_end(writer); }
static void test_lldb(void** state) { (void)state; // we only do the LLDB test on Mac for now #ifdef __APPLE__ PluginData* pluginData; Session* session; int count = 0; assert_true(PluginHandler_addPlugin(OBJECT_DIR, "lldb_plugin")); assert_non_null(pluginData = PluginHandler_getBackendPlugins(&count)[0]); session = Session_createLocal((PDBackendPlugin*)pluginData->plugin, OBJECT_DIR "/crashing_native"); assert_non_null(session); // I hate to do this but there is really no good way to deal with this otherwise (at least currently) Time_sleepMs(800); Session_update(session); Session_update(session); // Expect that we have a crash here and thus are in PDDebugState_stopException state assert_int_equal(session->state, PDDebugState_StopException); // Request locals location. PDWriter* writer = session->currentWriter; PDReader* reader = session->reader; PDWrite_event_begin(writer, PDEventType_GetCallstack); PDWrite_u8(writer, "dummy", 0); PDWrite_event_end(writer); Session_update(session); PDBinaryWriter_finalize(session->currentWriter); PDBinaryReader_initStream(reader, PDBinaryWriter_getData(session->currentWriter), PDBinaryWriter_getSize(session->currentWriter)); uint32_t event; bool foundCallstack = false; while ((event = PDRead_get_event(reader)) != 0) { switch (event) { case PDEventType_SetCallstack: { foundCallstack = true; break; } } } assert_true(foundCallstack); #endif }
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_event_begin(writer, PDEventType_SetCallstack); PDWrite_array_begin(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_array_entry_begin(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_entry_end(writer); } PDWrite_array_end(writer); PDWrite_event_end(writer); }
static void setDisassembly(PDWriter* writer, int start, int instCount) { char temp[65536]; disassembleToBuffer(temp, &start, &instCount); PDWrite_event_begin(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_event_end(writer); }
static int update(void* user_data, PDUI* uiFuncs, PDReader* inEvents, PDWriter* outEvents) { uint32_t event = 0; ThreadsData* data = (ThreadsData*)user_data; data->requestData = false; data->setSelectedThread = false; while ((event = PDRead_get_event(inEvents)) != 0) { switch (event) { case PDEventType_SetThreads: { showInUI((ThreadsData*)user_data, inEvents, uiFuncs); break; } case PDEventType_SetExceptionLocation: { data->requestData = true; break; } } } // Request threads data if (data->setSelectedThread) { PDWrite_event_begin(outEvents, PDEventType_SelectThread); printf("writing thread id %d\n", data->threadId); PDWrite_u32(outEvents, "thread_id", (uint32_t)data->threadId); PDWrite_event_end(outEvents); } if (data->requestData) { PDWrite_event_begin(outEvents, PDEventType_GetThreads); PDWrite_event_end(outEvents); } return 0; }
static int update(void* user_data, PDUI* uiFuncs, PDReader* inEvents, PDWriter* outEvents) { ConsoleData* consoleData = (ConsoleData*)user_data; uint32_t event = 0; (void)event; // test working build /*while ((event = PDRead_get_event(inEvents)) != 0) { switch (event) { case PDEventType_setConsole: { //showInUI((ConsoleData*)user_data, inEvents, uiFuncs); break; } } }*/ showInUI(consoleData, inEvents, uiFuncs); for (size_t i = 0; i < consoleData->scripts.size(); ++i) { PDWrite_event_begin(outEvents, PDEventType_ExecuteConsole); PDWrite_string(outEvents, "command", consoleData->scripts[i]); // TODO: Remove me PDWrite_event_end(outEvents); //free(consoleData->scripts[i]); } consoleData->scripts.clear(); // Request console data PDWrite_event_begin(outEvents, PDEventType_GetConsole); PDWrite_u8(outEvents, "dummy_remove", 0); // TODO: Remove me PDWrite_event_end(outEvents); return 0; }
static int update(void* user_data, PDUI* uiFuncs, PDReader* inEvents, PDWriter* writer) { uint32_t event; DissassemblyData* data = (DissassemblyData*)user_data; data->requestDisassembly = false; while ((event = PDRead_get_event(inEvents)) != 0) { switch (event) { case PDEventType_SetDisassembly: { setDisassemblyCode(data, inEvents); break; } case PDEventType_SetExceptionLocation: { uint64_t location = 0; PDRead_find_u64(inEvents, &location, "address", 0); if (location != data->location) { data->location = location; data->requestDisassembly = true; } PDRead_find_u8(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_event_begin(writer, PDEventType_GetDisassembly); PDWrite_u64(writer, "address_start", (uint64_t)pc); PDWrite_u32(writer, "instruction_count", (uint32_t)BlockSize / 3); PDWrite_event_end(writer); } return 0; }
static PDDebugState update(void* user_data, PDAction action, PDReader* reader, PDWriter* writer) { PluginData* plugin = (PluginData*)user_data; plugin->has_updated_registers = false; plugin->has_updated_exception_location = false; on_action(plugin, action); process_events(plugin, reader, writer); update_events(plugin); if (plugin->has_updated_registers) { log_debug("sending registens\n", ""); PDWrite_event_begin(writer, PDEventType_SetRegisters); PDWrite_array_begin(writer, "registers"); write_status_registers(writer, "flags", plugin->regs.flags); write_register(writer, "pc", 2, plugin->regs.pc, 1); write_register(writer, "sp", 1, plugin->regs.sp, 0); write_register(writer, "a", 1, plugin->regs.a, 0); write_register(writer, "x", 1, plugin->regs.x, 0); write_register(writer, "y", 1, plugin->regs.y, 0); PDWrite_array_end(writer); PDWrite_event_end(writer); } if (plugin->has_updated_exception_location) { PDWrite_event_begin(writer, PDEventType_SetExceptionLocation); PDWrite_u64(writer, "address", plugin->regs.pc); PDWrite_u8(writer, "address_size", 2); PDWrite_event_end(writer); } return plugin->state; }
static bool del_breakpoint(PluginData* data, PDReader* reader, PDWriter* writer) { int32_t id; if (PDRead_find_s32(reader, &id, "id", 0) == PDReadStatus_NotFound) { PDWrite_event_begin(writer, PDEventType_ReplyBreakpoint); PDWrite_string(writer, "error", "No ID being sent for breakpoint"); PDWrite_event_end(writer); return false; } log_debug("deleting breakpoint with id %d\n", id); return del_breakpoint_by_id(data, id); }
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_event_begin(writer, PDEventType_SetTty); PDWrite_string(writer, "tty", buffer); PDWrite_event_end(writer); } }
static void setRegisters(PDWriter* writer) { PDWrite_event_begin(writer, PDEventType_SetRegisters); PDWrite_array_begin(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_array_end(writer); PDWrite_event_end(writer); }
static bool parse_for_callstack(PluginData* data, const char* res, int length, PDReader* reader, PDWriter* writer) { uint16_t callstack_entries[256]; int callstack_count = 0; (void)data; (void)reader; memcpy(TEMP_BUFFER, res, length); TEMP_BUFFER[length] = 0; char* pch = strtok(TEMP_BUFFER, "\n"); while (pch) { const char* startText; const char* endText; if (!find_parentheses(pch, &startText, &endText)) break; // startText points at (xx) // endText points at ) xxxx uint16_t offset = (uint16_t)atoi(startText + 1); uint16_t address = (uint16_t)strtol(endText + 2, 0, 16); callstack_entries[callstack_count++] = address + offset; pch = strtok(0, "\n"); } if (callstack_count == 0) return false; PDWrite_event_begin(writer, PDEventType_SetCallstack); PDWrite_array_begin(writer, "callstack"); for (int i = 0; i < callstack_count; ++i) { PDWrite_array_entry_begin(writer); PDWrite_u16(writer, "address", callstack_entries[i]); PDWrite_entry_end(writer); } PDWrite_array_end(writer); PDWrite_event_end(writer); return true; }
bool parse_disassassembly_call(PluginData* plugin, const char* res, int len, PDReader* reader, PDWriter* writer) { memcpy(TEMP_BUFFER, res, len); TEMP_BUFFER[len] = 0; (void)plugin; (void)reader; // parse the buffer char* pch = strtok(TEMP_BUFFER, "\n"); PDWrite_event_begin(writer, PDEventType_SetDisassembly); PDWrite_array_begin(writer, "disassembly"); bool hasAllDisasembly = false; while (pch) { // expected format of each line: // xxx.. .C:080e A9 22 LDA #$22 char* endOfStream = strstr(pch, "(C:"); char* line = strstr(pch, ".C"); if (endOfStream) { hasAllDisasembly = true; break; } if (!line) break; uint16_t address = (uint16_t)strtol(&line[3], 0, 16); PDWrite_array_entry_begin(writer); PDWrite_u16(writer, "address", address); PDWrite_string(writer, "line", parse_disassembly_line(&line[9])); PDWrite_entry_end(writer); pch = strtok(0, "\n"); } PDWrite_array_end(writer); PDWrite_event_end(writer); return hasAllDisasembly; }
static void toggleBreakpointCurrentLine(PDUISCInterface* sourceFuncs, SourceCodeData* data, PDWriter* writer) { (void)data; (void)writer; PDUI_sc_send_command(sourceFuncs, SCN_TOGGLE_BREAKPOINT, 0, 0); uint32_t currentLine = (uint32_t)PDUI_sc_send_command(sourceFuncs, SCN_GETCURRENT_LINE, 0, 0); printf("currentLine %d\n", currentLine); // TODO: Currenty we don't handly if we set breakpoints on a line we can't PDWrite_event_begin(writer, PDEventType_SetBreakpoint); PDWrite_string(writer, "filename", data->filename); PDWrite_u32(writer, "line", currentLine); PDWrite_event_end(writer); }
static void setSourceFiles(LLDBPlugin* plugin, PDWriter* writer) { if (!plugin->hasValidTarget) return; PDWrite_event_begin(writer, PDEventType_SetSourceFiles); PDWrite_array_begin(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_array_entry_begin(writer); PDWrite_string(writer, "file", filename); PDWrite_entry_end(writer); } } } PDWrite_array_end(writer); PDWrite_event_end(writer); }
static void setThreads(LLDBPlugin* plugin, PDWriter* writer) { uint32_t threadCount = plugin->process.GetNumThreads(); if (threadCount == 0) return; PDWrite_event_begin(writer, PDEventType_SetThreads); PDWrite_array_begin(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_array_entry_begin(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_entry_end(writer); } PDWrite_array_end(writer); PDWrite_event_end(writer); }
static void selectThread(LLDBPlugin* plugin, PDReader* reader, PDWriter* writer) { uint64_t threadId; PDRead_find_u64(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_event_begin(writer, PDEventType_SelectFrame); PDWrite_u32(writer, "frame", getThreadFrame(plugin, threadId)); PDWrite_event_end(writer); }
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_event_begin(writer, PDEventType_SetLocals); PDWrite_array_begin(writer, "locals"); for (uint32_t i = 0; i < count; ++i) { lldb::SBValue value = variables.GetValueAtIndex(i); PDWrite_array_entry_begin(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_entry_end(writer); } PDWrite_array_end(writer); PDWrite_event_end(writer); }
static void get_memory(PluginData* data, PDReader* reader, PDWriter* writer) { uint64_t address; uint64_t size; size_t read_size = 0; PDRead_find_u64(reader, &address, "address_start", 0); PDRead_find_u64(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) { send_command(data, "bank io\n"); } uint8_t* memory = get_memory_internal(data, data->temp_file_full, &read_size, (uint16_t)(address), (uint16_t)(address + size)); if (address == 0xdd00) { send_command(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 // log_debug("c64_vice: sending memory\n", ""); PDWrite_event_begin(writer, PDEventType_SetMemory); PDWrite_u64(writer, "address", address); PDWrite_data(writer, "data", memory + 2, (uint32_t)(read_size - 3)); PDWrite_event_end(writer); // writer takes a copy free(memory); } }
static bool parse_breakpoint_call(PluginData* data, const char* res, int len, PDReader* reader, PDWriter* writer) { Breakpoint* bp = 0; (void)len; (void)reader; const char* breakStrOffset = strstr(res, "BREAK:"); if (!breakStrOffset) return false; int id = atoi(breakStrOffset + 7); const char* address = strstr(breakStrOffset, "C:$"); if (!find_breakpoint_by_id(data, &bp, id)) { bp = create_breakpoint(); add_breakpoint(data, bp); } bp->id = id; if (address) bp->address = (uint16_t)strtol(address + 3, 0, 16); // add data or update existing PDWrite_event_begin(writer, PDEventType_ReplyBreakpoint); PDWrite_u64(writer, "address", bp->address); PDWrite_u32(writer, "id", (uint32_t)id); PDWrite_event_end(writer); log_debug("sending reply back: breakpoint %x - %d\n", bp->address, id); // make sure we got all dat; return strstr(breakStrOffset, "(C:$"); }
static int update(void* user_data, PDUI* uiFuncs, PDReader* reader, PDWriter* writer) { uint32_t event; CallstackData* data = (CallstackData*)user_data; data->request = false; data->setSelectedFrame = false; while ((event = PDRead_get_event(reader)) != 0) { switch (event) { case PDEventType_SetCallstack: { updateCallstack(data, reader); break; } case PDEventType_SelectFrame: { PDRead_find_u32(reader, &data->selectedFrame, "frame", 0); break; } case PDEventType_SetExceptionLocation: { const char* filename = 0; uint32_t line = 0; uint64_t location = 0; PDRead_find_u64(reader, &location, "address", 0); if (location != data->location) { data->location = location; data->request = true; } PDRead_find_string(reader, &filename, "filename", 0); PDRead_find_u32(reader, &line, "line", 0); if (!filename || line == 0) break; if (strcmp(data->filename, filename)) { strcpy(data->filename, filename); data->line = (int)line; data->request = true; } } } } showUI(uiFuncs, data); if (data->setSelectedFrame) { PDWrite_event_begin(writer, PDEventType_SelectFrame); PDWrite_u32(writer, "frame", (uint32_t)data->selectedFrame); PDWrite_event_end(writer); } if (data->request) { PDWrite_event_begin(writer, PDEventType_GetCallstack); PDWrite_event_end(writer); } return 0; }
static int update(void* user_data, PDUI* uiFuncs, PDReader* inEvents, PDWriter* writer) { uint32_t event; (void)uiFuncs; SourceCodeData* data = (SourceCodeData*)user_data; PDUISCInterface* sourceFuncs = uiFuncs->sc_input_text("test", 800, 700, 0, 0); while ((event = PDRead_get_event(inEvents)) != 0) { switch (event) { case PDEventType_SetExceptionLocation: { setExceptionLocation(uiFuncs, sourceFuncs, data, inEvents); data->requestFiles = true; break; } case PDEventType_SetSourceCodeFile: { const char* filename; if (PDRead_find_string(inEvents, &filename, "filename", 0) == PDReadStatus_NotFound) break; setSourceCodeFile(uiFuncs, sourceFuncs, data, filename, 0); break; } case PDEventType_ToggleBreakpointCurrentLine: { toggleBreakpointCurrentLine(sourceFuncs, data, writer); break; } case PDEventType_SetSourceFiles: { // TODO: Store the files data->hasFiles = true; break; } } } updateKeyboard(data, sourceFuncs, uiFuncs); PDUI_sc_update(sourceFuncs); PDUI_sc_draw(sourceFuncs); //showInUI(data, uiFuncs); PDWrite_event_begin(writer, PDEventType_GetExceptionLocation); PDWrite_event_end(writer); if (!data->hasFiles && data->requestFiles) { PDWrite_event_begin(writer, PDEventType_GetSourceFiles); PDWrite_event_end(writer); } return 0; }