diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..1f0ef49 --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,580 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 50886d1..5438426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,30 @@ cmake_minimum_required(VERSION 3.28) project(aldbg) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) include_directories(.) +add_compile_options(-Og) + find_package(PkgConfig) -pkg_check_modules(GTKMM gtkmm-3.0) +pkg_check_modules(GTKMM gtkmm-4.0) include_directories(${GTKMM_INCLUDE_DIRS}) link_directories(${GTKMM_LIBRARY_DIRS}) +add_definitions(${GTKMM_CFLAGS_OTHER}) -add_executable(aldbg - main.cpp cpu/cpu.cpp core/attach.cpp core/core.cpp log/log.cpp) +pkg_check_modules(CAPSTONE capstone) -target_link_libraries(aldbg ${GTKMM_LIBRARIES}) \ No newline at end of file +include_directories(${CAPSTONE_INCLUDE_DIRS}) +link_directories(${CAPSTONE_LIBRARY_DIRS}) +add_definitions(${CAPSTONE_CFLAGS_OTHER}) + +pkg_check_modules(ELFPP libelf++) +include_directories(${ELFPP_INCLUDE_DIRS}) +link_directories(${ELFPP_LIBRARY_DIRS}) +add_definitions(${ELFPP_CFLAGS_OTHER}) + +add_executable(aldbg main.cpp) + +target_link_libraries(aldbg ${GTKMM_LIBRARIES} ${CAPSTONE_LIBRARIES} ${ELFPP_LIBRARIES}) \ No newline at end of file diff --git a/aldbg.glade b/aldbg.glade deleted file mode 100644 index 048d2b7..0000000 --- a/aldbg.glade +++ /dev/null @@ -1,850 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - False - False - True - center-on-parent - dialog - True - - - False - vertical - 2 - - - False - end - - - Attach - True - True - True - - - True - True - 0 - - - - - Cancel - True - True - True - - - True - True - 1 - - - - - False - False - 0 - - - - - - True - False - 6 - 5 - - - 30 - True - False - File Path: - - - 0 - 2 - - - - - 30 - True - False - Command Args: - - - 0 - 4 - - - - - 450 - 30 - True - True - - - 1 - 2 - 6 - - - - - 450 - 30 - True - True - - - 1 - 4 - 6 - - - - - True - False - - - 7 - 2 - - - - - True - False - - - 7 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - True - 1 - - - - - - - - - - - - - - - - - - - - - False - center-always - 1280 - 720 - - - True - False - - - True - False - stack - - - False - True - 0 - - - - - True - False - True - - - - True - False - vertical - True - True - - - True - True - regView - - - - - - Registers - - - - - 13 - 0 - 2 - 13 - - - - - True - False - - - Restart - True - True - True - - - False - True - 0 - - - - - Stop - True - True - True - - - False - True - 1 - - - - - Pause - True - True - True - - - False - True - 2 - - - - - Continue - True - True - True - - - False - True - 3 - - - - - Goin - True - True - True - - - False - True - 4 - - - - - Next - True - True - True - - - False - True - 5 - - - - - Tracein - True - True - True - - - False - True - 6 - - - - - Point - True - True - True - - - False - True - 7 - - - - - Escape - True - True - True - - - False - True - 8 - - - - - 0 - 0 - 13 - - - - - True - True - in - - - True - True - codeView - 0 - True - - - - - - Status - - - - 3 - - - - - - - 100 - Address - - - - 0 - - - - - - - 100 - Data - - - - 1 - - - - - - - Disassembly - - - - 2 - - - - - - - - - 0 - 1 - 13 - 9 - - - - - True - True - in - - - True - True - 2 - - - - - - column - - - - - column - - - - - - - 0 - 10 - 13 - 3 - - - - - CPU - CPU - - - - - - True - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Memory - Memory - 1 - - - - - - True - False - - - True - True - True - True - in - - - True - True - True - True - logView - 0 - - - - - - 85 - Time - - - - 0 - - - - - - - Data - - - - 1 - - - - - - - - - 0 - 0 - - - - - Log - Log - 2 - - - - - - True - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Breakpoints - Breakpoints - 3 - - - - - - True - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Call Stack - Call Stack - 4 - - - - - - True - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Symbols - Symbols - 5 - - - - - False - True - 1 - - - - - - - True - False - Aldbg x64 - True - - - Attach - True - True - True - - - - - - diff --git a/aldbg.ui b/aldbg.ui new file mode 100644 index 0000000..c502bb4 --- /dev/null +++ b/aldbg.ui @@ -0,0 +1,676 @@ + + + + + + False + 350 + 600 + + + 1 + + + True + False + vertical + + + + + + + + 0 + true + + + + vertical + 2 + + + 6 + 5 + + + 30 + File Path: + + 0 + 2 + + + + + + 30 + Command Args: + + 0 + 4 + + + + + + 450 + 30 + 1 + + 1 + 2 + 6 + + + + + + 450 + 30 + 1 + + 1 + 4 + 6 + + + + + + + 7 + 2 + + + + + + + 7 + 4 + + + + + + + + + + Attach + 1 + 1 + + + + + Cancel + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1280 + 720 + + + + + stack + + + + + vertical + + + center + + + + + ../interface/icon/arrow-restart.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/control-stop.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/control-pause.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/arrow-run.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/arrow-step-into.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/arrow-step-over.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/arrow-skip.png + + + 1 + 1 + center + center + + + + + + + ../interface/icon/arrow-step-rtr.png + + + 1 + 1 + center + center + + + + + True + True + False + True + popover1 + + + _start() + + + + + + + + 1 + 1 + center + center + Parse + + + + 0 + 0 + 13 + + + + + + 1 + + + CPU + CPU + + + vertical + 0 + 1 + + + 1 + 1 + 1 + + + 1 + regView + + + + + + Register + + + + 0 + + + + + + + Value + + + + 1 + + + + + + + + + 13 + 0 + 2 + 13 + + + + + + 1 + 1 + 1 + + + 1 + + + + True + 0 + 0 + 13 + 10 + + + + + + 1 + 1 + 1 + + + 1 + 2 + + + + + + column + + + + + column + + + + + + 0 + 10 + 13 + 3 + + + + + + + + + + Memory + Segments + + + 1 + 1 + 1 + + + 1 + memView + + + + + + Start Address + + + + 0 + + + + + + + End Address + + + + 1 + + + + + + + Permission + + + + 2 + + + + + + + Offset + + + + 3 + + + + + + + Path + + + + 4 + + + + + + + + + + + + + Log + Log + + + + + 1 + 1 + 1 + + + 1 + 1 + 1 + logView + 0 + + + + + + 85 + Time + + + + 0 + + + + + + + Data + + + + 1 + + + + + + + + 0 + 0 + + + + + + + + + + Breakpoints + Breakpoints + + + 1 + 1 + 1 + + + 1 + + + + + + + + + Call Stack + Call Stack + + + 1 + 1 + 1 + + + 1 + + + + + + + + + Symbols + Symbols + + + 1 + + + + + + + Editor + Memory + + + vertical + + + + + Push + 1 + 1 + + + + + Pull + 1 + 1 + + + + + 450 + 1 + center + + 1 + 2 + 6 + + + + + + Jump + 1 + 1 + + + + + + + 1 + 1 + 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + Attach + 1 + 1 + + + + + center + 1 + + + center + Aldbg + + + + + + + + + + diff --git a/core/Core.hpp b/core/Core.hpp new file mode 100644 index 0000000..43cfc43 --- /dev/null +++ b/core/Core.hpp @@ -0,0 +1,964 @@ +// +// Created by acite on 5/1/24. +// + +#ifndef _H_CORE +#define _H_CORE 1 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "MemoryMap.hpp" +#include + +#include +#include +#include +#include + +#include + +#define WORD_SIZE 8 + +enum Msg{ + MSG_PAUSE = 0, + MSG_STOP = 1, + MSG_CONTINUE = 2, + MSG_STARTUP = 3, + MSG_REG = 4, + MSG_QUIT = 5, + MSG_LOG = 6, + MSG_ASM = 7, + MSG_TITLE = 8, + MSG_STEPINTO = 9, + MSG_MEMORY = 10, + MSG_SELECT = 11, + MSG_CURRENTSYMBOL = 12, + MSG_RESTART = 13, + MSG_BREAK = 14, + MSG_STEPOVER = 15, + MSG_SYMBOLS = 16, + MSG_SWITCHSYMBOL= 17, + MSG_NONSYM = 18, + MSG_PARSE = 19, + MSG_INSYM = 20, + MSG_DELBREAK = 21, + MSG_SWITCHMODULE= 22, + MSG_GETBREAKS = 23, + MSG_CALLSTACK = 24, + MSG_BREAKONCE = 25 +}; + +struct DebugCommand +{ + char id; + void* param; +}; + +struct BreakPoint +{ + uint64_t addr; + bool once; + uint64_t origin; + uint16_t size; + + bool enable; +}; + +struct Symbol{ + char name[255]; + uint64_t address; + uint64_t size; + uint64_t base; +}; + +struct CallstackStruct +{ + uint64_t callPoint; + uint64_t stackBase; + Symbol symbol; + char module[255]; + int depth; +}; + +class Core{ +private: + std::map _breakPoints; + int _ep = -1; + uint64_t _lastRip = 0; + int _counter = 0; + uint64_t _needToRestore = 0; + +public: + const uint64_t int3 = 0xCCCCCCCCCCCCCCCC; + + int pipe = -1; + int remotePipe = -1; + + user_regs_struct regs; + std::vector symbols; + std::vector staticSymbols; + std::unordered_map> symbolMap; + + Symbol currentSymbol{}; + + void PeekTexts(uint64_t* data, uint64_t words) const + { + auto addr = _lastRip; + + for(uint64_t i=0;i= codeAddr && k.second.addr < codeAddr + codeSize) + { + uint64_t localOffset = k.second.addr - codeAddr; + auto px = reinterpret_cast(codeData + localOffset); + uint64_t mask = 0xFFFFFFFFFFFFFFFF << k.second.size * 8; + + *px = (k.second.origin & (~mask)) | ((*px) & mask); + } + } + } + */ + uint64_t GetBaseAddress() + { + if(_map == nullptr) return 0; + + for(int i=0;i<_map->Size();i++) + { + auto j = _map->GetItem(i); + if(_path == j.path) + { + return j.startAddress; + } + } + return 0; + } + + uint64_t GetBaseAddress(const std::string& module) + { + if(_map == nullptr) return 0; + + for(int i=0;i<_map->Size();i++) + { + auto j = _map->GetItem(i); + if(module == j.path) + { + return j.startAddress; + } + } + return 0; + } + + uint64_t GetEndAddress(const std::string& module) + { + if(_map == nullptr) return 0; + uint64_t endAddr = 0; + + for(int i=0;i<_map->Size();i++) + { + auto j = _map->GetItem(i); + if(module == j.path) + { + endAddr = j.endAddress; + } + } + return endAddr; + } + + uint64_t GetEntryPoint() + { + int fd = open(_path.c_str(), O_RDONLY); + if(fd < 0) return 0; + + elf::elf ef(elf::create_mmap_loader(fd)); + return ef.get_hdr().entry; + } + + std::vector GetSymbols(const std::string& module) + { + std::vector tr; + std::map r; + + uint64_t lbase = GetBaseAddress(module); + uint64_t ebase = GetEndAddress(module); + + if(symbolMap.contains(module)) + { + tr = symbolMap[module]; + } + else + { + int fd = open(module.c_str(), O_RDONLY); + if(fd < 0) return {}; + + elf::elf ef(elf::create_mmap_loader(fd)); + for (const auto& section : ef.sections()) { + if (section.get_hdr().type == elf::sht::symtab) { + + const auto& lsymbols = section.as_symtab(); + for (const auto& symbol : lsymbols) { + if (symbol.get_data().type() == elf::stt::func && symbol.get_data().value != 0) { + // A symbol with zero address maybe an extern symbol in (.so) + // We will not place it in local module symbol list + // Because we fill find its body in the symbol table of another modules + Symbol h{}; + strcpy(h.name, symbol.get_name().c_str()); + h.address = symbol.get_data().value; + h.size = symbol.get_data().size; + h.base = lbase; + r.emplace(symbol.get_name(), h); + } + } + } + } + + for (const auto& section : ef.sections()) { + if (section.get_hdr().type == elf::sht::dynsym) { + const auto& lsymbols = section.as_symtab(); + for (const auto& symbol : lsymbols) { + if (symbol.get_data().type() == elf::stt::func && symbol.get_data().value != 0 && (!r.contains(symbol.get_name()))) { + Symbol h{}; + strcpy(h.name, symbol.get_name().c_str()); + h.address = symbol.get_data().value; + h.size = symbol.get_data().size; + h.base = lbase; + r.emplace(symbol.get_name(), h); + } + } + } + } + for(const auto& j : r) + { + tr.emplace_back(j.second); + } + + for(auto &k : tr) + { + if(k.size == 0) // Unmarked Symbol + { + // Find a symbol following behind it + uint64_t addr = 0xffffffffffffffff; + for(auto &j : tr) + { + if(j.address > k.address && j.address < addr) addr = j.address; + } + + if(addr != 0xffffffffffffffff){ k.size = addr - k.address; continue; } + + // Found no Symbol + // Set its size to the end of its section + for (const auto& section : ef.sections()) + { + if(k.address > section.get_hdr().addr && k.address < section.get_hdr().addr + section.size()) + { + k.size = section.get_hdr().addr + section.size() - k.address; + } + } + } + } + + symbolMap.emplace(module, tr); + } + + for(const auto &k : staticSymbols) + { + if(k.address >= lbase && k.address < ebase) + { + bool within = false; + for(const auto &j : tr) + { + if(k.address >= j.address + j.base && k.address < j.address + j.size + j.base) + { + within = true; + break; + } + } + if(!within) tr.emplace_back(k); + } + } + + return tr; + } + + void InsertBreakPoint(uint64_t addr, bool once = true) + { + if(_breakPoints.contains(addr)) return; + + auto ins = disassemblyFrom(addr, 1, 0); + + BreakPoint bp{}; + bp.once = once; + bp.addr = addr; + bp.origin = ptrace(PTRACE_PEEKTEXT, _process, addr, NULL); + bp.size = ins[0].size; + if(bp.size > 8) bp.size = 8; + bp.enable = true; + + uint64_t mask = 0xFFFFFFFFFFFFFFFF << bp.size * 8; + + uint64_t int3_data = (bp.origin & mask) | (int3 & (~mask)); + ptrace(PTRACE_POKETEXT, _process, addr, int3_data); + + _breakPoints.emplace(bp.addr, bp); + } + + void DisableBreakPoint(uint64_t addr) + { + if(!_breakPoints.contains(addr)) return; + + _breakPoints[addr].enable = false; + + uint64_t origin = ptrace(PTRACE_PEEKTEXT, _process, addr, NULL); + uint64_t mask = 0xFFFFFFFFFFFFFFFF << _breakPoints[addr].size * 8; + + ptrace(PTRACE_POKETEXT, _process, addr, + (_breakPoints[addr].origin & (~mask)) | (origin & mask)); + } + + void RestoreBreakPoint(uint64_t addr) + { + if(!_breakPoints.contains(addr)) return; + + _breakPoints[addr].enable = true; + uint64_t origin = ptrace(PTRACE_PEEKTEXT, _process, addr, NULL); + + uint64_t mask = 0xFFFFFFFFFFFFFFFF << _breakPoints[addr].size * 8; + uint64_t int3_data = (origin & mask) | (int3 & (~mask)); + + ptrace(PTRACE_POKETEXT, _process, addr, int3_data); + } + + void DeleteBreakPoint(uint64_t addr) + { + if(!_breakPoints.contains(addr)) return; + + DisableBreakPoint(addr); + _breakPoints.erase(addr); + } + + bool ContainsBreakPoint(uint64_t addr) + { + return _breakPoints.contains(addr); + } + + std::vector GetBreakpoints() + { + std::vector r; + for(const auto &k : _breakPoints) + { + r.emplace_back(k.second); + } + return r; + } + + void TryContinue() + { + if(_needToRestore == 0) + ptrace(PTRACE_CONT, _process, NULL, NULL); + else + { + ptrace(PTRACE_SINGLESTEP, _process, NULL, NULL); + _temporaryStop = true; + } + } + + void queueMessage(char id, void* param) const + { + DebugCommand msg{id, param}; + if(pipe != -1) + { + write(remotePipe, &msg, sizeof(DebugCommand)); + } + } + + static bool ContainerContains(const std::vector& c, const std::string& e) + { + for(const auto &k : c) + { + if(k == e) return true; + } + return false; + } + + /// disassembly from an address + /// \param address + /// \param cc + /// \param sz cc and sz cannot be both 0 at the same time + /// \return + [[nodiscard]] std::vector disassemblyFrom(uint64_t address, int cc, uint32_t sz, const std::vector& end = {}, bool make = false) + { + if(cc == 0 && sz == 0) return {}; + uint64_t originAddress = address; + + csh handle; + cs_insn *insn; + size_t count; + std::vector r; + uint64_t data[4]; + + if(!cc) cc = INT_MAX; + if(!sz) sz = 0xFFFFFFFF; + + if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) + return {}; + cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + for(int i=0, p=0;i= staticSymbols[i].address && originAddress < staticSymbols[i].address + staticSymbols[i].size) + { + staticSymbols.erase(staticSymbols.begin() + i); + i--; + } + } + + Symbol sym{}; + sym.address = originAddress; + sym.base = 0; + sprintf(sym.name, "call_%lx", sym.address); + for(const auto &k : r) + { + sym.size += k.size; + } + staticSymbols.emplace_back(sym); + } + + return std::move(r); + } + + bool GetMapEntire(uint64_t addr, MapEntire& ent) + { + for(int i=0;i<_map->Size();i++) // Read Text Data + { + auto item = _map->GetItem(i); + if(item.startAddress == addr) { + ent = item; + return true; + } + } + + return false; + } +private: + bool entryBreak = true; + + int _process = -1; + pthread_t _th = 0; + std::string _path; + std::string _argv; + std::string _module; + std::shared_ptr _map = nullptr; + bool _temporaryStop = false; + + bool _trapped = false; + + void sendMessage(char id, void* param) const { + DebugCommand msg{id, param}; + if (pipe != -1) { + write(pipe, &msg, sizeof(DebugCommand)); + } + } + + void debugHandler() + { + char str_buffer[128]; + std::vector me; + + int fk = fork(); + if(fk == 0) + { + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1) { + perror("ptrace"); + exit(1); + } + + char env[255]; + strcpy(env, _path.c_str()); + env[_path.rfind('/') + 1] = 0; + + chdir(env); + execl(_path.c_str(), _argv.c_str(), NULL); + perror("execve"); + exit(1); + } + + _process = fk; + + sprintf(str_buffer, "%s - [/proc/%d/]", _argv.c_str(), _process); + sendMessage(MSG_TITLE, str_buffer); + + int status = 0; + long err; + char buffer[32]; + + _ep = epoll_create1(0); + auto ev1 = epoll_event{.events = EPOLLIN}; + ev1.data.fd = pipe; + epoll_ctl(_ep, EPOLL_CTL_ADD, pipe, &ev1); + sendMessage(MSG_STARTUP, nullptr); // Notify Main Thread + + while(true) + { + // Handle User IO Message + int n = epoll_wait(_ep, &ev1, 1, 1); + if(n > 0) + { + auto sz = read(pipe, buffer, sizeof(DebugCommand)); + if(sz != sizeof(DebugCommand)) continue; + + auto msg = (DebugCommand*)buffer; + switch (msg->id) { + case MSG_PAUSE: + kill(_process, SIGTRAP); + break; + case MSG_STOP: + kill(_process, SIGKILL); + sendMessage(MSG_STOP, nullptr); + return; + case MSG_RESTART: + kill(_process, SIGKILL); + sendMessage(MSG_RESTART, nullptr); + return; + case MSG_CONTINUE: + if(_trapped) { + TryContinue(); + if(err == -1) perror("ptrace"); + sendMessage(MSG_CONTINUE, nullptr); + _trapped = false; + } + break; + case MSG_STEPINTO: + if(_trapped) { + err = ptrace(PTRACE_SINGLESTEP, _process, NULL, NULL); + sendMessage(MSG_CONTINUE, nullptr); + _trapped = false; + break; + } + case MSG_STEPOVER: + { + auto ins = disassemblyFrom(_lastRip, 2, 0); + + if(ins.size() < 2 || !std::string(ins[0].mnemonic).contains("call")){ + err = ptrace(PTRACE_SINGLESTEP, _process, NULL, NULL); + sendMessage(MSG_CONTINUE, nullptr); + _trapped = false; + break; + } + if(!_breakPoints.contains(ins[1].address)) + InsertBreakPoint(ins[1].address, true); + + TryContinue(); + sendMessage(MSG_CONTINUE, nullptr); + _trapped = false; + break; + } + case MSG_SWITCHSYMBOL: + { + auto b = reinterpret_cast(msg->param); + auto ci = disassemblyFrom(b->base + b->address, 0, b->size); + auto ch = new std::vector; + *ch = ci; + + strcpy(currentSymbol.name, b->name); + currentSymbol.address = b->address; + currentSymbol.size = b->size; + currentSymbol.base = b->base; + // currentSymbol + sendMessage(MSG_ASM, ch); + sendMessage(MSG_CURRENTSYMBOL, nullptr); + sendMessage(MSG_SELECT, nullptr); + break; + } + case MSG_PARSE: + { + for(int i=0;i<_map->Size();i++) // Read Text Data + { + auto item = _map->GetItem(i); + me.emplace_back(item); + if(_lastRip >= item.startAddress && _lastRip < item.endAddress) + { + auto moduleBase = GetBaseAddress(_module); + + auto ci = disassemblyFrom(_lastRip, 10000, item.endAddress - _lastRip, {"int3", "endbr64"}, true); + if(ci.empty()) break; + + auto ch = new std::vector; + *ch = ci; + + sendMessage(MSG_ASM, ch); + + sprintf(str_buffer, "%s - [/proc/%d/] - [%s] at %lx", + _argv.c_str(), _process, _module.c_str(), moduleBase); + + sprintf(currentSymbol.name, "call_%lx", _lastRip); + currentSymbol.address = _lastRip; + currentSymbol.size = item.endAddress - _lastRip; + currentSymbol.base = moduleBase; + + symbols = GetSymbols(_module); + sendMessage(MSG_INSYM, nullptr); + sendMessage(MSG_TITLE, str_buffer); + sendMessage(MSG_SELECT, nullptr); + sendMessage(MSG_CURRENTSYMBOL, nullptr); + sendMessage(MSG_SYMBOLS, nullptr); + } + } + break; + } + case MSG_BREAK: + { + auto addr = (uint64_t)msg->param; + InsertBreakPoint(addr, false); + break; + } + case MSG_BREAKONCE: + { + auto addr = (uint64_t)msg->param; + InsertBreakPoint(addr, true); + break; + } + case MSG_DELBREAK: + { + auto addr = (uint64_t)msg->param; + DeleteBreakPoint(addr); + break; + } + case MSG_SWITCHMODULE: + { + _module = (char*)msg->param; + auto moduleBase = GetBaseAddress(_module); + symbols = GetSymbols(_module); + if(symbols.empty()) break; + currentSymbol = symbols[0]; + + sprintf(str_buffer, "%s - [/proc/%d/] - [%s] at %lx", _argv.c_str(), _process, _module.c_str(), moduleBase); + + auto ci = disassemblyFrom(moduleBase + currentSymbol.address, 0, currentSymbol.size); + auto ch = new std::vector; + *ch = ci; + + sendMessage(MSG_ASM, ch); + sendMessage(MSG_TITLE, str_buffer); + sendMessage(MSG_SYMBOLS, nullptr); + sendMessage(MSG_CURRENTSYMBOL, nullptr); + sendMessage(MSG_SELECT, nullptr); + + delete[](char*)msg->param; + break; + } + case MSG_GETBREAKS: + { + auto dst = new cs_insn[_breakPoints.size()]; + int p = 0; + + for(const auto &k : GetBreakpoints()) + { + auto ins = disassemblyFrom(k.addr, 1, 0); + dst[p++] = ins[0]; + } + sendMessage(MSG_GETBREAKS, dst); + break; + } + case MSG_CALLSTACK: + { + GetCallStack(); + break; + } + default: + break; + } + } + + // Handle Debug Process Signal + auto r = waitpid(_process, &status, WNOHANG); + if(r == 0) continue; + + if(WIFEXITED(status) || WIFSIGNALED(status)) break; + int signal_number = WSTOPSIG(status); + + switch (signal_number) { + case SIGTRAP: { + _trapped = true; + _map = std::make_shared(_process); + regs = {}; + + me.clear(); + ptrace(PTRACE_GETREGS, _process, NULL, ®s); + + + if(entryBreak) // If this is the first time enter trap, insert int3 break point to Entry Point + { + entryBreak = false; + _trapped = false; + auto base = GetBaseAddress(); + uint64_t entryPoint = base + GetEntryPoint(); + InsertBreakPoint(entryPoint); + + ptrace(PTRACE_CONT, _process, NULL, NULL); + break; + } + + bool couldBeBp = true; + if(_needToRestore != 0) + { + RestoreBreakPoint(_needToRestore); + _needToRestore = 0; + couldBeBp = false; + } + + if(_temporaryStop){ + _trapped = false; + _temporaryStop = false; + ptrace(PTRACE_CONT, _process, NULL, NULL); + break; + } + + if(_breakPoints.contains(regs.rip - 1) && couldBeBp) + { + // Reduce RIP by 1 + regs.rip -= 1; + ptrace(PTRACE_SETREGS, _process, NULL, ®s); + // Restore origin data + if(_breakPoints[regs.rip].once) + DeleteBreakPoint(regs.rip); + else + { + DisableBreakPoint(regs.rip); + _needToRestore = regs.rip; + } + } + + _lastRip = regs.rip; + bool updateModule = false; + bool ridSymbols = true; + + for(int i=0;i<_map->Size();i++) // Read Text Data + { + auto item = _map->GetItem(i); + me.emplace_back(item); + if(regs.rip >= item.startAddress && regs.rip < item.endAddress) + { + if(_module != item.path) updateModule = true; + + _module = item.path; + auto moduleBase = GetBaseAddress(_module); + symbols = GetSymbols(_module); + + for(auto b : symbols) + { + // If Rip is between the start and the end of a module + if(regs.rip >= b.base + b.address && regs.rip < b.base + b.address + b.size) + { + ridSymbols = false; + if (currentSymbol.address == b.address) break; + currentSymbol = b; + + auto ci = disassemblyFrom(moduleBase + b.address, 0, b.size); + auto ch = new std::vector; + *ch = ci; + + sendMessage(MSG_ASM, ch); + sendMessage(MSG_CURRENTSYMBOL, nullptr); + } + } + if(ridSymbols) { // ridSymbols keeps true means RIP isn't in any Symbol + sprintf(str_buffer, "%s - [/proc/%d/] - [%s] at %lx (!Symbol table Escaping!)", + _argv.c_str(), _process, _module.c_str(), moduleBase); + sendMessage(MSG_NONSYM, nullptr); + + strcpy(currentSymbol.name, "[Out of Symbol Table]"); + currentSymbol.address = _lastRip; + currentSymbol.size = item.endAddress - _lastRip; + currentSymbol.base = moduleBase; + sendMessage(MSG_CURRENTSYMBOL, nullptr); + } + else{ + sprintf(str_buffer, "%s - [/proc/%d/] - [%s] at %lx", _argv.c_str(), _process, _module.c_str(), moduleBase); + sendMessage(MSG_INSYM, nullptr); + } + sendMessage(MSG_TITLE, str_buffer); + } + } + + sendMessage(MSG_PAUSE, nullptr); + sendMessage(MSG_REG, ®s); + sendMessage(MSG_MEMORY, &me); + if(updateModule) sendMessage(MSG_SYMBOLS, nullptr); + sendMessage(MSG_SELECT, nullptr); + break; + } + case SIGTERM: + kill(_process, SIGKILL); + waitpid(_process, &status, 0); + _process = -1; + sendMessage(MSG_STOP, nullptr); + return; + default: + break; + } + } + + sendMessage(MSG_STOP, nullptr); + } + +public: + explicit Core(const std::string& f, const std::string& a) + { + _path = f; + _argv = a; + + auto lambda = [](void *arg) { + Core* instance = static_cast(arg); + instance->debugHandler(); + return (void*)nullptr; + }; + + pthread_create(&_th, nullptr, lambda, this); + } + + ~Core() + { + if(_process > 0) + { + pthread_join(_th, nullptr); + // delete[] codeData; + close(_ep); + } + } + + bool Status() const + { + return _trapped; + } + + + + std::optional GetSymbolAt(uint64_t address, std::string &mod) + { + auto _m = _map->GetModules(); + for(const auto &k : _m) + { + if(address >= k.startAddress && address < k.endAddress) + { + mod = k.path; + for(const auto &l : GetSymbols(k.path)) + { + if(address >= l.address + l.base && address < l.address + l.size + l.base) + { + return l; + } + } + } + } + + return std::nullopt; + } + + void GetCallStack() + { + std::vector> callPoints; + auto r = new std::stack; + uint64_t cbp = regs.rbp; + + callPoints.emplace_back(regs.rip, cbp); + + while(cbp) + { + callPoints.emplace_back(ptrace(PTRACE_PEEKDATA, _process, cbp + 8, NULL), ptrace(PTRACE_PEEKDATA, _process, cbp, NULL)); + cbp = ptrace(PTRACE_PEEKDATA, _process, cbp, NULL); + } + int cc = 0; + for(const auto &k : callPoints) + { + std::string mod; + auto s = GetSymbolAt(k.first, mod); + + Symbol s2{}; + strcpy(s2.name, ""); + if(s.has_value()) s2 = s.value(); + + CallstackStruct e{}; + e.callPoint = k.first; + sprintf(e.module, "<%s>", mod.empty() ? "???" : mod.c_str()); + e.symbol = s2; + e.stackBase = k.second; + e.depth = cc++; + + r->emplace(e); + } + CallstackStruct e{}; + e.depth = _process; + r->emplace(e); + sendMessage(MSG_CALLSTACK, r); + } +}; + +#endif \ No newline at end of file diff --git a/core/MemoryMap.hpp b/core/MemoryMap.hpp new file mode 100644 index 0000000..954de05 --- /dev/null +++ b/core/MemoryMap.hpp @@ -0,0 +1,133 @@ + +#include + +#ifndef _H_MEMORYMAP +#define _H_MEMORYMAP 1 + +static std::vector split(const std::string& str, char delimiter) { + std::vector tokens; + std::string token; + std::stringstream ss(str); + + while (std::getline(ss, token, delimiter)) { + tokens.push_back(token); + } + + return tokens; +} + +enum Access{ + READ = 0x01, + WRITE = 0x02, + EXECUTE = 0x04, + PRIVATE = 0x08, + SHARED = 0x10 +}; + +struct MapEntire +{ + uint64_t startAddress; + uint64_t endAddress; + uint8_t access = 0; + uint32_t offset; + char path[512] = {0}; + + MapEntire() + { + startAddress = 0; + endAddress = 0; + offset = 0; + } + + explicit MapEntire(const std::string& src) + { + auto e = split(src, ' '); + for(int i=0;i& dst, const std::string& path) + { + auto f = fopen(path.c_str(), "r"); + if(!f){ perror("fopen()"); return false; } + + dst.clear(); + char line[1024]; + while(fgets(line, 1024, f)) + { + dst.emplace_back(line); + } + fclose(f); + + return true; + } + +private: + char _path[255] = {0}; + std::vector _content; + +public: + explicit MemoryMap(int pid) + { + sprintf(_path, "/proc/%d/maps", pid); + readAll(_content, _path); + } + + MapEntire GetItem(int index) + { + auto u = MapEntire(_content[index]); + return u; + } + + size_t Size() + { + return _content.size(); + } + + std::vector GetModules() + { + std::vector r; + for(int i=0;i - -using namespace Gtk; - -extern Button* bAttach; -extern Dialog* dialogAttach; -extern Window* MainWindow; - -void button_attach() -{ - dialogAttach->show(); -} - -void button_exec() -{ - int fk = fork(); - if(fk == 0) - { - execl("/usr/bin/netstat", "netstat" ,"-tupln", NULL); - return; - } -} \ No newline at end of file diff --git a/core/core.cpp b/core/core.cpp deleted file mode 100644 index 3a0eb7e..0000000 --- a/core/core.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// -// Created by acite on 5/1/24. -// - diff --git a/cpu/cpu.cpp b/cpu/cpu.cpp deleted file mode 100644 index 68551e9..0000000 --- a/cpu/cpu.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Created by acite on 5/1/24. -// - -#include "cpu.h" - -using namespace std; -using namespace Gtk; - -extern TreeView* codeView; -extern Glib::RefPtr codeViewStore; - -void add_row(const string& addr, - const string& data, - const string& dasm, - const string& sts - ){ - auto mm = codeViewStore->append(); - Gtk::TreeModel::Row row = *mm; - - row.set_value(0, addr); - row.set_value(1, data); - row.set_value(2, dasm); - row.set_value(3, sts); -} - -void set_row_status(uint64_t index_addr, const string& sts) -{ - string addr; - for(auto i : codeViewStore->children()) - { - i.get_value(0, addr); - if(to_string(index_addr) == addr) - { - i.set_value(3, sts); - break; - } - } -} diff --git a/cpu/cpu.h b/cpu/cpu.h deleted file mode 100644 index 66711bc..0000000 --- a/cpu/cpu.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Created by acite on 5/1/24. -// - -#ifndef ALDBG_CPU_H -#define ALDBG_CPU_H - -#include -#include -#include - -void add_row(const std::string &addr, - const std::string &data, - const std::string &dasm, - const std::string &sts -); - -void set_row_status(uint64_t index_addr, const std::string& sts); - -#endif //ALDBG_CPU_H diff --git a/interface/callstack/CallstackView.hpp b/interface/callstack/CallstackView.hpp new file mode 100644 index 0000000..5f12ecb --- /dev/null +++ b/interface/callstack/CallstackView.hpp @@ -0,0 +1,272 @@ + +#include + +namespace +{ + class CallstackItem + { + public: + CallstackItem() = default; + CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth); + CallstackItem(Glib::ustring callPoint, const std::vector& children); + CallstackItem(const CallstackItem& src) = default; + CallstackItem(CallstackItem&& src) noexcept = default; + CallstackItem& operator=(const CallstackItem& src) = default; + CallstackItem& operator=(CallstackItem&& src) noexcept = default; + ~CallstackItem() = default; + + Glib::ustring callPoint; + Glib::ustring stackBase; + Glib::ustring symbol; + Glib::ustring module; + Glib::ustring depth; + std::vector m_children; + }; // CallstackItem + + CallstackItem::CallstackItem(Glib::ustring callPoint, Glib::ustring stackBase, Glib::ustring symbol, Glib::ustring module, Glib::ustring depth) + : callPoint(std::move(callPoint)), stackBase(std::move(stackBase)), symbol(std::move(symbol)), module(std::move(module)), depth(std::move(depth)) + { } + + CallstackItem::CallstackItem(Glib::ustring callPoint, + const std::vector& children) + : callPoint(std::move(callPoint)), m_children(children) + { } +} + +class CallstackView : public Gtk::ColumnView +{ +protected: + class ModelColumns : public Glib::Object + { + public: + std::vector m_children; + Glib::ustring callPoint; + Glib::ustring stackBase; + Glib::ustring symbol; + Glib::ustring module; + Glib::ustring depth; + + static Glib::RefPtr create(const CallstackItem& item) + { + + return Glib::make_refptr_for_instance(new ModelColumns(item)); + } + + protected: + explicit ModelColumns(const CallstackItem& item) + : m_children(item.m_children), callPoint(item.callPoint), + stackBase(item.stackBase), symbol(item.symbol), + module(item.module), depth(item.depth) + { } + }; // ModelColumns + +protected: + static Glib::RefPtr create_model( + const Glib::RefPtr& item) + { + auto col = std::dynamic_pointer_cast(item); + if (col && col->m_children.empty()) + return {}; + + auto result = Gio::ListStore::create(); + const std::vector& children = col ? col->m_children : std::vector(); + for (const auto& child : children) + result->append(ModelColumns::create(child)); + return result; + } + + Glib::RefPtr m_TreeListModel; + Glib::RefPtr m_TreeSelection; + Glib::RefPtr> _store; + +public: + void append_group(const std::string &name, const std::vector &g) + { + CallstackItem k(name, g); + if(_store) _store->append(ModelColumns::create(k)); + } + + void clear() + { + _store->remove_all(); + } + + CallstackView (BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::ColumnView(cobject) + { + auto root = create_model({}); + + m_TreeListModel = Gtk::TreeListModel::create(root, + sigc::ptr_fun(&CallstackView::create_model), false, true); + m_TreeSelection = Gtk::MultiSelection::create(m_TreeListModel); + set_model(m_TreeSelection); + { + auto factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CallstackView::on_setup_keylabel)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CallstackView::on_bind_callPoint)); + auto column = Gtk::ColumnViewColumn::create("Call Point", factory); + column->set_fixed_width(200); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CallstackView::on_setup_label)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CallstackView::on_bind_stackBase)); + + column = Gtk::ColumnViewColumn::create("Stack Base", factory); + column->set_expand(); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CallstackView::on_setup_label)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CallstackView::on_bind_symbol)); + + column = Gtk::ColumnViewColumn::create("Symbol", factory); + column->set_expand(); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CallstackView::on_setup_label)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CallstackView::on_bind_module)); + + column = Gtk::ColumnViewColumn::create("Module", factory); + column->set_expand(); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CallstackView::on_setup_label)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CallstackView::on_bind_depth)); + + column = Gtk::ColumnViewColumn::create("Depth", factory); + column->set_expand(); + append_column(column); + } + + _store = std::dynamic_pointer_cast>(root); + } + + void on_setup_keylabel( + const Glib::RefPtr& list_item) + { + // Each ListItem contains a TreeExpander, which contains a Label. + // The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday(). + auto expander = Gtk::make_managed(); + auto label = Gtk::make_managed(); + label->set_halign(Gtk::Align::START); + expander->set_child(*label); + list_item->set_child(*expander); + } + + void on_setup_label( + const Glib::RefPtr& list_item) + { + // Each ListItem contains a TreeExpander, which contains a Label. + // The Label shows the ModelColumns::m_holiday_name. That's done in on_bind_holiday(). + auto label = Gtk::make_managed(); + label->set_halign(Gtk::Align::START); + list_item->set_child(*label); + } + + void on_bind_callPoint( + const Glib::RefPtr& list_item) + { + auto row = std::dynamic_pointer_cast(list_item->get_item()); + if (!row) + return; + auto col = std::dynamic_pointer_cast(row->get_item()); + if (!col) + return; + auto expander = dynamic_cast(list_item->get_child()); + if (!expander) + return; + expander->set_list_row(row); + auto label = dynamic_cast(expander->get_child()); + if (!label) + return; + label->set_text(col->callPoint); + } + + void on_bind_stackBase( + const Glib::RefPtr& list_item) + { + auto row = std::dynamic_pointer_cast(list_item->get_item()); + if (!row) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_visible(!row->is_expandable()); + if (row->is_expandable()) + return; + + auto col = std::dynamic_pointer_cast(row->get_item()); + if (!col) + return; + label->set_text(col->stackBase); + } + + void on_bind_symbol( + const Glib::RefPtr& list_item) + { + auto row = std::dynamic_pointer_cast(list_item->get_item()); + if (!row) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_visible(!row->is_expandable()); + if (row->is_expandable()) + return; + + auto col = std::dynamic_pointer_cast(row->get_item()); + if (!col) + return; + label->set_text(col->symbol); + } + + void on_bind_module( + const Glib::RefPtr& list_item) + { + auto row = std::dynamic_pointer_cast(list_item->get_item()); + if (!row) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_visible(!row->is_expandable()); + if (row->is_expandable()) + return; + + auto col = std::dynamic_pointer_cast(row->get_item()); + if (!col) + return; + label->set_text(col->module); + } + + void on_bind_depth( + const Glib::RefPtr& list_item) + { + auto row = std::dynamic_pointer_cast(list_item->get_item()); + if (!row) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_visible(!row->is_expandable()); + if (row->is_expandable()) + return; + + auto col = std::dynamic_pointer_cast(row->get_item()); + if (!col) + return; + label->set_text(col->depth); + } +}; diff --git a/interface/cpu/CPUView.hpp b/interface/cpu/CPUView.hpp new file mode 100644 index 0000000..f980132 --- /dev/null +++ b/interface/cpu/CPUView.hpp @@ -0,0 +1,358 @@ +// +// Created by acite on 5/1/24. +// + +#include +#include + +#include "../../core/Core.hpp" + +namespace { + class CPUModelColumns : public Glib::Object { + public: + Glib::PropertyProxy propertyBroke() { return _broke.get_proxy(); } + Glib::PropertyProxy> propertyClasses() { return _classes.get_proxy(); } + + Glib::ustring Address; + Glib::ustring Data; + Glib::ustring Disassembly; + Glib::RefPtr BindingToCheckbutton = nullptr; + + Glib::RefPtr BindingToAddress = nullptr; + Glib::RefPtr BindingToData = nullptr; + Glib::RefPtr BindingToDisassembly = nullptr; + std::shared_ptr core = nullptr; + + + static Glib::RefPtr create(bool broke, const Glib::ustring &address, + const Glib::ustring &data, const Glib::ustring &disassembly, std::shared_ptr _core){ + return Glib::make_refptr_for_instance( + new CPUModelColumns(broke, address, data, disassembly, std::move(_core))); + } + + protected: + CPUModelColumns(bool broke, Glib::ustring address, + Glib::ustring data, Glib::ustring disassembly, std::shared_ptr _core) + : Glib::ObjectBase(typeid(CPUModelColumns)), + Address(std::move(address)), Data(std::move(data)), Disassembly(std::move(disassembly)), + _broke(*this, "broke", broke), + _classes(*this, "highlighted", {}), core(std::move(_core)){ + propertyBroke().signal_changed().connect( + sigc::mem_fun(*this, &CPUModelColumns::on_fixed_changed)); + } + + Glib::Property _broke; + Glib::Property> _classes; + + void on_fixed_changed() { + if(propertyBroke().get_value()) + { + core->queueMessage(MSG_BREAK, (void*)std::stoull(Address, nullptr, 16)); + } + else + { + core->queueMessage(MSG_DELBREAK, (void*)std::stoull(Address, nullptr, 16)); + } + } + }; +} + +class CPUView : public Gtk::ColumnView +{ +public: + uint64_t rip = 0; + int _lastSelectedRow = -1; + std::shared_ptr core = nullptr; + +protected: + Glib::RefPtr> _codeViewStore; + Glib::RefPtr _model; + + [[nodiscard]]static std::vector disassembly(uint8_t* data, int cc, size_t size, int address) + { + std::vector r; + + csh handle; + cs_insn *insn; + size_t count; + + if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) + return {}; + cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + for(int i=0, sz = 0;i &refBuilder) : Gtk::ColumnView(cobject) + { + _codeViewStore = Gio::ListStore::create(); + _model = Gtk::SingleSelection::create(_codeViewStore); + _model->set_autoselect(false); + _model->set_can_unselect(true); + set_model(_model); + set_reorderable(false); + set_hexpand(); + set_vexpand(); + add_cols(); + + signal_activate().connect([this](guint i){ + auto row = _codeViewStore->get_item(i); + bool old = row->propertyBroke().get_value(); + row->propertyBroke().set_value(!old); + }); + } + + void setData(const std::vector& insn) + { + _lastSelectedRow = -1; + clear(); + for (const auto &k : insn) { + char cmdAddr[32], insByte[32]; + std::string bytes, cmdStr; + for(int j = 0;jContainsBreakPoint(k.address)); + } + } + + void add_row(const std::string& addr, + const std::string& data, + const std::string& disassembly, + bool isBroke + ){ + _codeViewStore->append(CPUModelColumns::create(isBroke, addr, data, disassembly, core)); + } + + + void clear() + { + _codeViewStore->remove_all(); + } + + uint64_t GetSelected() + { + auto i = _model->get_selected(); + if(i == GTK_INVALID_LIST_POSITION) return 0; + + auto k = _codeViewStore->get_item(i); + return std::stoull(k->Address, nullptr, 16); + } + + void Select() + { + for (int i=0;i<_codeViewStore->get_n_items();i++) { + auto row = _codeViewStore->get_item(i); + std::string str = row->Address; + if (std::stoull(str, nullptr, 16) == rip) { + if(_lastSelectedRow >= 0) + _codeViewStore->get_item(_lastSelectedRow)->propertyClasses().set_value({}); + _lastSelectedRow = i; + row->propertyClasses().set_value({"highlight"}); + + _model->select_item(i, true); + gtk_column_view_scroll_to(this->gobj(), i, nullptr, GTK_LIST_SCROLL_NONE, nullptr); + break; + } + } + queue_draw(); + } + + void add_cols() + { + /* column for fixed toggles */ + auto factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect( + sigc::mem_fun(*this, &CPUView::onSetupCheckbutton)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CPUView::onBindBroke)); + factory->signal_unbind().connect( + sigc::mem_fun(*this, &CPUView::onUnbindBroke)); + auto column = Gtk::ColumnViewColumn::create("Broke", factory); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect(sigc::bind(sigc::mem_fun(*this, + &CPUView::onSetupLabel), Gtk::Align::START)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CPUView::onBindAddress)); + factory->signal_unbind().connect( + sigc::mem_fun(*this, &CPUView::onUnbindAddress)); + column = Gtk::ColumnViewColumn::create("Address", factory); + column->set_fixed_width(150); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect(sigc::bind(sigc::mem_fun(*this, + &CPUView::onSetupLabel), Gtk::Align::START)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CPUView::onBindData)); + factory->signal_unbind().connect( + sigc::mem_fun(*this, &CPUView::onUnbindData)); + + column = Gtk::ColumnViewColumn::create("Data", factory); + append_column(column); + + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect(sigc::bind(sigc::mem_fun(*this, + &CPUView::onSetupLabel), Gtk::Align::START)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &CPUView::onBindDisassembly)); + factory->signal_unbind().connect( + sigc::mem_fun(*this, &CPUView::onUnbindDisassembly)); + + column = Gtk::ColumnViewColumn::create("Disassembly", factory); + column->set_expand(); + append_column(column); + } + + void onSetupCheckbutton(const Glib::RefPtr& list_item) + { + auto checkbutton = Gtk::make_managed(); + checkbutton->set_halign(Gtk::Align::CENTER); + checkbutton->set_valign(Gtk::Align::CENTER); + list_item->set_child(*checkbutton); + } + + void onSetupLabel( + const Glib::RefPtr& list_item, Gtk::Align halign) + { + auto label = Gtk::make_managed("", halign); + list_item->set_child(*label); + } + + void onBindBroke(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto checkbutton = dynamic_cast(list_item->get_child()); + if (!checkbutton) + return; + checkbutton->set_active(col->propertyBroke()); + + if (col->BindingToCheckbutton) + col->BindingToCheckbutton->unbind(); + col->BindingToCheckbutton = Glib::Binding::bind_property( + checkbutton->property_active(), col->propertyBroke(), + Glib::Binding::Flags::BIDIRECTIONAL); + } + + void onUnbindBroke(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + if (col->BindingToCheckbutton) + col->BindingToCheckbutton->unbind(); + col->BindingToCheckbutton.reset(); + } + + void onBindAddress(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + std::string tx = label->get_text(); + label->set_text(col->Address); + + if (col->BindingToAddress) + col->BindingToAddress->unbind(); + col->BindingToAddress = Glib::Binding::bind_property( + label->property_css_classes(), col->propertyClasses(), + Glib::Binding::Flags::BIDIRECTIONAL); + } + + void onUnbindAddress(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + if (col->BindingToAddress) + col->BindingToAddress->unbind(); + col->BindingToAddress.reset(); + } + + void onBindData(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_text(col->Data + " "); + + if (col->BindingToData) + col->BindingToData->unbind(); + col->BindingToData = Glib::Binding::bind_property( + label->property_css_classes(), col->propertyClasses(), + Glib::Binding::Flags::BIDIRECTIONAL); + } + + void onUnbindData(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + if (col->BindingToData) + col->BindingToData->unbind(); + col->BindingToData.reset(); + } + + void onBindDisassembly(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + label->set_text(col->Disassembly); + + if (col->BindingToDisassembly) + col->BindingToDisassembly->unbind(); + col->BindingToDisassembly = Glib::Binding::bind_property( + label->property_css_classes(), col->propertyClasses(), + Glib::Binding::Flags::BIDIRECTIONAL); + } + + void onUnbindDisassembly(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + if (col->BindingToDisassembly) + col->BindingToDisassembly->unbind(); + col->BindingToDisassembly.reset(); + } + +}; diff --git a/interface/cpu/RegView.hpp b/interface/cpu/RegView.hpp new file mode 100644 index 0000000..3e72846 --- /dev/null +++ b/interface/cpu/RegView.hpp @@ -0,0 +1,32 @@ + +#include + +class RegView : public Gtk::TreeView +{ +private: + Glib::RefPtr _regViewStore; + +public: + RegView(BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::TreeView(cobject), + _regViewStore(std::dynamic_pointer_cast(get_model())) + { + + } + + void add_data(const std::string& reg, uint64_t value) + { + auto mm = _regViewStore->append(); + Gtk::TreeModel::Row row = *mm; + + char regv[64]; + sprintf(regv, "%lX", value); + + row.set_value(0, reg); + row.set_value(1, std::string(regv)); + } + + void clear() + { + _regViewStore->clear(); + } +}; \ No newline at end of file diff --git a/interface/cpu/SymbolMenu.hpp b/interface/cpu/SymbolMenu.hpp new file mode 100644 index 0000000..fcfcaeb --- /dev/null +++ b/interface/cpu/SymbolMenu.hpp @@ -0,0 +1,79 @@ + +#include + +class SymbolMenu; + +class SelfContainedButton : public Gtk::Button +{ + typedef void(*Action)(const std::string &, SymbolMenu* menu, const Symbol& sym); + +public: + SelfContainedButton(SymbolMenu* menu, const Symbol& sym) : Gtk::Button(), _menu(menu), _sym(sym) + { + + } + + void SetAction(Action ac) + { + _action = ac; + signal_clicked().connect(sigc::mem_fun(*this, &SelfContainedButton::clicked)); + } + +private: + void clicked() + { + _action(get_label(), _menu, _sym); + } + + Action _action = nullptr; + SymbolMenu* _menu = nullptr; + Symbol _sym; +}; + +class SymbolMenu : public Gtk::MenuButton +{ +private: + void sendMessage(char id, void* param) const + { + DebugCommand msg{id, param}; + if(port != -1) + { + write(port, &msg, sizeof(DebugCommand)); + } + } + +public: + Glib::RefPtr popoverBox = nullptr; + std::vector buttonList; + Glib::RefPtr childLabel = nullptr; + int port = -1; + +public: + SymbolMenu(BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::MenuButton(cobject) + { + + } + + void UpdateList(const std::vector &list) + { + if(popoverBox) + { + for(const auto &k : buttonList) + { + popoverBox->remove(*k); + } + buttonList.clear(); + + for(const auto &k : list) + { + auto b = Gtk::make_managed(this, k); + b->set_label(k.name); + b->SetAction([](const std::string& label, SymbolMenu* menu, const Symbol& sym){ + menu->sendMessage(MSG_SWITCHSYMBOL, (void*)&sym); + }); + buttonList.push_back(b); + popoverBox->append(*b); + } + } + } +}; \ No newline at end of file diff --git a/interface/editor/EditorView.hpp b/interface/editor/EditorView.hpp new file mode 100644 index 0000000..b70e85d --- /dev/null +++ b/interface/editor/EditorView.hpp @@ -0,0 +1,225 @@ + +#include +#include +#include + +std::unordered_map allowedChar +{ + {'0', 1}, + {'1', 1}, + {'2', 1}, + {'3', 1}, + {'4', 1}, + {'5', 1}, + {'6', 1}, + {'7', 1}, + {'8', 1}, + {'9', 1}, + {'0', 1}, + {'a', 1}, + {'b', 1}, + {'c', 1}, + {'d', 1}, + {'e', 1}, + {'f', 1}, + {'A', 1}, + {'B', 1}, + {'C', 1}, + {'D', 1}, + {'E', 1}, + {'F', 1}, +}; + +class NoNewlineTextView : public Gtk::TextView { +public: + NoNewlineTextView() { + + auto buffer = get_buffer(); + buffer->signal_insert().connect(sigc::mem_fun(*this, &NoNewlineTextView::on_insert_text), false); + } + +protected: + void on_insert_text(const Gtk::TextBuffer::iterator& pos, const Glib::ustring& text, int x) { + for(const auto &k : text) + { + if(!allowedChar[k] || get_buffer()->get_text().size() + text.size() > 2) + { + get_buffer()->signal_insert().emission_stop(); + break; + } + } + } + + void on_focus_out() + { + + } +}; + +namespace { + class EditorModelColumns : public Glib::Object { + public: + Glib::ustring baseAddress; + + Glib::RefPtr bindingToValues[16]; + Glib::PropertyProxy propertyValues(int i) { return _values[i].get_proxy(); } + + static Glib::RefPtr create(const Glib::ustring &baseAddress, uint8_t values[16]){ + return Glib::make_refptr_for_instance(new EditorModelColumns(baseAddress, values)); + } + + protected: + Glib::Property _values[16]; + + EditorModelColumns(Glib::ustring baseAddress, uint8_t values[16]) : Glib::ObjectBase(typeid(EditorModelColumns)), baseAddress(std::move(baseAddress)),_values{ + Glib::Property (*this, "i1", std::format("{:02x}", values[0])), + Glib::Property (*this, "i2", std::format("{:02x}", values[1])), + Glib::Property (*this, "i3", std::format("{:02x}", values[2])), + Glib::Property (*this, "i4", std::format("{:02x}", values[3])), + Glib::Property (*this, "i5", std::format("{:02x}", values[4])), + Glib::Property (*this, "i6", std::format("{:02x}", values[5])), + Glib::Property (*this, "i7", std::format("{:02x}", values[6])), + Glib::Property (*this, "i8", std::format("{:02x}", values[7])), + Glib::Property (*this, "i9", std::format("{:02x}", values[8])), + Glib::Property (*this, "i10", std::format("{:02x}", values[9])), + Glib::Property (*this, "i11", std::format("{:02x}", values[10])), + Glib::Property (*this, "i12", std::format("{:02x}", values[11])), + Glib::Property (*this, "i13", std::format("{:02x}", values[12])), + Glib::Property (*this, "i14", std::format("{:02x}", values[13])), + Glib::Property (*this, "i15", std::format("{:02x}", values[14])), + Glib::Property (*this, "i16", std::format("{:02x}", values[15]))} { } + }; +} + +class EditorView : public Gtk::ColumnView { +private: + Glib::RefPtr> _editorModel; + Glib::RefPtr _model; + +public: + EditorView(BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::ColumnView(cobject) + { + _editorModel = Gio::ListStore::create(); + _model = Gtk::SingleSelection::create(_editorModel); + _model->set_autoselect(false); + _model->set_can_unselect(true); + set_model(_model); + set_reorderable(false); + set_hexpand(); + set_vexpand(); + + add_cols(); + add_row("7fff7e"); + add_row("7fff7f"); + add_row("7fff71"); + add_row("7fff72"); + } + + void add_cols() + { + auto factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect(sigc::bind(sigc::mem_fun(*this, + &EditorView::onSetupLabel), Gtk::Align::START)); + factory->signal_bind().connect( + sigc::mem_fun(*this, &EditorView::onBindBase)); + auto column = Gtk::ColumnViewColumn::create("Base", factory); + column->set_fixed_width(150); + append_column(column); + + for(int i=0;i<16;i++) + { + factory = Gtk::SignalListItemFactory::create(); + factory->signal_setup().connect(sigc::bind(sigc::mem_fun(*this, + &EditorView::onSetupEditableLabel), i)); + factory->signal_bind().connect( + sigc::bind(sigc::mem_fun(*this, &EditorView::onBindValue), i)); + factory->signal_unbind().connect( + sigc::bind(sigc::mem_fun(*this, &EditorView::onUnbindValue), i)); + + column = Gtk::ColumnViewColumn::create(std::format("{:02x}", i) , factory); + column->set_expand(); + append_column(column); + } + } + + void add_row(const std::string& base + ){ + uint8_t db[16] = {0}; + _editorModel->append(EditorModelColumns::create(base, db)); + } + + void onSetupLabel( + const Glib::RefPtr& list_item, Gtk::Align halign) + { + auto label = Gtk::make_managed("", halign); + list_item->set_child(*label); + } + + void onBindBase(const Glib::RefPtr& list_item) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + std::string tx = label->get_text(); + label->set_text(col->baseAddress); + } + + void onSetupEditableLabel( + const Glib::RefPtr& list_item, int i) + { + auto label = Gtk::make_managed(); + label->set_editable(); + label->set_accepts_tab(false); + +// label->signal_insert_text().connect([](const Glib::ustring& str, int* n){ +// +// }); + label->get_buffer()->property_text().signal_changed().connect(sigc::bind(sigc::mem_fun( + *this, &EditorView::on_edited), list_item, i)); + list_item->set_child(*label); + } + + void onBindValue( + const Glib::RefPtr& list_item, int i) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + + label->get_buffer()->set_text(col->propertyValues(i).get_value()); + + if (col->bindingToValues[i]) + col->bindingToValues[i]->unbind(); + + col->bindingToValues[i] = Glib::Binding::bind_property( + label->get_buffer()->property_text(), col->propertyValues(i), + Glib::Binding::Flags::BIDIRECTIONAL); + } + + void onUnbindValue( + const Glib::RefPtr& list_item, int i) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + if (col->bindingToValues[i]) + col->bindingToValues[i]->unbind(); + col->bindingToValues[i].reset(); + } + + void on_edited(const Glib::RefPtr& list_item, int i) + { + auto col = std::dynamic_pointer_cast(list_item->get_item()); + if (!col) + return; + auto label = dynamic_cast(list_item->get_child()); + if (!label) + return; + } +}; diff --git a/interface/home.hpp b/interface/home.hpp new file mode 100644 index 0000000..b580921 --- /dev/null +++ b/interface/home.hpp @@ -0,0 +1,490 @@ + +#include +#include +#include +#include + +#include "interface/log/LogView.hpp" +#include "interface/cpu/CPUView.hpp" + +#include "../core/Core.hpp" +#include "interface/cpu/RegView.hpp" +#include "interface/cpu/SymbolMenu.hpp" +#include "interface/memory/MemoryView.hpp" +#include "interface/callstack/CallstackView.hpp" +#include "interface/editor/EditorView.hpp" + +class HomeWindow : public Gtk::Window +{ +public: + void sendMessage(char id, void* param) const + { + DebugCommand msg{id, param}; + if(sock_pair[0] != -1) + { + write(sock_pair[0], &msg, sizeof(DebugCommand)); + } + } +protected: + int sock_pair[2]{}; + + Glib::RefPtr _refBuilder; + Glib::RefPtr _app = nullptr; + + std::shared_ptr _core = nullptr; + + pthread_t _th = 0; + + std::string _lastPath = ""; + std::string _lastArgv = ""; + + char buffer[32] = {0}; + int ep = -1; + epoll_event ev1 {}; + + std::vector* pInsn = nullptr; + +public: // Elements + Glib::RefPtr codeView = nullptr; + Glib::RefPtr logView = nullptr; + Glib::RefPtr bAttach = nullptr; + Glib::RefPtr dialogAttach = nullptr; + Glib::RefPtr dCancel = nullptr; + Glib::RefPtr dAttach = nullptr; + Glib::RefPtr bStop = nullptr; + Glib::RefPtr bCont = nullptr; + Glib::RefPtr bSuspend = nullptr; + Glib::RefPtr debugBox = nullptr; + Glib::RefPtr tExecutable = nullptr; + Glib::RefPtr tArg = nullptr; + Glib::RefPtr logScroll = nullptr; + Glib::RefPtr HeaderBar = nullptr; + Glib::RefPtr bRestart = nullptr; + Glib::RefPtr regView = nullptr; + Glib::RefPtr windowTitle = nullptr; + Glib::RefPtr bStepinto = nullptr; + Glib::RefPtr memory = nullptr; + Glib::RefPtr popover1 = nullptr; + Glib::RefPtr popover1Box = nullptr; + Glib::RefPtr currentSymbol = nullptr; + Glib::RefPtr bStepover = nullptr; + Glib::RefPtr mSymbols = nullptr; + Glib::RefPtr bTryParse = nullptr; + Glib::RefPtr breakpoints = nullptr; + Glib::RefPtr stack = nullptr; + Glib::RefPtr callstack = nullptr; + Glib::RefPtr bGoto = nullptr; + Glib::RefPtr editor = nullptr; + Glib::RefPtr bMemPush = nullptr; + Glib::RefPtr bMemPull = nullptr; + Glib::RefPtr bMemJump = nullptr; + +public: + + HomeWindow(BaseObjectType *cobject, const Glib::RefPtr &refBuilder, const Glib::RefPtr& app) : + Gtk::Window(cobject), _refBuilder(refBuilder), _app(app), + codeView(_refBuilder->get_widget_derived(_refBuilder, "code")), + regView(_refBuilder->get_widget_derived(_refBuilder, "reg")), + logScroll(refBuilder->get_widget("logScroll")), + bAttach(refBuilder->get_widget("bAttach")), + dialogAttach(refBuilder->get_widget("dialogAttach")), + dCancel(refBuilder->get_widget("dCancel")), + dAttach(refBuilder->get_widget("dAttach")), + bStop(refBuilder->get_widget("bStop")), + debugBox(refBuilder->get_widget("debugBox")), + tExecutable(refBuilder->get_widget("tExecutable")), + tArg(refBuilder->get_widget("tArg")), + logView(_refBuilder->get_widget_derived(_refBuilder, "log")), + bCont(refBuilder->get_widget("bCont")), + bSuspend(refBuilder->get_widget("bSuspend")), + HeaderBar(refBuilder->get_widget("HeaderBar")), + bRestart(refBuilder->get_widget("bRestart")), + windowTitle(refBuilder->get_widget("windowTitle")), + bStepinto(refBuilder->get_widget("bStepinto")), + memory(_refBuilder->get_widget_derived(_refBuilder, "memory")), + popover1(refBuilder->get_widget("popover1")), + popover1Box(refBuilder->get_widget("popover1Box")), + currentSymbol(refBuilder->get_widget("currentSymbol")), + bStepover(refBuilder->get_widget("bStepover")), + mSymbols(refBuilder->get_widget_derived(_refBuilder, "mSymbols")), + bTryParse(refBuilder->get_widget("bTryParse")), + breakpoints(_refBuilder->get_widget_derived(_refBuilder, "breakpoints")), + stack(refBuilder->get_widget("stack")), + callstack(_refBuilder->get_widget_derived(_refBuilder, "callstack")), + bGoto(refBuilder->get_widget("bGoto")), + editor(_refBuilder->get_widget_derived(_refBuilder, "editor")), + bMemPush(refBuilder->get_widget("bMemPush")), + bMemPull(refBuilder->get_widget("bMemPull")), + bMemJump(refBuilder->get_widget("bMemJump")) + { + socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair); + ep = epoll_create1(0); + + ev1 = epoll_event{.events = EPOLLIN}; + ev1.data.fd = sock_pair[0]; + epoll_ctl(ep, EPOLL_CTL_ADD, sock_pair[0], &ev1); + bTryParse->hide(); + this->add_tick_callback([this](const Glib::RefPtr& c){ + int n = epoll_wait(ep, &ev1, 1, 0); + if(n > 0) + { + auto sz = read(sock_pair[0], buffer, sizeof(DebugCommand)); + if(sz != sizeof(DebugCommand)) return true; + + auto msg = (DebugCommand*)buffer; + switch (msg->id) { + case MSG_PAUSE: + UpdateUI(1, BTN_CONT | BTN_STOP | BTN_STI); + break; + case MSG_STOP: + _core = nullptr; + UpdateUI(0, BTN_ATTACH); + break; + case MSG_CONTINUE: + UpdateUI(2, BTN_INT | BTN_STOP); + break; + case MSG_STARTUP: + UpdateUI(0, BTN_INT | BTN_STOP); + break; + case MSG_REG:{ + auto reg = reinterpret_cast(msg->param); + UpdateUI(0, 0, reg); // The first two parameters do not take effect when reg isn't empty + codeView->rip = reg->rip; + break; + } + case MSG_QUIT: + return false; + case MSG_LOG: + logView->add_log_data((char*)msg->param); + delete[] (char*)msg->param; + break; + case MSG_TITLE: + windowTitle->set_text((char*)msg->param); + break; + case MSG_MEMORY:{ + auto pList = reinterpret_cast*>(msg->param); + memory->set_data(*pList); + break; + } + case MSG_ASM:{ + delete pInsn; + pInsn = reinterpret_cast*>(msg->param); + codeView->setData(*pInsn); + break; + } + case MSG_SELECT: + codeView->Select(); + break; + case MSG_CURRENTSYMBOL: + currentSymbol->set_text(_core->currentSymbol.name); + break; + case MSG_RESTART: + _core = std::make_shared(_lastPath, _lastArgv); + _core->pipe = sock_pair[1]; + _core->remotePipe = sock_pair[0]; + codeView->core = _core; + breakpoints->core = _core; + + bAttach->set_sensitive(false); + logView->clear(); + break; + case MSG_SYMBOLS: + mSymbols->UpdateList(_core->symbols); + break; + case MSG_NONSYM: + bTryParse->show(); + break; + case MSG_INSYM: + bTryParse->hide(); + break; + case MSG_GETBREAKS: + { + breakpoints->clear(); + auto insn = reinterpret_cast(msg->param); + auto count = _core->GetBreakpoints().size(); + + for (size_t i = 0; i < count; i++) { + char cmdAddr[32], insByte[32]; + std::string bytes, cmdStr; + for(int j = 0;jadd_row(cmdAddr, bytes, cmdStr, _core->ContainsBreakPoint(insn[i].address)); + } + delete[] insn; + break; + } + case MSG_CALLSTACK: + { + auto *p = (std::stack*)msg->param; + + callstack->clear(); + while(!p->empty()) + { + std::string name = "Thread: "; + std::vector g; + name += std::to_string(p->top().depth); + p->pop(); + + int depth = INT_MAX; + do + { + char strBuf[512]; + depth = p->top().depth; + CallstackItem i{}; + i.depth = std::to_string(depth); + + sprintf(strBuf, "%lX", p->top().callPoint); + i.callPoint = strBuf; + + sprintf(strBuf, "%lX", p->top().stackBase); + i.stackBase = strBuf; + + i.symbol = p->top().symbol.name; + i.module = p->top().module; + g.emplace_back(i); + p->pop(); + }while(depth); + + callstack->append_group(name, g); + } + delete p; + break; + } + default: + break; + } + } + return true; + }); + mSymbols->popoverBox = popover1Box; + mSymbols->childLabel = currentSymbol; + mSymbols->port = sock_pair[0]; + + _app->signal_activate().connect([this](){ + _app->add_window(*this); + this->show(); + }); + + codeView->add_css_class("code_view"); + + dialogAttach->set_hide_on_close(true); + + bAttach->signal_clicked().connect([this](){ + dialogAttach->set_transient_for(*this); + dialogAttach->show(); + }); + + dCancel->signal_clicked().connect([this](){ + dialogAttach->close(); + }); + + dAttach->signal_clicked().connect([this](){ + auto s = tExecutable->get_buffer()->get_text(); + std::size_t pos = s.rfind('/'); + std::string filename = (pos != std::string::npos) ? s.substr(pos + 1) : s; + + dialogAttach->close(); + _lastPath = s; + _lastArgv = filename; + + _core = std::make_shared(s, filename); + _core->pipe = sock_pair[1]; + _core->remotePipe = sock_pair[0]; + codeView->core = _core; + breakpoints->core = _core; + + bAttach->set_sensitive(false); + logView->clear(); + }); + + bStop->signal_clicked().connect([this](){ + if(_core) + { + codeView->clear(); + sendMessage(MSG_STOP, nullptr); + _core = nullptr; + codeView->core = nullptr; + breakpoints->core = nullptr; + } + }); + + bSuspend->signal_clicked().connect([this](){ + sendMessage(MSG_PAUSE, nullptr); + }); + + bCont->signal_clicked().connect([this](){ + sendMessage(MSG_CONTINUE, nullptr); + }); + + bStepinto->signal_clicked().connect([this](){ + sendMessage(MSG_STEPINTO, nullptr); + }); + + bRestart->signal_clicked().connect([this](){ + if(!_lastPath.empty()) + { + if(!_core) + { + _core = std::make_shared(_lastPath, _lastArgv); + _core->pipe = sock_pair[1]; + _core->remotePipe = sock_pair[0]; + codeView->core = _core; + breakpoints->core = _core; + + bAttach->set_sensitive(false); + logView->clear(); + return; + } + sendMessage(MSG_RESTART, nullptr); + _core = nullptr; + codeView->core = nullptr; + breakpoints->core = nullptr; + + printf("%s\n", "Pending to Restart"); + } + }); + + bStepover->signal_clicked().connect([this](){ + sendMessage(MSG_STEPOVER, nullptr); + }); + bGoto->signal_clicked().connect([this](){ + auto i = codeView->GetSelected(); + _core->queueMessage(MSG_BREAKONCE, (void*)i); + sendMessage(MSG_CONTINUE, nullptr); + }); + + bTryParse->signal_clicked().connect([this](){ + sendMessage(MSG_PARSE, nullptr); + }); + + memory->signal_row_activated().connect([this](const Gtk::TreeModel::Path& p, Gtk::TreeViewColumn* c){ + auto iter = memory->get_model()->get_iter(p); + if(iter) + { + Glib::ustring addr; + (*iter).get_value(0, addr); + printf("%s\n", addr.c_str()); + + MapEntire me; + _core->GetMapEntire(std::stoull(addr, nullptr, 16), me); + + if(me.access & EXECUTE) + { + auto buf = new char[512]; + strcpy(buf, me.path); + sendMessage(MSG_SWITCHMODULE, buf); + } + } + }); + + stack->property_visible_child().signal_changed().connect([this](){ + auto name = stack->get_visible_child_name(); + if(name == "Breakpoints" && _core != nullptr) + { + if(_core) + sendMessage(MSG_GETBREAKS, nullptr); + }else if(name == "CPU" && _core != nullptr) + { + if(pInsn) + codeView->setData(*pInsn); + codeView->Select(); + }else if(name == "Call Stack" && _core != nullptr) + { + if(_core) + sendMessage(MSG_CALLSTACK, nullptr); + } + + }); + + UpdateUI(0, BTN_ATTACH); + } + + static Glib::RefPtr create() + { + auto app = Gtk::Application::create("acite.aldbg.app"); + auto refBuilder = Gtk::Builder::create(); + refBuilder->add_from_file("../aldbg.ui"); + auto home = Gtk::Builder::get_widget_derived(refBuilder, "MainWindow", app); + + if (!home) { + std::cerr << "No \"MainWindow\" object in main-window.ui" << std::endl; + return nullptr; + } + + auto css_provider = Gtk::CssProvider::create(); + css_provider->load_from_path("../interface/style.css"); + + // 将 CSS 提供程序应用到屏幕 + Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER); + + return Glib::make_refptr_for_instance(home); + } + + enum ButtonMask + { + BTN_ATTACH = 0x01, + BTN_STOP = 0x02, + BTN_CONT = 0x04, + BTN_INT = 0x08, + BTN_STI = 0x10 + }; + + void UpdateUI(int status, uint64_t buttons, user_regs_struct* reg = nullptr) + { + if(reg) + { + regView->clear(); + regView->add_data("rax", reg->rax); + regView->add_data("rbx", reg->rbx); + regView->add_data("rcx", reg->rcx); + regView->add_data("rdx", reg->rdx); + regView->add_data("rbp", reg->rbp); + regView->add_data("rsp", reg->rsp); + regView->add_data("pc", reg->rip); + return; + } + switch(status) + { + case 0: + HeaderBar->remove_css_class("cont"); + HeaderBar->remove_css_class("trap"); + break; + case 1: + HeaderBar->remove_css_class("cont"); + HeaderBar->add_css_class("trap"); + break; + case 2: + HeaderBar->add_css_class("cont"); + HeaderBar->remove_css_class("trap"); + break; + default: + break; + } + + bSuspend->set_sensitive(buttons & BTN_INT); + bCont->set_sensitive(buttons & BTN_CONT); + bAttach->set_sensitive(buttons & BTN_ATTACH); + bStop->set_sensitive(buttons & BTN_STOP); + bStepinto->set_sensitive(buttons & BTN_STI); + bStepover->set_sensitive(buttons & BTN_STI); + mSymbols->set_sensitive(buttons & BTN_STI); + bGoto->set_sensitive(buttons & BTN_STI); + + bMemJump->set_sensitive(buttons & BTN_STI); + bMemPull->set_sensitive(buttons & BTN_STI); + bMemPush->set_sensitive(buttons & BTN_STI); + } + + int loop() + { + return _app->run(); + } +}; \ No newline at end of file diff --git a/interface/icon/arrow-restart.png b/interface/icon/arrow-restart.png new file mode 100644 index 0000000..e55a304 Binary files /dev/null and b/interface/icon/arrow-restart.png differ diff --git a/interface/icon/arrow-run-cursor.png b/interface/icon/arrow-run-cursor.png new file mode 100644 index 0000000..e383d6b Binary files /dev/null and b/interface/icon/arrow-run-cursor.png differ diff --git a/interface/icon/arrow-run.png b/interface/icon/arrow-run.png new file mode 100644 index 0000000..1799620 Binary files /dev/null and b/interface/icon/arrow-run.png differ diff --git a/interface/icon/arrow-skip.png b/interface/icon/arrow-skip.png new file mode 100644 index 0000000..ebcd4ff Binary files /dev/null and b/interface/icon/arrow-skip.png differ diff --git a/interface/icon/arrow-small-down.png b/interface/icon/arrow-small-down.png new file mode 100644 index 0000000..377400e Binary files /dev/null and b/interface/icon/arrow-small-down.png differ diff --git a/interface/icon/arrow-small-up.png b/interface/icon/arrow-small-up.png new file mode 100644 index 0000000..b2a251b Binary files /dev/null and b/interface/icon/arrow-small-up.png differ diff --git a/interface/icon/arrow-step-into.png b/interface/icon/arrow-step-into.png new file mode 100644 index 0000000..5d13ddc Binary files /dev/null and b/interface/icon/arrow-step-into.png differ diff --git a/interface/icon/arrow-step-over.png b/interface/icon/arrow-step-over.png new file mode 100644 index 0000000..6aca13c Binary files /dev/null and b/interface/icon/arrow-step-over.png differ diff --git a/interface/icon/arrow-step-rtr.png b/interface/icon/arrow-step-rtr.png new file mode 100644 index 0000000..04bb4f4 Binary files /dev/null and b/interface/icon/arrow-step-rtr.png differ diff --git a/interface/icon/arrow-threads.png b/interface/icon/arrow-threads.png new file mode 100644 index 0000000..6bd0479 Binary files /dev/null and b/interface/icon/arrow-threads.png differ diff --git a/interface/icon/close-all-tabs.png b/interface/icon/close-all-tabs.png new file mode 100644 index 0000000..6b9fa6d Binary files /dev/null and b/interface/icon/close-all-tabs.png differ diff --git a/interface/icon/control-pause.png b/interface/icon/control-pause.png new file mode 100644 index 0000000..fdd7fab Binary files /dev/null and b/interface/icon/control-pause.png differ diff --git a/interface/icon/control-stop.png b/interface/icon/control-stop.png new file mode 100644 index 0000000..fdaeb85 Binary files /dev/null and b/interface/icon/control-stop.png differ diff --git a/interface/log/LogView.hpp b/interface/log/LogView.hpp new file mode 100644 index 0000000..f302eae --- /dev/null +++ b/interface/log/LogView.hpp @@ -0,0 +1,46 @@ +// +// Created by acite on 5/1/24. +// + +#include +#include +#include +#include +#include +#include + + +class LogView : public Gtk::TreeView +{ +protected: + Glib::RefPtr _logStore = nullptr; + +public: + LogView(BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::TreeView(cobject), + _logStore(std::dynamic_pointer_cast(get_model())) + { + + } + + void add_log_data(const std::string& data) + { + auto mm = _logStore->append(); + Gtk::TreeModel::Row row = *mm; + + time_t currentTime; + time(¤tTime); + tm* localTime = localtime(¤tTime); + + char time_str[64]; + sprintf(time_str, "[%d:%d:%d]", localTime->tm_hour, localTime->tm_min, localTime->tm_sec); + std::string cppstrtime = time_str; + + row.set_value(0, cppstrtime); + row.set_value(1, data); + } + + void clear() + { + _logStore->clear(); + } +}; diff --git a/interface/memory/MemoryView.hpp b/interface/memory/MemoryView.hpp new file mode 100644 index 0000000..5e0f247 --- /dev/null +++ b/interface/memory/MemoryView.hpp @@ -0,0 +1,57 @@ + +#include +#include "../../core/MemoryMap.hpp" + +class MemoryView : public Gtk::TreeView +{ +private: + Glib::RefPtr _memoryViewStore; + +public: + void GetSelection(uint64_t& address) + { + Gtk::TreeModel::Row row = *get_selection()->get_selected(); + row.get_value(0, address); + } + + std::vector _map; + + MemoryView(BaseObjectType *cobject, const Glib::RefPtr &refBuilder) : Gtk::TreeView(cobject), + _memoryViewStore(std::dynamic_pointer_cast(get_model())) + { + + } + + void set_data(std::vector& list) + { + _map = list; + + _memoryViewStore->clear(); + + for(auto e : list) + { + auto mm = _memoryViewStore->append(); + Gtk::TreeModel::Row row = *mm; + + char startAddr[32], endAddr[32], offset[32]; + std::string permission; + + permission += (e.access & READ ? "r" : "-"); + permission += (e.access & WRITE ? "w" : "-"); + permission += (e.access & EXECUTE ? "x" : "-"); + permission += (e.access & PRIVATE ? "p" : "-"); + permission += (e.access & SHARED ? "s" : "-"); + + sprintf(startAddr, "%16lx", e.startAddress); + sprintf(endAddr, "%16lx", e.endAddress); + sprintf(offset, "%8x", e.offset); + + + row.set_value(0, std::string(startAddr)); + row.set_value(1, std::string(endAddr)); + row.set_value(2, permission); + row.set_value(3, std::string(offset)); + row.set_value(4, std::string(e.path)); + } + } +}; \ No newline at end of file diff --git a/interface/style.css b/interface/style.css new file mode 100644 index 0000000..f968f30 --- /dev/null +++ b/interface/style.css @@ -0,0 +1,20 @@ +/* 设置窗口的背景颜色 */ + +/* 设置标签的字体样式 */ +label { + font-size: 16px; + font-weight: bold; +} + +headerbar.cont { + background-color: #66CC00; +} + +headerbar.trap { + background-color: #CC6600; +} + +label.highlight { + color: #CC6600; + font-weight: bold; +} diff --git a/log/log.cpp b/log/log.cpp deleted file mode 100644 index 4f68e39..0000000 --- a/log/log.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by acite on 5/1/24. -// - -#include -#include -#include -#include -#include -#include "log.h" -#include - -using namespace Gtk; -using namespace std; - -extern Glib::RefPtr logStore; - -void add_log_data(const std::string& data) -{ - auto mm = logStore->append(); - Gtk::TreeModel::Row row = *mm; - - time_t currentTime; - time(¤tTime); - tm* localTime = localtime(¤tTime); - - char time_str[64]; - sprintf(time_str, "[%d:%d:%d]", localTime->tm_hour, localTime->tm_min, localTime->tm_sec); - string cppstrtime = time_str; - - row.set_value(0, cppstrtime); - row.set_value(1, data); -} \ No newline at end of file diff --git a/log/log.h b/log/log.h deleted file mode 100644 index ed39629..0000000 --- a/log/log.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by acite on 5/1/24. -// - -#ifndef ALDBG_LOG_H -#define ALDBG_LOG_H - -#include - -void add_log_data(const std::string& data); - -#endif //ALDBG_LOG_H diff --git a/main.cpp b/main.cpp index e2668d1..8db4635 100644 --- a/main.cpp +++ b/main.cpp @@ -9,74 +9,52 @@ #include #include -#include "cpu/cpu.h" -#include "log/log.h" +#include "interface/home.hpp" #define MAX_LOG_BUFFER_SIZE (1024*1024) using namespace std; -using namespace Gtk; + +Glib::RefPtr home; extern void button_attach(); extern void button_exec(); -TreeView* codeView; -TreeView* logView; -Glib::RefPtr codeViewStore; -Glib::RefPtr logStore; -Button* bAttach; -Dialog* dialogAttach; -Button* dCancel; -Button* dAttach; -Button* bStop; -Window* MainWindow = nullptr; - -static Glib::RefPtr app; static pthread_t threads[5]; -epoll_event events[5] = { - { .events = EPOLLIN } // Event for pipe data -}; -epoll_event r_events[5] = {0}; char buffer[MAX_LOG_BUFFER_SIZE]; ssize_t sz = -1; int pipefd[2] = {0}; void *aldbg_io_handler(void *arg) { - int r = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK); - if(r == -1) - { - perror("pipe2()"); - return nullptr; - } - dup2(pipefd[1], 1); // dup pipe write port to stdout + int r; + + socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd); + dup2(pipefd[1], STDOUT_FILENO); // dup pipe write port to stdout + + epoll_event ev{}; + ev.events = EPOLLIN; + ev.data.fd = pipefd[0]; - events[0].data.fd = pipefd[0]; int efd = epoll_create1(0); - epoll_ctl(efd, EPOLL_CTL_ADD, pipefd[0], &events[0]); + epoll_ctl(efd, EPOLL_CTL_ADD, pipefd[0], &ev); while(1) { - r = epoll_wait(efd, r_events, 5, 2000); + r = epoll_wait(efd, &ev, 1, 50); if(r == -1)perror("epoll_wait()"); - if(r == 0)continue; - - for(int i=0;ilogView->add_log_data(pStr); + pStr = strtok(nullptr, "\n"); } } } @@ -84,66 +62,11 @@ void *aldbg_io_handler(void *arg) return nullptr; } -bool motion_event(GdkEventMotion* m) -{ - double x = m->x; - double y = m->y; - std::cout << "Mouse moved to: (" << x << ", " << y << ")" << std::endl; - return false; // 事件已被处理 -} - -void window_init() -{ - ////////////////////////////////////////// register assemblies - auto builder = Builder::create_from_file("../aldbg.glade"); - builder->get_widget("MainWindow", MainWindow); - builder->get_widget("code", codeView); - builder->get_widget("log", logView); - builder->get_widget("bAttach", bAttach); - builder->get_widget("dialogAttach", dialogAttach); - builder->get_widget("dCancel", dCancel); - builder->get_widget("dAttach", dAttach); - builder->get_widget("bStop", bStop); - codeViewStore = Glib::RefPtr::cast_dynamic(codeView->get_model()); - logStore = Glib::RefPtr::cast_dynamic(logView->get_model()); - /////////////////////////////////////////// - - app->add_window(*MainWindow); - MainWindow->show(); // Show Window - - for(int i=0;i<35;i++) - add_row(to_string(i * 1000), "DAF", "Fuck", "->"); - set_row_status(2000, "*->"); - - ///////////////////////////////////////////////////// register events - bAttach->signal_clicked().connect([](){ - button_attach(); - }); - - dCancel->signal_clicked().connect([](){ - dialogAttach->close(); - }); - - dAttach->signal_clicked().connect([](){ - button_exec(); - }); - - bStop->signal_clicked().connect([](){ - - }); - - MainWindow->add_events(Gdk::POINTER_MOTION_MASK); - ///////////////////////////////////////////////////// - - pthread_create(&threads[0], nullptr, aldbg_io_handler, nullptr); -} - int main() { - app = Application::create(); - app->signal_activate().connect([](){ - window_init(); - }); + home = HomeWindow::create(); - return app->run(); + //pthread_create(&threads[0], nullptr, aldbg_io_handler, nullptr); + + return home->loop(); } \ No newline at end of file