################################################# # # * How to use MorphOS 1.4.x debugging facilities # # # # v2.0 (2005/08/02) # # # # by Nicolas Sallin (henes at biclodon dot com) # # # ################################################# Chapter 1: How to get the MorphOS debug log. Chapter 2: First interpretation of a debug log. Chapter 3: How to find where the program crashed (using objdump). Chapter 4: If the crash point is not located inside the program itself. Chapter 5: A few tips. Chapter 6: A commented debug log example. Chapter 7: PowerPC Registers overview. Chapter 8: FAQ. ************************************************ * * * Chapter 1: How to get the MorphOS debug log. ******************************* * * ************************************************ There are three different but complementary ways to get the MorphOS debug log: 1) Serial debug ------------ In short: The debug output is redirected to the RS232 serial port. In details: This is the preferred debug method because it only relies on the Quark kernel availability. It works even when the rest of MorphOS is unusable and it is the only way to debug hardcore problems. Usage: There is no need to do anything special to enable it because it is the built-in default debug output. To capture debug information, you need a second computer, a nullmodem cable and a serial terminal program. The output speed is 115200 bps and serial settings are 8n1 (eight data bits, no parity, one stop bit). 2) RamDebug -------- In short: The debug output is redirected to a memory buffer. In details: The buffer is managed by the Quark kernel and located outside the ABox's memory space. It has a limited size (currently 4MB). When it fills up, it will loop around and older entries will be overwritten by new ones. Please note some firmware setups always clear memory during the warm boot process. In this case, the RAM content is not preserved and the RamDebug log is lost after a reboot. Usage: To activate RamDebug, it is required to boot from the OpenFirmware using the "ramdebug" argument. For example: boot boot.img ramdebug To take a look at the debug log, it is first needed to manually extract it using dedicated tools, such as: - "GetRamDebugLog", a basic command line tool. It is able to save the RamDebug buffer to a file. It's part of MorphOS 1.4.4 and up. - "logTool", a GUI tool. More information at http://binaryriot.com/dreamolers/logtool/ 3) LogServer --------- In short: The *exception* debug output is redirected in a console window. The LogServer is always simultaneously used with Serial or RamDebug. In details: An exception happens when a program performs an invalid memory access or executes an illegal processor instruction. The LogServer is a dedicated "Log Task" task communicating with Exec's exception-handler. Exec output is caught by the LogServer and redirected in a console window. Please note the LogServer doesn't display Alert() content and other MorphOS debug messages. Furthermore, its exception report is very limited and doesn't contain all possible information. Worse, when the LogServer is running, usual RamDebug and Serial logs are also modified and even cut down! The LogServer is meant to be used complementary with RamDebug or Serial debug... and by users only. Programmers should better not use it. Usage: To activate the LogServer when booting MorphOS, use the "logserver" argument from OpenFirmware. Exemple: boot boot.img ramdebug logserver You can ask for a bit more informative output: boot boot.img ramdebug logserver edebugflags="logextended" *************************************************** * * * Chapter 2: First interpretation of a debug log. **************************** * * *************************************************** The aim of this first read of a debug log is to identify: - the crash reason - the name of the crashed program - the location of the crash point inside the program The reference log is "hitmania.log.num" and is available in the hitmania.lha archive. 001> -------------------------------------------- 002> 003> ASM_Exception: DAR 0x0 DSISR 0xa000000 The Data Address Register (DAR) contains 0. That means the program did an illegal memory access to the address 0. 004> ASM_Exception: IntGPR1 0xc02fb8 SRR0 0x21240a34 SRR1 0xf030 LR 0x21240a5c 005> ASM_Exception: Type 0x3 006> ASM_Exception: Thread 0xe0e640 Name ABox 007> ASM_Exception: DAR 0x0 DSISR 0xa000000 008> 009> 010> ------------------------------------------------ 011> Quark Thread: 012> TID 0000000010020010 013> Name ABox 014> Exception 3 The program did an illegal memory write ("Store") to the address 0. 015> SRR0 0x21240a34 SRR1 0x0000f030 016> LR 0x21240a5c CTR 0x10115934 017> CR 0x22002022 XER 0x20000000 018> GPR[00] 212408cc 21184ba0 21185110 00000000 00000000 fffffff7 00000004 00000004 019> GPR[08] 20850000 20850000 20850000 20850000 24002022 00000000 21184d08 087805bd 020> GPR[16] 0000000a 0000000a 00000000 226e89b4 2260ce14 226e89b0 00000001 08983385 021> GPR[24] 226e89b0 08212584 2085bcb4 20850000 20850000 20850000 20850000 2260cd30 022> FPSCR 43efff0000104050 023> FPR[00] 0000000000000000 0000000000000000 f787e60fc099915d fc6f40a94a3f1345 024> FPR[04] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 025> FPR[08] 0000000000000000 3ff0000000000000 0000000000000000 3f40624dd2f1a9fc 026> FPR[12] 3ff0000000000000 4009faed64015a8b 0000000000000000 0000000000000000 027> FPR[16] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 028> FPR[20] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 029> FPR[24] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 030> FPR[28] 0000000000000000 0000000000000000 0000000000000000 216200a000157800 031> IABR 00000000 032> DABR 00000000 033> MMCR0 00000000 034> MMCR1 00000000 035> MMCR2 00000000 036> PMC1 00000000 PMC2 00000000 PMC3 00000000 PMC4 00000000 037> SIA 00000000 038> SDA 00000000 039> 040> PPCStackFrame History: 041> StackFrame[-0].LR-> Address 0x212408cc -> hitmania Hunk 1 Offset 0x000004bc 042> StackFrame[-1].LR-> Address 0x212406ac -> hitmania Hunk 1 Offset 0x0000029c 043> StackFrame[-2].LR-> Address 0x10248f5c -> Module Hunk 0 Offset 0x00148f5c 044> StackFrame[-3].LR-> Address 0x1024d9b0 -> Module Hunk 0 Offset 0x0014d9b0 045> StackFrame[-4].LR-> Address 0x1024d6b0 -> Module Hunk 0 Offset 0x0014d6b0 046> StackFrame[-5].LR-> Address 0x102b5b1c -> Module Hunk 0 Offset 0x001b5b1c 047> StackFrame[-6].LR-> Address 0x102b20e4 -> Module Hunk 0 Offset 0x001b20e4 048> StackFrame[-7].LR-> Address 0x102b1328 -> Module Hunk 0 Offset 0x001b1328 049> StackFrame[-8].LR-> Address 0x102b0dd8 -> Module Hunk 0 Offset 0x001b0dd8 050> StackFrame[-9].LR-> Address 0x10241da0 -> Module Hunk 0 Offset 0x00141da0 051> StackFrame[-10].LR-> Address 0x10241bf0 -> Module Hunk 0 Offset 0x00141bf0 052> StackFrame[-11].LR-> Address 0x10241e64 -> Module Hunk 0 Offset 0x00141e64 053> ************************************************************** 054> ************************************************************** 055> ABox State 056> Hardware: 057> Openfirmware..skip for now 058> ExecBase: SysBase 0x20000c38 059> SysFlags 0x0000c000 AttnResched 0x00000000 IDNestCnt -1 TDNestCnt -1 060> ThisTask 0x2260cd30 TaskReady 0x2002b954 TaskWait 0x200359c4 061> ResModules 0x20004dd0 062> TaskTrapCode 0x10100970 TaskExceptCode 0x10100670 TaskExitCode 0x101006cc 063> TaskSigAlloc 0xffff TaskTrapAlloc 0x8000 064> IdleCount 743136 065> DispCount 3310554 066> Quantum 4 067> Elapsed 2 068> VBlankFrequency 50 PowerSupplyFrequency 50 EClockFrequency 709379 069> MainTID 0x10020010 070> SchedulerTID 0x10020012 071> SchedulerSig 0x80000000 072> OldSRR0 0x0 073> ConfigServerTID 0x10000013 074> Int0: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 075> Int1: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 076> Int2: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 077> Int3: iv_Code 0x1010055c iv_Data 0x20004ba8 iv_Node 0x00000000 078> Int4: iv_Code 0x1010055c iv_Data 0x20004bc8 iv_Node 0x00000000 079> Int5: iv_Code 0x1010055c iv_Data 0x20004bb8 iv_Node 0x00000000 080> Interrupt 0x20012e4e 081> Code 0x101503bc Data 0x20012e04 082> Interrupt 0x208488ec 083> Code 0x2083c654 Data 0x00000000 084> Interrupt 0x204d213c 085> Code 0x204d2134 Data 0x204d2028 086> Int6: iv_Code 0x101503c4 iv_Data 0x20012e04 iv_Node 0x20012e7a 087> Int7: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 088> Int8: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 089> Int9: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 090> Int10: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 091> Int11: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 092> Int12: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 093> Int13: iv_Code 0x1010055c iv_Data 0x20004bd8 iv_Node 0x00000000 094> Int14: iv_Code 0x00000000 iv_Data 0x00000000 iv_Node 0x00000000 095> Int15: iv_Code 0x1010055c iv_Data 0x20004be8 iv_Node 0x00000000 096> ************************************************************** 097> ************************************************************** 098> ************************************************************** 099> ************************************************************** 100> 101> 102> Running Task 103> 104> 105> ************************************************************** 106> ************************************************************** 107> Task 0x2260cd30 Name 0x226e89b4 Type 13 Pri 0 The name of the crashed task is "Shell Process". 108> Flags 0x8 State 2 IDNestCnt -1 TDNestCnt -1 109> SigAlloc 0x0000ffff SigWait 0x00000100 SigRecvd 0x04008120 SigExcept 0x00000000 110> ExceptCode 0x10100670 ExceptData 0x00000000 TrapCode 0x10100970 TrapData 0x00000000 111> Switch 0x00000000 Launch 0x00000000 UserData 0x215fc21c 112> SPLower 0x21623c48 SPUpper 0x216ff7e8 SPReg 0x226e8950 113> ---------------------------------------------------------------------- 114> ETask 0x2081f2b4 115> MemPool 0x205bc788 PPCLibData 0x00000000 116> PPCSPLower 0x2117d204 PPCSPUpper 0x21185200 117> PPCTrapMsgPort 0x00000000 PPCTrapMessage 0x20774fd4 118> PPCRegFrame 0x211848e0 119> Private[] 0x00000000 0x00000000 0x00000000 0x00000000 120> EmulHandle 0x00000000 121> ---------------------------------------------------------------------- 122> EmulHandle 0x21185110 Type 0x00000004 Flags 0x00000001 123> SuperHandle 0x10001000 Type 0x00000000 WaitMask 0x00000000 SyncMask 0x00000000 124> USP 0x00000000 SSP 0x20004818 VBR 0x2000ded0 125> SFC 0x00000000 DFC 0x00000000 CACR 0x00000000 TC 0x00000000 126> ITT0 0x00000000 ITT1 0x00000000 DTT0 0x00000000 DTT1 0x00000000 127> URP 0x00000000 SRP 0x00000000 BUSCR 0x00000000 PCR 0x04310000 128> ---------------------------------------------------------------------- 129> SRR0 0x21240a34 SRR1 0x0000f030 130> LR 0x21240a5c CTR 0x10115934 131> CR 0x22002022 XER 0x20000000 132> GPR[00] 212408cc 21184ba0 21185110 00000000 00000000 fffffff7 00000004 00000004 133> GPR[08] 20850000 20850000 20850000 20850000 24002022 00000000 21184d08 087805bd 134> GPR[16] 0000000a 0000000a 00000000 226e89b4 2260ce14 226e89b0 00000001 08983385 135> GPR[24] 226e89b0 08212584 2085bcb4 20850000 20850000 20850000 20850000 2260cd30 136> SRR0 -> hitmania Hunk 1 Offset 0x00000624 The task crashed in the "hitmania" program, at offset 0x624. More information about the SRR0 register in the chapter 7. 137> LR -> hitmania Hunk 1 Offset 0x0000064c The crashed function was called from another part of the code in the "hitmania" program: around offset 0x64c. This will be explained in the chapter 4. More information about the LR register in the chapter 7. 138> CTR -> Module Hunk 0 Offset 0x00015934 139> 140> PPCStackFrame History: 141> StackFrame[-0].LR-> Address 0x212408cc -> hitmania Hunk 1 Offset 0x000004bc 142> StackFrame[-1].LR-> Address 0x212406ac -> hitmania Hunk 1 Offset 0x0000029c 143> StackFrame[-2].LR-> Address 0x10248f5c -> Module Hunk 0 Offset 0x00148f5c 144> StackFrame[-3].LR-> Address 0x1024d9b0 -> Module Hunk 0 Offset 0x0014d9b0 145> StackFrame[-4].LR-> Address 0x1024d6b0 -> Module Hunk 0 Offset 0x0014d6b0 146> StackFrame[-5].LR-> Address 0x102b5b1c -> Module Hunk 0 Offset 0x001b5b1c 147> StackFrame[-6].LR-> Address 0x102b20e4 -> Module Hunk 0 Offset 0x001b20e4 148> StackFrame[-7].LR-> Address 0x102b1328 -> Module Hunk 0 Offset 0x001b1328 149> StackFrame[-8].LR-> Address 0x102b0dd8 -> Module Hunk 0 Offset 0x001b0dd8 150> StackFrame[-9].LR-> Address 0x10241da0 -> Module Hunk 0 Offset 0x00141da0 151> StackFrame[-10].LR-> Address 0x10241bf0 -> Module Hunk 0 Offset 0x00141bf0 152> StackFrame[-11].LR-> Address 0x10241e64 -> Module Hunk 0 Offset 0x00141e64 The PPCStackFrame History lists previously executed code sections. Is is mentioned more indepth in the chapter 4. 153> Full PPC mode: Last 68k context 154> PC 87654321 SR 0008 155> Dn[0] 00000014 00100000 00002000 00000000 00000000 00000000 00000000 00000000 156> An[0] 215fc0c8 00000000 00000000 00000000 00000000 00000000 20000c38 216ff7e0 157> Stack: 0x216ff7e0 158> A7[-32] 00000000 00000000 00000000 00000000 159> A7[-16] 00000000 00000000 00000000 11328720 160> A7[000] 000dbba0 226e89b0 219317a8 0008fd78 161> A7[016] 00000000 00000000 00000000 00000000 162> A7[032] 00000000 00000000 00000000 00000000 163> A7[048] 00000000 00000000 00000000 00000000 164> A7[064] 00000000 00000000 00000000 00000000 165> A7[080] 00000000 00000000 00000000 00000000 166> A7[096] 00000000 00000000 00000000 00000000 167> A7[112] 00000000 00000000 00000000 00000000 168> Last saved PPCThread State: 169> SRR0 0x25 SRR1 0x20000c38 LR 0x2260cd30 R1 0x21184cc0 170> GPR[00] 00000030 21184cc0 21185110 21030ca0 000043b0 00010001 00000000 00000000 171> GPR[08] 00000000 20000000 21030b90 20000c38 24004029 216ff7dc 80000004 00000008 172> GPR[16] 10001000 00000004 00000000 11007000 1100859c 11008348 110084c0 1100873c 173> GPR[24] 11008748 21185110 00000000 0816f1e3 20534788 21184d28 21184cc8 20000c38 174> FPSCR 43efff0024002022 175> FPR[00] 0000000000000000 0000000000000000 f787e60fc099915d fc6f40a94a3f1345 176> FPR[04] 0000000000000000 0000000000000000 0000000000000000 0000000000000000 177> FPR[08] 0000000000000000 211849f000000000 0000000000000000 21184a101100708c 178> FPR[12] 0000000000000000 21184a1064015a8b 0000000000000000 21184b70110087ec 179> FPR[16] fffffffa88002022 0000000021184d08 087805bd0000000a 0000000a00000000 180> FPR[20] 226e89b42260ce14 226e89b000000001 08983385226e89b0 082125842085bcb4 181> FPR[24] 2085000000000000 215fc0c320850000 000000082260cd30 21184c1010253218 182> FPR[28] 0000000000000000 21184a9000000000 0000000000000000 21184ac010109390 183> CTR -> Module Hunk 0 Offset 0x000098d8 184> 185> ---------------------------------------------------------------------- 186> SegList 0x081dd3c6 GlobVec 0x202dbaf8 187> StackBase 0x08588f12 StackSize 0x000dbba0 188> TaskNum 0x00000006 Result2 0x00000000 189> CurrentDir 0x081dd3cd CIS 0x0878043b 190> COS 0x087804f3 CES 0x00000000 191> ConsoleTask 0x207754c0 FileSystemTask 0x200099ac 192> CLI 0x0878033d ReturnAddr 0x216ff7e0 193> PktWait 0x00000000 WindowPtr 0x00000000 194> HomeDir 0x081c99d1 Flags 0x00000024 195> ExitCode 0x00000000 ExitData 0x00000000 196> Arguments 0x2085bcb4 ShellPrivate 0x00000000 197> CmdName: 198> ************************************************************** 199> ************************************************************** The gathered information: - The "Shell Process" task did an illegal memory write to the address 0. - The faulty code is located at the offset 0x624 in the "hitmania" program. - The crashed code was called from another part of the code located around the offset 0x64c in the "hitmania" program. This is the basis for any debugging. It is now possible to search for the 0x624 offset in the hitmania program and to know which part of the source code is corresponding to it. ********************************************************************* * * * Chapter 3: How to find where the program crashed (using objdump). ********** * * ********************************************************************* The principle is simple: to get the crash point, it is required to locate the offset (see chapter 2) inside the disassembled program. Objdump is a tool used to disassemble programs. Please note it should only be used on unstripped binaries because they provide important information such as function names. Objdump syntax is something like: ppc-morphos-objdump --syms --reloc --disassemble-all unstripped_exe >disassembled_exe Alternatively, just use the hitmania makefile and type "make dump" to create a "hitmania.dump" file. Load the disassembled file in a text editor like MorphEd. No need to be scared by the content :-) There is no need to understand powerpc assembler to locate the crash offset. The file is a list made of three columns: - The first column is an offset. - The second column is the hexadecimal form of a PPC instruction. - The third column is the human readable form of a PPC instruction. Just search the needed offset in the first column. Then find the function it belongs to. The function name is always surrounding the columns list. In the reference log, the crash offset is 0x624: ------------------------------------------------------------------------------ 624: b0 83 00 00 sth r4,0(r3) ------------------------------------------------------------------------------ It is part of a little function called "WriteWord": ------------------------------------------------------------------------------ 00000624 : 624: b0 83 00 00 sth r4,0(r3) 628: 4e 80 00 20 blr ------------------------------------------------------------------------------ So the WriteWord() function did an illegal write to the address 0! *************************************************************************** * * * Chapter 4: If the crash point is not located inside the program itself. **** * * *************************************************************************** It can happen that the crash offset is not located inside the program. Typically, it is when performing a system call using wrong parameter or when misusing a function pointer. Hopefully, it is still possible to know the point where the program performed this system call or function pointer jump. This is achieved using the LR register. The LR register contains the address where the program will return to when it will exit from the current function. This address points to the function which called the current one. So, if the func1() function calls the func2() function and the program crashes in func2(), then SRR0 points to func2() and LR points to func1(). int main(void) { WriteWord(NULL, 0); ReadLong((ULONG *)0xFFFFFFFF); return 0; } When the above "hitmania" program crashes in the WriteWord() function, then the SRR0 register contains an address pointing to the WriteWord() function and the LR register contains an address pointing to the main() function. ------------------------------------------------------------------------------ 136> SRR0 -> hitmania Hunk 1 Offset 0x00000624 137> LR -> hitmania Hunk 1 Offset 0x0000064c ------------------------------------------------------------------------------ 0x624 is in WriteWord() as seen in the chapter 3 0x64c is in main() If the program is a bit more complex and calls a func1() function calling a func2() function calling a func3() function where it crashes, then SRR0 will point to func3() and LR will point to func2(). But no register will contain a reference to func1(). But there is a way to trace all previous functions and get a reference to func1(). This is achieved using the "stack frame". Everytime a new function is executed, the program allocates a new stack frame where it saves the current context. The content of the LR register is also saved in the stack frame. So, by analyzing previous stack frames, it is possible to know previous LR contents and to trace the program. When a crash happens, MorphOS fetchs all possible information from the stack frames and displays it: 136> SRR0 -> hitmania Hunk 1 Offset 0x00000624 137> LR -> hitmania Hunk 1 Offset 0x0000064c 138> CTR -> Module Hunk 0 Offset 0x00015934 139> 140> PPCStackFrame History: 141> StackFrame[-0].LR-> Address 0x212408cc -> hitmania Hunk 1 Offset 0x000004bc 142> StackFrame[-1].LR-> Address 0x212406ac -> hitmania Hunk 1 Offset 0x0000029c That means the current content of the LR register is 0x64c (the func3 function). Its previous content was 0x4bc (the func2 function). And just before, it was 0x29c (the func1 function). To debug a program crashed in some foreign code, simply look at the LR content until there is an address inside the program code. If there is no such address in the stack frame, then read the questions about hardcore problems in the FAQ (chapter 8). ************************** * * * Chapter 5: A few tips. ***************************************************** * * ************************** This section is supposed to cover: - --demangle - abadcafe - -O0 usefulness - r2 usage for tracking 68k abi system calls - stackframe - Emulation module - 3 log levels: quark, abox, exec - "Emul: Time" crash due to an illegal access to 0xdeadf00d+offset... forgot AbortIO+WaitIO before DeleteIORequest() - "trance crashed !!", of course not... - stack overflow - maxhits usage to avoid looping ramdebug buffer - new getlog options - invzeropage and 1.4.4+ - tasklist stacktrace - and more... But supposed only... so feel free to write it yourself :-) ******************************************** * * * Chapter 6: A commented debug log example *********************************** * * ******************************************** ------------------------------------------------------------------------------ 003> ASM_Exception: DAR 0x0 DSISR 0xa000000 004> ASM_Exception: IntGPR1 0xc02fb8 SRR0 0x21240a34 SRR1 0xf030 LR 0x21240a5c 005> ASM_Exception: Type 0x3 006> ASM_Exception: Thread 0xe0e640 Name ABox 007> ASM_Exception: DAR 0x0 DSISR 0xa000000 ------------------------------------------------------------------------------ 001-010: ASM_Exception This debug comes from the Quark kernel and will always happen, even if the ABox and Exec are badly trashed. Most important information is: - DAR (the last accessed invalid address) - Exception Type. Most common ones are: DATAACCESS 0x3 when accessing data from/to invalid memory INSTACCESS 0x4 when running code from invalid memory PROGRAM 0x7 when trying to execute an invalid instruction ------------------------------------------------------------------------------ 011> Quark Thread: 012> TID 0000000010020010 013> Name ABox 014> Exception 3 ------------------------------------------------------------------------------ 011-097: The PowerPC is a RISC CPU family using a load/store architecture. An illegal memory access can be caused by a load (memory read) or a store (memory write) operation. This debug comes from ABox's exception-handler. 098-199: Running Task This debug comes from Exec's exception-handler and is a dump of the faulty task's state. ------------------------------------------------------------------------------ 107> Task 0x2260cd30 Name 0x226e89b4 Type 13 Pri 0 108> Flags 0x8 State 2 IDNestCnt -1 TDNestCnt -1 109> SigAlloc 0x0000ffff SigWait 0x00000100 SigRecvd 0x04008120 SigExcept 0x00000000 110> ExceptCode 0x10100670 ExceptData 0x00000000 TrapCode 0x10100970 TrapData 0x00000000 111> Switch 0x00000000 Launch 0x00000000 UserData 0x215fc21c 112> SPLower 0x21623c48 SPUpper 0x216ff7e8 SPReg 0x226e8950 ------------------------------------------------------------------------------ 107-112: Dump of Exec Task structure. 107: Name of the task that caused the crash. 109: task's signals You can take a look at SigAlloc (allocated signals mask) and SigWait (wait signals mask) to know if the task was waiting for some specific signal (see exec.doc/AllocSignal and exec.doc/Wait). 112: task's 68k stack boundaries, a7 being the stack pointer For more information, see "struct Task" in exec/tasks.h header file. ------------------------------------------------------------------------------ 114> ETask 0x2081f2b4 115> MemPool 0x205bc788 PPCLibData 0x00000000 116> PPCSPLower 0x2117d204 PPCSPUpper 0x21185200 117> PPCTrapMsgPort 0x00000000 PPCTrapMessage 0x20774fd4 118> PPCRegFrame 0x211848e0 119> Private[] 0x00000000 0x00000000 0x00000000 0x00000000 120> EmulHandle 0x00000000 ------------------------------------------------------------------------------ 114-120: Dump of Exec Task Extension structure. 116: task's PPC stack boundaries, r1 being the stack pointer For more information, see "struct ETask" in exec/tasks.h header file. ------------------------------------------------------------------------------ 122> EmulHandle 0x21185110 Type 0x00000004 Flags 0x00000001 123> SuperHandle 0x10001000 Type 0x00000000 WaitMask 0x00000000 SyncMask 0x00000000 124> USP 0x00000000 SSP 0x20004818 VBR 0x2000ded0 125> SFC 0x00000000 DFC 0x00000000 CACR 0x00000000 TC 0x00000000 126> ITT0 0x00000000 ITT1 0x00000000 DTT0 0x00000000 DTT1 0x00000000 127> URP 0x00000000 SRP 0x00000000 BUSCR 0x00000000 PCR 0x04310000 ------------------------------------------------------------------------------ 122 : The r2 register always contains a pointer to the EmulHandle structure. 124-127: Dump of some virtual 68k registers. ------------------------------------------------------------------------------ 129> SRR0 0x21240a34 SRR1 0x0000f030 130> LR 0x21240a5c CTR 0x10115934 131> CR 0x22002022 XER 0x20000000 132> GPR[00] 212408cc 21184ba0 21185110 00000000 00000000 fffffff7 00000004 00000004 133> GPR[08] 20850000 20850000 20850000 20850000 24002022 00000000 21184d08 087805bd 134> GPR[16] 0000000a 0000000a 00000000 226e89b4 2260ce14 226e89b0 00000001 08983385 135> GPR[24] 226e89b0 08212584 2085bcb4 20850000 20850000 20850000 20850000 2260cd30 ------------------------------------------------------------------------------ 129-135: Dump of PowerPC registers. 129-131: content of SRR0, LR, etc. registers 132: content of r0 to r7 registers 133: content of r8 to r15 registers 134: content of r16 to r23 registers 135: content of r24 to r31 registers ------------------------------------------------------------------------------ 136> SRR0 -> hitmania Hunk 1 Offset 0x00000624 137> LR -> hitmania Hunk 1 Offset 0x0000064c 138> CTR -> Module Hunk 0 Offset 0x00015934 ------------------------------------------------------------------------------ 136-138: SegTracker information For SRR0, LR and CTR registers, tells where the address points to. Could be inside MorphOS or in a user executable. Includes name, hunk and offset. So, by looking at this information, it's possible to know the place where this task crashed (SRR0) and the code it was previously executing (LR). The chapter 3 and the chapter 4 explain how to use this information. ------------------------------------------------------------------------------ 140> PPCStackFrame History: 141> StackFrame[-0].LR-> Address 0x212408cc -> hitmania Hunk 1 Offset 0x000004bc 142> StackFrame[-1].LR-> Address 0x212406ac -> hitmania Hunk 1 Offset 0x0000029c 143> StackFrame[-2].LR-> Address 0x10248f5c -> Module Hunk 0 Offset 0x00148f5c 144> StackFrame[-3].LR-> Address 0x1024d9b0 -> Module Hunk 0 Offset 0x0014d9b0 145> StackFrame[-4].LR-> Address 0x1024d6b0 -> Module Hunk 0 Offset 0x0014d6b0 146> StackFrame[-5].LR-> Address 0x102b5b1c -> Module Hunk 0 Offset 0x001b5b1c 147> StackFrame[-6].LR-> Address 0x102b20e4 -> Module Hunk 0 Offset 0x001b20e4 148> StackFrame[-7].LR-> Address 0x102b1328 -> Module Hunk 0 Offset 0x001b1328 149> StackFrame[-8].LR-> Address 0x102b0dd8 -> Module Hunk 0 Offset 0x001b0dd8 150> StackFrame[-9].LR-> Address 0x10241da0 -> Module Hunk 0 Offset 0x00141da0 151> StackFrame[-10].LR-> Address 0x10241bf0 -> Module Hunk 0 Offset 0x00141bf0 152> StackFrame[-11].LR-> Address 0x10241e64 -> Module Hunk 0 Offset 0x00141e64 ------------------------------------------------------------------------------ 140-152: PPCStackFrame Basically, it's the stack backtrace (previous LR content). So, it's all previous places the code was going through. If it would return from the current function, this task would run the code pointed to by LR. And when returning from the function pointed to by LR, it would run the code pointed to by StackFrame[-0].LR, then by StackFrame[-1].LR, and so on... -------------------------------------------------------------------------------- 153> Full PPC mode: Last 68k context 154> PC 87654321 SR 0008 155> Dn[0] 00000014 00100000 00002000 00000000 00000000 00000000 00000000 00000000 156> An[0] 215fc0c8 00000000 00000000 00000000 00000000 00000000 20000c38 216ff7e0 157> Stack: 0x216ff7e0 158> A7[-32] 00000000 00000000 00000000 00000000 159> A7[-16] 00000000 00000000 00000000 11328720 160> A7[000] 000dbba0 226e89b0 219317a8 0008fd78 161> A7[016] 00000000 00000000 00000000 00000000 162> A7[032] 00000000 00000000 00000000 00000000 163> A7[048] 00000000 00000000 00000000 00000000 164> A7[064] 00000000 00000000 00000000 00000000 165> A7[080] 00000000 00000000 00000000 00000000 166> A7[096] 00000000 00000000 00000000 00000000 167> A7[112] 00000000 00000000 00000000 00000000 ------------------------------------------------------------------------------ 153-167: Dump of 68k context If no 68k code was executed, this part will be useless. Otherwise, it contains d0 to d7 and a0 to a7 registers content, 68k program counter in PC register, 68k stackframe, and so on... Note that stack is also displayed from the negative, unused side (it could sometimes contain useful information). Stack pointer itself points to A7[000]. 168-183: Ignore this part for now. ------------------------------------------------------------------------------ 186> SegList 0x081dd3c6 GlobVec 0x202dbaf8 187> StackBase 0x08588f12 StackSize 0x000dbba0 188> TaskNum 0x00000006 Result2 0x00000000 189> CurrentDir 0x081dd3cd CIS 0x0878043b 190> COS 0x087804f3 CES 0x00000000 191> ConsoleTask 0x207754c0 FileSystemTask 0x200099ac 192> CLI 0x0878033d ReturnAddr 0x216ff7e0 193> PktWait 0x00000000 WindowPtr 0x00000000 194> HomeDir 0x081c99d1 Flags 0x00000024 195> ExitCode 0x00000000 ExitData 0x00000000 196> Arguments 0x2085bcb4 ShellPrivate 0x00000000 197> CmdName: ------------------------------------------------------------------------------ 185-197: Dump of DOS Process structure Only if the crash happened for a dos process. Also contains the program name (CmdName), from shell. ****************************************** * * * Chapter 7: PowerPC Registers overview. ************************************* * * ****************************************** - GPRs - General-Purpose Registers FPRs - Floating-Point Registers There are 64 of them: 32 integer registers (GPR0 to GPR31) and 32 floating- point registers (FPR0 to FPR31). It's common usage to name them r0 to r31 (integers) and f0 to f31 (floats). MorphOS uses the standard System V.4 ABI. This defines how registers are used. A complete description of the ABI is available in the MorphOS SDK: SDK:Documentation/Articles/Porting/PowerOpenAPI.txt In short: The first integer argument of a function is in r3, the second is in r4, the third is in r5... The first floating-point argument is in f1, the second is in f2, etc... The function return value is in r3 if it's an integer and in f1 if it's a float. r2 contains MorphOS' EmulHandle pointer and must always be preserved. All emulated 68k registers (d0 to d7 and a0 to a7) are available through it. They can also be directly mapped on PowerPC registers (r16 to r31). For more information about MorphOS specific points, please take a look at SDK:Documentation/Articles/Porting/MorphOS.txt file. - DAR - Data Address Register Contains the invalid address which was accessed and caused the exception. - SRR0 - Machine Status Save/Restore Register 0 On an exception, it contains the address of the instruction which caused it. This is the most important register when debugging. - LR - Link Register When calling a sub-routine, LR contains the address of the instruction following the calling one. So LR points to the instruction executed after the program returns from the current sub-function. With this register, it's possible to track all functions executed before the current one. - CTR - Count Register Often used to implement loops. In that case, it contains the loop count. For more complete information about PowerPC internal, please take a look at Freescale manual: http://www.freescale.com/files/32bit/doc/user_guide/MPCFPE_AD_R1.pdf ****************** * * * Chapter 8: FAQ ************************************************************* * * ****************** Debug bases: Q: What is a hit? A: If a program is accessing the zero-page (also called the low-page) or any non-available memory, it will create a hit. Basically, a hit is the report of an illegal memory access. Hits are never harmless. They are program bugs and must be fixed. Q: What are Enforcer, Cyberguard and all these MMU tools? A: They are very hardware specific tools watching for illegal memory access. Do not use them! The same functionality is already built-in MorphOS and is always active. Q: What's SegTracker? A: This tool tracks all code locations. When something is loaded in memory, address is stored and put in a database. Then MorphOS uses it to display the name of a crashed module. It's possible to more easily identify where hits come from: libraries, devices, handlers, etc SegTracker functionnality is built-in MorphOS and is always active. Q: MorphOS doesn't seem to detect read-access to address 0. Is it normal? A: Yes, MorphOS doesn't read-protect zero page; yet. It write-protects it though. The memtracker: Q: What is the memtracker? A: It is a powerfull debug tool built-in MorphOS. It tracks memory allocations and reports wrong freeing sizes and mismatching pointers. Activate it by using the MorphOS' EDebugFlags boot argument. EDebugFlags="permmemtrack" permanently activates memtracker. EDebugFlags="permmemtrack memtrack" also activates memtracker's output. When memtracker is used (EDebugFlags="permmemtrack"), it is possible to disable/enable its output on the fly, using SystemSettings/Debug/MemTrack. When permmemtrack is not used, memtrack still toggles memtracker on/off but it won't notice invalid freeing of memory. Please note the memtracker fills all free memory using the 0xABADCAFE pattern. It helps to catch uninitialised pointers, or using already free memory. Q: Why does the system become slower when the memtracker is enabled? A: The memtracker involves a lot of extra operations during memory allocation and deallocation. It is a pure debug tool. Only use it when you need to track a problem or when you want to check your memory management correctness. Debug tools: Q: Objdump is slow when processing big executable files. Is it possible to speed it up? A: Yes. It can be restricted to dump only a certain address range around an offset. Just type "objdump" in a shell and read its argument-options. You are looking for the --start-address=addr and --stop-address=addr ones. Example: objdump program -disassemble-all --start-address=10000 --stop-address=20000 >program.dump Q: Objdump crashed, how is it possible to debug anyway? A: It seems there is a problem with objdump. You can workaround it by restricting the dump to a smaller range. See above. Q: How do I use FindHit? A: You can't. Please use objdump for now. Q: I heard about addr2line. Can it be used like FindHit? A: There is a problem with addr2line and it isn't reliable. But CISC is working on it. :-) kprintf: Q: How can I output my own debug information? I used to use kprintf(). A: You can still use kprintf(). It is in libdebug.a Q: How do I capture kprintf() output? A: Use sushi/sashimi or use EDebugFlags="logkprintf" MorphOS boot argument. Example: boot boot.img EDebugFlags="logkprintf" Q: I heard about dprintf() but how can I use it? A: You do not. There is no such a public function. Please use kprintf(). Weird error messages in the log: Q: Why do I get "PPC Stack Ptr is not between PPCSPLower and PPCSPUpper" message? A: It means the PPC stack pointer is out of bound. Perhaps the program used too much PPC stack and did a stack overflow. Or the r1 register got trashed (r1 is the PPC stack pointer, as defined by the SystemV ABI). This can also happen if a program uses setjmp() or any other function playing with the stack. Q: Why do I get "68k Stack Ptr is not between SPLower and SPUpper" messsage? A: Perhaps the program used too much 68k stack and overflowed it. Or the a7 register got trashed (a7 is the 68k stack pointer). This can also happen if a program uses a non-standard way to swap the stack. AmigaE applications are known to do it. Then this is not a bug, of course. Q: Why do I get "Error: TaskEmulHandle 0x00000000 is not a legal address"? A: EmulHandle is the 68k emulation's entry-point and its address is stored in r2. It must always be valid. If it is not; r2 register got trashed. 68k emulation: Q: Why do I see offset referring to "Emulation" or "Module"? A: If an offset is in "Emulation". It means the static emulator was running some 68k code and you should look at the 68k part of the debug log. If an offset is in "Module", it simply means that it is somewhere in the MorphOS module ROM: exec, dos, intuition, sfs... Q: MorphOS has a JIT emulator. When 68k code crashed, what should I look for; PPC or 68k code? A: 68k code. But, when Trance is running, the PC register is referring to the start of the translated code-block. This is probably not exactly the point where the crash happened but it's the only available reference to it. You might want to try disabling JIT to get the precise location of the problem. Hardcore problems: Q: I have a really complex crash and much more StackFrame would be needed to track the problem in my code. What is it possible to do? A: There is a BackTraceDepth argument to choose the amount of displayed StackFrame. See the documentation in SYS:Docs/PegasosFirmware.txt Example: boot boot.img BackTraceDepth=10 Q: The system freezes, there is no console window and I can't get the ramdebug log. A: It may be possible to get the ramdebug log after a reboot if the firmware didn't clear the memory. It all depends on your hardware setup. But the best solution is to use serial debug. Q: What is the meaning of "FAQ" ? A: Frequently Asked Questions. ******************************************************************************