initial import
[picodrive.git] / platform / uiq2 / debug.cpp
1 \r
2 #include <e32svr.h> // RDebug\r
3 #include "debug.h"\r
4 \r
5 #ifdef __WINS__\r
6 \r
7 void ExceptionHandler(TExcType exc) {}\r
8 \r
9 #else\r
10 \r
11 static const wchar_t * const exception_names[] = {\r
12         L"General",\r
13         L"IntegerDivideByZero",\r
14         L"SingleStep",\r
15         L"BreakPoint",\r
16         L"IntegerOverflow",\r
17         L"BoundsCheck",\r
18         L"InvalidOpCode",\r
19         L"DoubleFault",\r
20         L"StackFault",\r
21         L"AccessViolation",\r
22         L"PrivInstruction",\r
23         L"Alignment",\r
24         L"PageFault",\r
25         L"FloatDenormal",\r
26         L"FloatDivideByZero",\r
27         L"FloatInexactResult",\r
28         L"FloatInvalidOperation",\r
29         L"FloatOverflow",\r
30         L"FloatStackCheck",\r
31         L"FloatUnderflow",\r
32         L"Abort",\r
33         L"Kill",\r
34         L"DataAbort",\r
35         L"CodeAbort",\r
36         L"MaxNumber",\r
37         L"InvalidVector",\r
38         L"UserInterrupt",\r
39         L"Unknown"\r
40 };\r
41 \r
42 \r
43 static void getASpace(TUint *code_start, TUint *code_end, TUint *stack_start, TUint *stack_end)\r
44 {\r
45         TUint pc, sp;\r
46         RChunk chunk;\r
47         TFullName chunkname;\r
48         TFindChunk findChunk(_L("*"));\r
49 \r
50         asm volatile ("str pc, %0" : "=m" (pc) );\r
51         asm volatile ("str sp, %0" : "=m" (sp) );\r
52 \r
53         while( findChunk.Next(chunkname) != KErrNotFound ) {\r
54                 chunk.Open(findChunk);\r
55                 if((TUint)chunk.Base()+chunk.Bottom() < pc && pc < (TUint)chunk.Base()+chunk.Top()) {\r
56                         if(code_start) *code_start = (TUint)chunk.Base()+chunk.Bottom();\r
57                         if(code_end)   *code_end   = (TUint)chunk.Base()+chunk.Top();\r
58                 } else\r
59                 if((TUint)chunk.Base()+chunk.Bottom() < sp && sp < (TUint)chunk.Base()+chunk.Top()) {\r
60                         if(stack_start) *stack_start = (TUint)chunk.Base()+chunk.Bottom();\r
61                         if(stack_end)   *stack_end   = (TUint)chunk.Base()+chunk.Top();\r
62                 }\r
63                 chunk.Close();\r
64         }\r
65 }\r
66 \r
67 // tmp\r
68 #if defined(__DEBUG_PRINT)\r
69 extern "C" char *debugString();\r
70 #endif\r
71 \r
72 // our very own exception handler\r
73 void ExceptionHandler(TExcType exc)\r
74 {\r
75         TUint lr, sp, i;\r
76         TUint stack_end = 0;                            // ending address of our stack chunk\r
77         TUint code_start = 0, code_end = 0; // starting and ending addresses of our code chunk\r
78         TUint guessed_address = 0;\r
79 \r
80         asm volatile ("str lr, %0" : "=m" (lr) );\r
81         asm volatile ("str sp, %0" : "=m" (sp) );\r
82 \r
83         // first get some info about the chunks we live in\r
84         getASpace(&code_start, &code_end, 0, &stack_end);\r
85 \r
86         // now we begin some black magic tricks\r
87         // we go up our stack until we pass our caller address\r
88         for(; sp < stack_end; sp += 4)\r
89                 if(*(TUint *)sp == lr) break;\r
90 \r
91         // there might be mirored caller address\r
92         for(i = sp + 4; i < sp + 0x300 && i < stack_end; i += 4)\r
93                 if(*(TUint *)i == lr) { sp = i; break; }\r
94 \r
95         // aah, it is always 0x9c bytes away from the caller address in my firmware,\r
96         // don't know how to detect it in any other way\r
97         sp += 0x9c;\r
98         guessed_address = *(TUint *)sp;\r
99 \r
100         // output the info\r
101         TUint exec_show = exc;\r
102         if(exec_show > 27) exec_show = 27;\r
103         TPtrC ptrExc((TUint16 *) exception_names[exec_show]);\r
104 \r
105         RDebug::Print(_L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start);\r
106 #ifdef __DEBUG_PRINT_FILE\r
107         DEBUGPRINT(   _L("!!!Exception %i (%S) @ 0x%08x (guessed; relative=0x%08x)"), exc, &ptrExc, guessed_address, guessed_address - code_start);\r
108 #endif\r
109 \r
110         TBuf<148> buff1;\r
111         TBuf<10>  buff2;\r
112         buff1.Copy(_L("  guessed stack: "));\r
113 \r
114         for(sp += 4, i = 0; i < 5 && sp < stack_end; sp += 4) {\r
115                 if((*(TUint *)sp >> 28) == 5) {\r
116                         if(i++) buff1.Append(_L(", "));\r
117                         buff2.Format(_L("0x%08x"), *(TUint *)sp);\r
118                         buff1.Append(buff2);\r
119                 }\r
120                 else if(code_start < *(TUint *)sp && *(TUint *)sp < code_end) {\r
121                         if(i++) buff1.Append(_L(", "));\r
122                         buff2.Format(_L("0x%08x"), *(TUint *)sp);\r
123                         buff1.Append(buff2);\r
124                         buff1.Append(_L(" ("));\r
125                         buff2.Format(_L("0x%08x"), *(TUint *)sp - code_start);\r
126                         buff1.Append(buff2);\r
127                         buff1.Append(_L(")"));\r
128                 }\r
129         }\r
130         RDebug::Print(_L("%S"), &buff1);\r
131 #ifdef __DEBUG_PRINT_FILE\r
132         DEBUGPRINT(_L("%S"), &buff1);\r
133 #endif\r
134 \r
135         // tmp\r
136 #if defined(__DEBUG_PRINT)\r
137         char *ps, *cstr = debugString();\r
138         for(ps = cstr; *ps; ps++) {\r
139           if(*ps == '\n') {\r
140             *ps = 0;\r
141             dprintf(cstr);\r
142                 cstr = ps+1;\r
143           }\r
144         }\r
145 #endif\r
146 \r
147 //      RDebug::Print(_L("Stack dump:"));\r
148 //      asm volatile ("str sp, %0" : "=m" (sp) );\r
149 //      for(TUint i = sp+0x400; i >= sp-16; i-=4)\r
150 //              RDebug::Print(_L("%08x: %08x"), i, *(int *)i);\r
151 \r
152         // more descriptive replacement of "KERN-EXEC 3" panic\r
153         buff1.Format(_L("K-EX3: %S"), &ptrExc);\r
154         User::Panic(buff1, exc);\r
155 }\r
156 \r
157 #endif // ifdef __WINS__\r
158 \r
159 \r
160 #if defined(__DEBUG_PRINT) || defined(__WINS__)\r
161 \r
162 #ifndef __DLL__\r
163         // c string dumper for RDebug::Print()\r
164         static  TBuf<1024> sTextBuffer;\r
165         TDesC* DO_CONV(const char* s)\r
166         {\r
167                 TPtrC8  text8((TUint8*) (s));\r
168                 sTextBuffer.Copy(text8);\r
169                 return &sTextBuffer;\r
170         }\r
171 #endif\r
172 \r
173 #ifdef __DEBUG_PRINT_C\r
174         #include <stdarg.h> // va_*\r
175         #include <stdio.h>  // vsprintf\r
176 \r
177         // debug print from c code\r
178         extern "C" void dprintf(char *format, ...)\r
179         {\r
180                 va_list args;\r
181                 char    buffer[512];\r
182 \r
183                 va_start(args,format);\r
184                 vsprintf(buffer,format,args);\r
185                 va_end(args);\r
186 \r
187                 DEBUGPRINT(_L("%S"), DO_CONV(buffer));\r
188         }\r
189 #endif\r
190 \r
191 #ifdef __DEBUG_PRINT_FILE\r
192         #include <f32file.h>\r
193 \r
194         // note: uses tls, leaks some mem\r
195         void debugPrintFileInit()\r
196         {\r
197                 RFs *fs = new(ELeave) RFs;\r
198                 fs->Connect();\r
199                 RFile *file = new(ELeave) RFile;\r
200                 // try to open\r
201                 TInt    res = file->Open(*fs, _L("C:\\documents\\Media files\\other\\snes9x.log"), EFileWrite|EFileShareAny);\r
202                 if(res) res = file->Open(*fs, _L("C:\\snes9x.log"), EFileWrite|EFileShareAny);\r
203                 if(!res) { TInt size; file->Size(size); file->Seek(ESeekStart, size); }\r
204                 // try to create\r
205                 if(res) res = file->Create(*fs, _L("C:\\documents\\Media files\\other\\snes9x.log"), EFileWrite|EFileShareAny);\r
206                 if(res) res = file->Create(*fs, _L("C:\\snes9x.log"), EFileWrite|EFileShareAny);\r
207                 Dll::SetTls(res ? 0 : file);\r
208         }\r
209 \r
210         // debug print to file\r
211         void debugPrintFile(TRefByValue<const TDesC> aFmt, ...)\r
212         {\r
213                 // get RFile\r
214                 RFile *file = (RFile *) Dll::Tls();\r
215                 if(!file) return; // shit!\r
216 \r
217                 TTime now; now.UniversalTime();\r
218                 TBuf<512>  tmpBuff;\r
219                 TBuf8<512> tmpBuff8;\r
220                 TInt size;\r
221 \r
222                 file->Size(size); file->Seek(ESeekStart, size); // something else could have written to the file\r
223 \r
224                 now.FormatL(tmpBuff, _L("%H:%T:%S.%C: "));\r
225                 tmpBuff8.Copy(tmpBuff);\r
226                 file->Write(tmpBuff8);\r
227 \r
228                 VA_LIST args;\r
229                 VA_START(args, aFmt);\r
230                 tmpBuff.FormatList(aFmt, args);\r
231                 VA_END(args);\r
232                 tmpBuff8.Copy(tmpBuff);\r
233                 file->Write(tmpBuff8);\r
234 \r
235                 file->Write(TPtrC8((TUint8 const *) "\r\n"));\r
236                 file->Flush();\r
237         }\r
238 #endif\r
239 \r
240 #endif\r
241 \r