Esempio n. 1
0
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);
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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

}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 12
0
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);
    }
}
Esempio n. 13
0
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;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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);
}
Esempio n. 18
0
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);
}
Esempio n. 19
0
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);
}
Esempio n. 20
0
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:$");
}
Esempio n. 23
0
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;
}
Esempio n. 24
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;
}