From ccd0c183ec3067e95816d1bd2d520b24d0ea5a5d Mon Sep 17 00:00:00 2001 From: Max Logaev Date: Sun, 18 Jan 2026 13:08:02 +0000 Subject: [PATCH] mtdbg: Backtrace implemented (#315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added support for backtrace/stacktrace output. This is useful for high-level languages ​​like C and Oberon07. If a debug file is provided, searches for the nearest debug symbol. Reviewed-on: https://git.kolibrios.org/KolibriOS/kolibrios/pulls/315 Reviewed-by: Mikhail Frolov Reviewed-by: Burer --- programs/develop/mtdbg/mtdbg.asm | 124 ++++++++++++++++++++++++++++- programs/develop/mtdbg/symbols.inc | 72 ++++++++++++++++- 2 files changed, 192 insertions(+), 4 deletions(-) diff --git a/programs/develop/mtdbg/mtdbg.asm b/programs/develop/mtdbg/mtdbg.asm index 44c5c6dbb..24b1caf12 100644 --- a/programs/develop/mtdbg/mtdbg.asm +++ b/programs/develop/mtdbg/mtdbg.asm @@ -2,7 +2,10 @@ COLOR_THEME fix MOVIEOS format binary as "" + include '../../macros.inc' +include '../../KOSfuncs.inc' + use32 db 'MENUET01' dd 1 @@ -1145,6 +1148,105 @@ OnDump: .ret: ret +;----------------------------------------------------------------------------- +; Print Backtrace + +struct STACK_FRAME + prev_frame rd 1 + ret_addr rd 1 +ends + +OnBacktrace: + push ebp + + ; Set max depth counter + xor eax, eax + dec eax + + mov esi, [curarg] + cmp byte [esi], 0 + jz .save_depth + + call get_hex_number + mov esi, aParseError + jc .exit + + ; If depth 0 + test eax, eax + jz .done + + .save_depth: + mov [bt_depth], eax + + ; Get start frame addres + mov ebp, [_ebp] + test ebp, ebp + jz .done + + mov edi, stack_frame_dump + + .next: + mcall SF_DEBUG, SSF_READ_MEMORY, [debuggee_pid], sizeof.STACK_FRAME, ebp + cmp eax, -1 + mov esi, read_mem_err + jz .exit + + ; The address of the previous frame must be less than the current one + mov eax, [edi + STACK_FRAME.prev_frame] + test eax, eax + jz .done + + ; Save stack_frame_dump + push edi + ; Save previous frame + push ebp + ; Save return address + mov eax, [edi + STACK_FRAME.ret_addr] + push eax + + ; Print frame address and return address + push eax ; pop in put_message_nodraw + push ebp ; pop in put_message_nodraw + mov esi, aBacktraceFmt + call put_message_nodraw + + ; Restore return address + pop eax + + ; Find symbol by return address + call find_near_symbol + test esi, esi + jnz .print_sym + + mov esi, aBacktraceSymStub + + .print_sym: + call put_message_nodraw + mov esi, newline + call put_message_nodraw + + ; Restore previous frame + pop ebp + ; Restore stack_frame_dump + pop edi + + ; The address of the previous frame must be greater than the current one. + cmp [edi + STACK_FRAME.prev_frame], ebp + jna .done + + ; Set previous frame + mov ebp, [edi + STACK_FRAME.prev_frame] + dec [bt_depth] + jnz .next + + .done: + mov esi, newline + + .exit: + call put_message + pop ebp + ret + ;----------------------------------------------------------------------------- ; Dissassemble block of executable event @@ -1864,7 +1966,7 @@ include 'disasm.inc' caption_str db 'Kolibri Debugger',0 -begin_str db 'Kolibri Debugger, version 0.35',10 +begin_str db 'Kolibri Debugger, version 0.36',10 db 'Hint: type "help" for help, "quit" to quit' newline db 10,0 prompt db '> ',0 @@ -1920,6 +2022,9 @@ commands: dd aDump, OnDump, DumpSyntax, DumpHelp db CMD_WITHOUT_PARAM or CMD_WITH_PARAM or CMD_WITH_LOADED_APP + dd aBacktrace, OnBacktrace, BacktraceSyntax, BacktraceHelp + db CMD_WITHOUT_PARAM or CMD_WITH_PARAM or CMD_WITH_LOADED_APP + dd aUnassemble, OnUnassemble, UnassembleSyntax, UnassembleHelp db CMD_WITHOUT_PARAM or CMD_WITH_PARAM or CMD_WITH_LOADED_APP @@ -1999,7 +2104,8 @@ help_data_msg db 'List of data commands:',10 db 'd [] - dump data at given address',10 db 'u [] - unassemble instructions at given address',10 db 'r or',10 - db 'r = - set register value',10,0 + db 'r = - set register value',10 + db 'bt [] - display backtrace / stacktrace',10,0 ; Breakpoints commands group @@ -2057,6 +2163,11 @@ DumpHelp db 'Dump data of debugged program',10 DumpSyntax db 'Usage: d - dump data at specified address',10 db ' or: d - continue current dump',10,0 +aBacktrace db 3,'bt',0 +BacktraceHelp db 'Display backtrace / stacktrace',10 +BacktraceSyntax db 'Usage: bt - display backtrace with depth',10 + db ' or: bt display all backtrace',10,0 + aCalc db 2,'?',0 CalcHelp db 'Calculate value of expression',10 CalcSyntax db 'Usage: ? ',10,0 @@ -2121,6 +2232,11 @@ LoadSymbolsSyntax db 'Usage: load-symbols ',10,0 aUnknownCommand db 'Unknown command',10,0 +;----------------------------------------------------------------------------- +; Info messages +aBacktraceSymStub db '??',0 +aBacktraceFmt db '[0x%8X] 0x%8X in ',0 + ;----------------------------------------------------------------------------- ; Error messages @@ -2493,11 +2609,13 @@ disasm_cur_pos dd ? disasm_cur_str dd ? disasm_string rb 256 -thread_info process_information +stack_frame_dump rb sizeof.STACK_FRAME +bt_depth rd 1 ;----------------------------------------------------------------------------- ; Coordinates and sizes for GUI +thread_info process_information data_x_size_dd dd ?, ? messages_x_size_dd dd ?, ? registers_x_pos_dd dd ?, ? diff --git a/programs/develop/mtdbg/symbols.inc b/programs/develop/mtdbg/symbols.inc index bd7923f67..2b06656e1 100644 --- a/programs/develop/mtdbg/symbols.inc +++ b/programs/develop/mtdbg/symbols.inc @@ -4,6 +4,11 @@ include 'sort.inc' +struct DEBUG_SYMBOL + addr rd 1 + string rd 0 +ends + ; compare proc for sorter compare: cmpsd @@ -459,4 +464,69 @@ find_symbol_name: @@: pop esi - ret \ No newline at end of file + ret + +;----------------------------------------------------------------------------- +; +; Find the nearest symol using binary search +; +; in: eax - target addres +; out: esi - symbol name +; destroys: ebx, ecx, edx, edi, ebp +; +find_near_symbol: + mov edi, [symbols] + + xor esi, esi ; Result + mov ecx, esi ; Left + mov edx, [num_symbols] ; Right + dec edx + js .end + + ; If the first address is already greater than the target + mov ebp, [edi + ecx * sizeof.DEBUG_SYMBOL] + cmp [ebp + DEBUG_SYMBOL.addr], eax + ja .end + + ; If the last address is less than or equal to the target + mov ebp, [edi + edx * sizeof.DEBUG_SYMBOL] + cmp [ebp + DEBUG_SYMBOL.addr], eax + jbe .found + + .loop: + cmp ecx, edx + ja .end + + ; Calc middle: + mov ebx, edx ; Middle + sub ebx, ecx ; (right - left) + shr ebx, 1 ; / 2 + add ebx, ecx ; + left + + ; Equal + mov ebp, [edi + ebx * sizeof.DEBUG_SYMBOL] + cmp [ebp + DEBUG_SYMBOL.addr], eax + jz .found + jb .update_left + + ; Update right + mov edx, ebx + dec edx + jmp .loop + + .update_left: + ; Save potential result + mov esi, ebp + add esi, DEBUG_SYMBOL.string + + ; Update left + mov ecx, ebx + inc ecx + jmp .loop + + .found: + mov esi, ebp + add esi, DEBUG_SYMBOL.string + + .end: + ret