diff --git a/CMakeLists.txt b/CMakeLists.txt index 942b0dc..c15fb93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,14 +121,3 @@ install(CODE " message(STATUS \"Command 'ds' not found. Skipping completion symlink.\") endif() ") - -# Create pre-install script to clean old templates -install(CODE " - message(STATUS \"Removing old template files...\") - execute_process(COMMAND rm -rf /opt/dropshell/templates) -") - -# Install templates with pre-install script -install(DIRECTORY templates/ - DESTINATION /opt/dropshell/templates -) diff --git a/build.sh b/build.sh index 5ed3dd9..0f5a919 100755 --- a/build.sh +++ b/build.sh @@ -74,8 +74,8 @@ fi # Configure with CMake print_status "Configuring with CMake..." -#cmake .. -DCMAKE_BUILD_TYPE=Debug -cmake .. -DCMAKE_BUILD_TYPE=Release +cmake .. -DCMAKE_BUILD_TYPE=Debug +#cmake .. -DCMAKE_BUILD_TYPE=Release # Build the project print_status "Building project..." diff --git a/src/utils/assert.hpp b/src/utils/assert.hpp index 03c9837..fbecec6 100644 --- a/src/utils/assert.hpp +++ b/src/utils/assert.hpp @@ -4,6 +4,14 @@ #include #include #include // For std::exit and EXIT_FAILURE +#include +#include +#include +#include +#include +#include +#include +#include namespace ds { @@ -16,6 +24,73 @@ struct SourceLocation { // Helper macro to create a SourceLocation with current context #define DS_CURRENT_LOCATION ds::SourceLocation{__FILE__, __LINE__, __func__} +inline uintptr_t get_base_address(const char* exe_path) { + // Open /proc/self/maps + FILE* maps = fopen("/proc/self/maps", "r"); + if (!maps) return 0; + char line[512]; + uintptr_t base_addr = 0; + while (fgets(line, sizeof(line), maps)) { + // Look for a line containing the exe path and 'r-xp' + if (strstr(line, exe_path) && strstr(line, "r-xp")) { + // Parse the start address + char* endptr = nullptr; + base_addr = strtoull(line, &endptr, 16); + break; + } + } + fclose(maps); + return base_addr; +} + +inline void print_stacktrace() { + constexpr int max_frames = 64; + void* addrlist[max_frames]; + int addrlen = backtrace(addrlist, max_frames); + + if (addrlen == 0) { + std::cerr << " \n"; + return; + } + + // Get the program name + char exe_path[1024]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len == -1) { + std::cerr << " \n"; + return; + } + exe_path[len] = '\0'; + + uintptr_t base_addr = get_base_address(exe_path); + + for (int i = 0; i < addrlen; i++) { + uintptr_t addr = (uintptr_t)addrlist[i]; + uintptr_t offset = base_addr ? (addr - base_addr) : addr; + std::ostringstream cmd; + cmd << "addr2line -e " << exe_path << " -f -C 0x" << std::hex << offset; + std::unique_ptr pipe(popen(cmd.str().c_str(), "r"), pclose); + if (!pipe) { + std::cerr << " \n"; + continue; + } + // addr2line -f prints two lines per address: function name, then file:line + char func[256] = {0}; + char fileline[256] = {0}; + if (fgets(func, sizeof(func), pipe.get()) && fgets(fileline, sizeof(fileline), pipe.get())) { + // Remove trailing newlines + size_t len1 = strlen(func); + if (len1 > 0 && func[len1-1] == '\n') func[len1-1] = 0; + size_t len2 = strlen(fileline); + if (len2 > 0 && fileline[len2-1] == '\n') fileline[len2-1] = 0; + // Remove argument list from function name (truncate at first '(') + char* paren = strchr(func, '('); + if (paren) *paren = 0; + std::cerr << " " << func << " at " << fileline << "\n"; + } + } +} + [[noreturn]] inline void assert_fail( const char* expression, const SourceLocation& location, @@ -33,6 +108,10 @@ struct SourceLocation { std::cerr << std::endl; + std::cerr << "Stack trace:" << std::endl; + print_stacktrace(); + std::cerr << "----------------------------------------" << std::endl; + // Exit the program without creating a core dump std::exit(EXIT_FAILURE); }