Debugging pascal code on android lazarus / 43-Android ---------------------------------------------------------------------- chronozphere · 2011-11-24 11:10 Hey everybody, I just tested to see if I could resolve a stacktrace generated by a buggy program. Like it's done in the wiki: http://wiki.lazarus.freepascal.org/Android_Interface#My_Pascal_applica tion_crashed._How_to_get_a_stacktrace.3F However, the stack that logcat returns looks quite different from the one on that page: Code: [Select]I/DEBUG (12825): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG (12825): Build fingerprint: 'asus/WW_epad/TF101:3.2.1/HTK75/ WW_epad-8.6.5.19-20111107:user/release-keys' I/DEBUG (12825): pid: 14315, tid: 14315 >>> com.example.exception <<< I/DEBUG (12825): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000 I/DEBUG (12825): r0 00000000 r1 807766d8 r2 00000000 r3 57aeccae I/DEBUG (12825): r4 807766d8 r5 00000004 r6 be9ea550 r7 56436cb4 I/DEBUG (12825): r8 be9ea488 r9 56436cac 10 56436c94 fp be9ea394 I/DEBUG (12825): ip be9ea398 sp be9ea318 lr 80709e7c pc 80709e88 cpsr 60000010 I/DEBUG (12825): d0 0000006442c80000 d1 3ff0000042c80000 I/DEBUG (12825): d2 4e19a0dc42becd2d d3 42c8000000670ff0 I/DEBUG (12825): d4 000001fd00625278 d5 3fe999999999999a I/DEBUG (12825): d6 3fe8000000000000 d7 3f8000003f800000 I/DEBUG (12825): d8 0000000000000000 d9 0000000000000000 I/DEBUG (12825): d10 0000000000000000 d11 0000000000000000 I/DEBUG (12825): d12 0000000000000000 d13 0000000000000000 I/DEBUG (12825): d14 0000000000000000 d15 0000000000000000 I/DEBUG (12825): scr 60000012 I/DEBUG (12825): I/DEBUG (12825): #00 pc 00009e88 /data/data/com.example.exception/lib/libexception.so (P$EXCEPTION_ERRONIOUSCALL) I/DEBUG (12825): #01 lr 80709e7c /data/data/com.example.exception/lib/libexception.so I/DEBUG (12825): I/DEBUG (12825): libc base address: aff00000 I/DEBUG (12825): I/DEBUG (12825): code around pc: I/DEBUG (12825): 80709e68 e50b002c eb00a955 e1a04000 e24b0068 I/DEBUG (12825): 80709e78 eb005b1d e3a00000 e50b0068 e51b002c I/DEBUG (12825): 80709e88 e5901000 e24b0068 eb00dac9 e51b2068 I/DEBUG (12825): 80709e98 e1a01004 e3a00000 eb00aba5 eb00903c I/DEBUG (12825): 80709ea8 e1a00004 eb00a9af eb009039 eb00824d I/DEBUG (12825): I/DEBUG (12825): code around lr: I/DEBUG (12825): 80709e5c e3500000 1a000013 e3a00000 e50b002c I/DEBUG (12825): 80709e6c eb00a955 e1a04000 e24b0068 eb005b1d I/DEBUG (12825): 80709e7c e3a00000 e50b0068 e51b002c e5901000 I/DEBUG (12825): 80709e8c e24b0068 eb00dac9 e51b2068 e1a01004 I/DEBUG (12825): 80709e9c e3a00000 eb00aba5 eb00903c e1a00004 I/DEBUG (12825): I/DEBUG (12825): stack: I/DEBUG (12825): be9ea2d8 fffffffc I/DEBUG (12825): be9ea2dc 0013acb0 I/DEBUG (12825): be9ea2e0 0000046c I/DEBUG (12825): be9ea2e4 58d9c7f0 I/DEBUG (12825): be9ea2e8 a80236b7 /system/lib/libutils.so I/DEBUG (12825): be9ea2ec a8023f7b /system/lib/libutils.so I/DEBUG (12825): be9ea2f0 00000000 I/DEBUG (12825): be9ea2f4 0008d538 I/DEBUG (12825): be9ea2f8 00000007 I/DEBUG (12825): be9ea2fc 000011b0 I/DEBUG (12825): be9ea300 00000001 I/DEBUG (12825): be9ea304 be9ea4a8 I/DEBUG (12825): be9ea308 00000004 I/DEBUG (12825): be9ea30c be9ea550 I/DEBUG (12825): be9ea310 df002777 I/DEBUG (12825): be9ea314 e3a070ad I/DEBUG (12825): #00 be9ea318 00000000 I/DEBUG (12825): be9ea31c 00000000 I/DEBUG (12825): be9ea320 00a00000 I/DEBUG (12825): be9ea324 00000000 I/DEBUG (12825): be9ea328 00000000 I/DEBUG (12825): be9ea32c 00000000 I/DEBUG (12825): be9ea330 00000000 I/DEBUG (12825): be9ea334 be9ea4a8 I/DEBUG (12825): be9ea338 00000004 I/DEBUG (12825): be9ea33c be9ea550 I/DEBUG (12825): be9ea340 56436cb4 I/DEBUG (12825): be9ea344 be9ea488 I/DEBUG (12825): be9ea348 56436cac I/DEBUG (12825): be9ea34c 56436c94 I/DEBUG (12825): be9ea350 be9ea394 I/DEBUG (12825): be9ea354 be9ea318 I/DEBUG (12825): be9ea358 80709e58 /data/data/com.example.exception/lib/libexception.so I/DEBUG (12825): be9ea35c be9ea334 I/ActivityManager( 134): Start proc android.process.media for service com.android.providers.media/.MtpService: pid=14323 uid=10031 gids={1015, 1023, 1024, 2001, 3003} I/ActivityThread(14323): Pub media: com.android.providers.media.MediaProvider etc etc... The stacktrace in the wiki seems like a long list of symbols that simply need to be resolved by GDB. What I've got here looks more like a stackdump. A long list of (address, data) pairs, from what I can tell. This could also be a regular core dump (never seen them actually). The NDK has a special script "ndk-stack" which should do this, but this doesn't work for my pascal program. It probably doesn't have the right debug symbols. I compiled with "-g -gl -gw". Is there any other way to make GDB resolve this? Thanks ---------------------------------------------------------------------- chronozphere · 2011-11-24 11:45 I've found this: http://www.lindusembedded.com/blog/2011/08/04/debugging-android-core- dumps/ My dump contained a program counter value: Code: [Select]I/DEBUG (12825): #00 pc 00009e88 /data/data/com.example.exception/lib/libexception.so (P$EXCEPTION_ERRONIOUSCALL) So I did: Code: [Select]addr2line -f -e libs/armeabi/libexception.so 00009e88 ERRONIOUSCALL /home/nathan/android/exceptiontest/jni//exception.dpr:13 Unfortunately, my dump contains only one pc, which will only tell me the line at which it crashed, not a full stacktrace. Edit: this step is not neccesary actually, since the name was also printed in the log. The name of the procedure that contained the error is: ERRONIOUSCALL ---------------------------------------------------------------------- felipemdc · 2011-11-24 12:27 It is the same thing only in a different format, just use lazstacktrace. It was built for a different format, so just change it to support this other format too. ---------------------------------------------------------------------- chronozphere · 2011-11-24 13:04 Are you sure that it's only the presentation that is different? The mem-addresses in the wiki example seem like locations relative to the base address of the library. The ones I have are look like memory adresses (location of library in ram + location of symbol). I tested a few of the values with the command: Code: [Select]gdb --batch "--eval-command=info symbol 0x
" libs/armeabi/libexception.so as is used by lazstacktrace. But it cant find any symbols. ---------------------------------------------------------------------- felipemdc · 2011-11-24 13:22 ummm ... no I am not sure .... one option might be putting your entire app in a try..except and then call the method which dumps the standard Free Pascal stack dump ... then write it to the log. It might be a little tricky, because I think that DumpStacktrace (or something with a similar name) dumps using WriteLn, which might be a big problem ... you can change the Output global variable to something which you control. A bit of work, but the advantage of getting stacktraces is big. ---------------------------------------------------------------------- chronozphere · 2011-11-25 00:06 I have found code to print a stacktrace. It worked the first time I ran it on linux. However, android seems to grab the exception right as it happens and doesn't let me handle it myself, let alone unwind the stack to print my own stacktrace. This is my code: Code: [Select]library exception; uses SysUtils, log, JNI; procedure ErroniousCall(); var J: PInteger; begin J := nil; LOGW('Before the error!'); J^ := 5; end; procedure OneMoreCall(); begin ErroniousCall(); end; procedure NextCall(); begin OneMoreCall(); end; procedure SomeCall(); begin NextCall(); end; function Java_com_example_exception_Exception_stringFromJNI(PEnv: PJNIEnv; this: JObject): JString; begin LOGW('Starting native code now...'); try SomeCall(); Result := (PEnv^).NewStringUTF(PEnv, 'Hello world!'); except on E: SysUtils.Exception do begin LOGW('An exception was caught!!!'); end; end; end; exports Java_com_example_exception_Exception_stringFromJNI; begin end. As you see, there is a single JNI call that is the entry point of this library. I added some dummy methods to fill the stack. Then I generate an accessviolation. logcat gives me the following: Code: [Select]D/dalvikvm(20901): Trying to load lib /data/data/com.example.exception/lib/libexception.so 0x407ebda0 D/dalvikvm(20901): Added shared lib /data/data/com.example.exception/lib/libexception.so 0x407ebda0 D/dalvikvm(20901): No JNI_OnLoad found in /data/data/com.example.exception/lib/libexception.so 0x407ebda0, skipping init F/exception_demo(20901): Starting native code now... F/exception_demo(20901): Before the error! I/DEBUG (12825): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG (12825): Build fingerprint: 'asus/WW_epad/TF101:3.2.1/HTK75/ WW_epad-8.6.5.19-20111107:user/release-keys' I/DEBUG (12825): pid: 20901, tid: 20901 >>> com.example.exception <<< I/DEBUG (12825): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000 I/DEBUG (12825): r0 00000000 r1 00000005 r2 00000003 r3 afc03188 I/DEBUG (12825): r4 aca43085 r5 00000004 r6 be9ea550 r7 56436cb4 I/DEBUG (12825): r8 be9ea488 r9 56436cac 10 56436c94 fp be9ea304 I/DEBUG (12825): ip afc03108 sp be9ea2c8 lr afc011c7 pc 80709ee4 cpsr 20000010 I/DEBUG (12825): d0 0000006442c80000 d1 3ff0000042c80000 I/DEBUG (12825): d2 4e19a0e842becd3c d3 42c8000000670ff0 I/DEBUG (12825): d4 000001fd00625280 d5 3fe999999999999a I/DEBUG (12825): d6 3fe8000000000000 d7 3f8000003f800000 I/DEBUG (12825): d8 0000000000000000 d9 0000000000000000 I/DEBUG (12825): d10 0000000000000000 d11 0000000000000000 I/DEBUG (12825): d12 0000000000000000 d13 0000000000000000 I/DEBUG (12825): d14 0000000000000000 d15 0000000000000000 I/DEBUG (12825): scr 60000012 I/DEBUG (12825): I/DEBUG (12825): #00 pc 00009ee4 /data/data/com.example.exception/lib/libexception.so (P$EXCEPTION_ERRONIOUSCALL$LONGINT) I/DEBUG (12825): #01 pc 000011c4 /system/lib/liblog.so I/DEBUG (12825): I/DEBUG (12825): libc base address: aff00000 I/DEBUG (12825): I/DEBUG (12825): code around pc: I/DEBUG (12825): 80709ec4 e24dd030 e50b002c e3a00000 e50b0030 I/DEBUG (12825): 80709ed4 e59f0010 eb013c42 e51b0030 e3a01005 I/DEBUG (12825): 80709ee4 e5801000 e91ba800 8075f3c8 e1a0c00d I/DEBUG (12825): 80709ef4 e92dd800 e24cb004 e24dd030 e50b002c I/DEBUG (12825): 80709f04 e51b002c e2400001 ebffffe9 e91ba800 I/DEBUG (12825): I/DEBUG (12825): code around lr: I/DEBUG (12825): afc011a4 e92d2803 460d41f0 dd014616 e0102709 I/DEBUG (12825): afc011b4 447b4b09 4020f853 46294620 f7ff4632 I/DEBUG (12825): afc011c4 2800ee72 da044607 ee72f7ff 29046801 I/DEBUG (12825): afc011d4 4638d0f2 81f0e8bd 00001fce b088b570 I/DEBUG (12825): afc011e4 46144605 461e9101 4c26b90a 4926447c I/DEBUG (12825): I/DEBUG (12825): stack: I/DEBUG (12825): be9ea288 00000000 I/DEBUG (12825): be9ea28c 00000000 I/DEBUG (12825): be9ea290 000b82c0 I/DEBUG (12825): be9ea294 be9ea35c I/DEBUG (12825): be9ea298 8075f3c8 /data/data/com.example.exception/lib/libexception.so I/DEBUG (12825): be9ea29c 00000000 I/DEBUG (12825): be9ea2a0 be9ea3a4 I/DEBUG (12825): be9ea2a4 000b82b8 I/DEBUG (12825): be9ea2a8 58d9c7f0 I/DEBUG (12825): be9ea2ac 0108046c I/DEBUG (12825): be9ea2b0 00000000 I/DEBUG (12825): be9ea2b4 a8018d79 /system/lib/libutils.so I/DEBUG (12825): be9ea2b8 be9ea304 I/DEBUG (12825): be9ea2bc be9ea2c8 I/DEBUG (12825): be9ea2c0 df002777 I/DEBUG (12825): be9ea2c4 e3a070ad I/DEBUG (12825): #01 be9ea2c8 000b82c0 I/DEBUG (12825): be9ea2cc be9ea314 I/DEBUG (12825): be9ea2d0 407e5018 I/DEBUG (12825): be9ea2d4 00000000 I/DEBUG (12825): be9ea2d8 00000000 I/DEBUG (12825): be9ea2dc 00000001 I/DEBUG (12825): be9ea2e0 407e5018 I/DEBUG (12825): be9ea2e4 00000028 I/DEBUG (12825): be9ea2e8 00012630 I/DEBUG (12825): be9ea2ec 407f12d8 I/DEBUG (12825): be9ea2f0 00000003 I/DEBUG (12825): be9ea2f4 000125f8 I/DEBUG (12825): be9ea2f8 be9ea344 I/DEBUG (12825): be9ea2fc be9ea308 I/DEBUG (12825): be9ea300 80709f10 /data/data/com.example.exception/lib/libexception.so I/DEBUG (12825): be9ea304 80709ec4 /data/data/com.example.exception/lib/libexception.so I/DEBUG (12825): be9ea308 407f12d8 I/DEBUG (12825): be9ea30c 00000000 So, android interferes with my exception handling. Android doesn't seem to support native exceptions very well. If they do, it would be C++ specific. http://groups.google.com/group/android- ndk/browse_thread/thread/89db67ed1fbf6450?pli=1 I have no clue about exceptions apart from how to use them. Can anyone tell me whether pascal code running on android will be capable of handling it's own exceptions? ---------------------------------------------------------------------- felipemdc · 2011-11-25 06:03 If no-one here knows I would recommend asking in Google Groups in the group "android-ndk" and then let us known the result I asked a lot of complex stuff there and Google employees are really helpful. They really answered my complex questions with good answers. ---------------------------------------------------------------------- chronozphere · 2011-11-26 02:16 I just did some more expiriments. This time, I wrote a program that could resolve the stacktrace for me. I'll release that later, if it helps anybody. This is the program I use: Code: [Select]library exception; uses pastrace, SysUtils, log, JNI; procedure ErroniousCall(); var J: PInteger; begin J := nil; J^ := 5; end; procedure OneMoreCall(); begin ErroniousCall(); end; procedure NextCall(); begin OneMoreCall(); end; procedure SomeCall(); begin NextCall(); end; function Java_com_example_exception_Exception_execute(PEnv: PJNIEnv; this: JObject): JString; begin //This will help us generate good stacktraces pastrace_init('exception test'); SomeCall(); Result := (PEnv^).NewStringUTF(PEnv, 'Hello world!'); end; exports Java_com_example_exception_Exception_execute; begin end. [code] However, This is my (homebrewn) stacktrace: [code] Symbol (00061078, _$PASTRACE$_Ld4 in section .rodata) in libexception.so Symbol (000207D0, SYSTEM_NEWANSISTRING$LONGINT$$POINTER + 20 in section .text) in libexception.so Symbol (0002EFE4, SYSTEM_SYSOSFREE$POINTER$LONGWORD + 12 in section .text) in libexception.so Symbol (0002F660, SYSTEM_FREE_OSCHUNK$PFREELISTS$POSCHUNK + 160 in section .text) in libexception.so Symbol (0002F6E4, SYSTEM_APPEND_TO_OSLIST$POSCHUNK + 124 in section .text) in libexception.so Symbol (00030508, SYSTEM_SYSFREEMEM$POINTER$$LONGWORD + 124 in section .text) in libexception.so Symbol (0003048C, SYSTEM_SYSFREEMEM$POINTER$$LONGWORD in section .text) in libexception.so Symbol (0002F200, SYSTEM_FREEMEM$POINTER$$LONGWORD + 20 in section .text) in libexception.so Symbol (000208DC, fpc_ansistr_decr_ref + 96 in section .text) in libexception.so Symbol (00009C94, P$EXCEPTION_ONEMORECALL + 20 in section .text) in libexception.so Symbol (00009C64, P$EXCEPTION_ERRONIOUSCALL + 12 in section .text) in libexception.so the only ones that make sense are EXCEPTION_ONEMORECALL and EXCEPTION_ERRONIOUSCALL. The rest is just... weird. I did resolve every symbol on the stack that was located in my library (had it's path next to it). Just wondering whether this is a real stacktrace, or just a stackdump with it's symbols resolved. ---------------------------------------------------------------------- Laksen · 2011-11-26 02:37 Does pastrace use ansistrings? My guess would be that it does, and that the call from Java_com_example_exception_Exception_execute is from another thread and tries to allocate and free memory on the FPC heap, which is not initialized from this thread If this is the case then it'll most likely screw something up ---------------------------------------------------------------------- chronozphere · 2011-11-26 10:21 This is the source for pastrace. It just spits out some information to the log: Code: [Select]unit pastrace; interface const PASTRACE_TAG = 'PASTRACE'; procedure pastrace_init(appname: String); procedure pastrace_log(msg: String); implementation uses sysutils, dl, log; {$optimization off} //Dummy we use to fetch dl_info structure via dladdr() //This symbol should always be there procedure _pastrace_dummy_(); begin end; {$optimization default} //Call this to initialize pastrace //It sends the base address to the log, so that the pastrace client //can resolve symbol names in case of a crash procedure pastrace_init(appname: String); var info: dl_info; pinfo: Pdl_info; begin pastrace_log('INITIALIZING PASTRACE...'); pinfo := @info; if (dladdr(@_pastrace_dummy_, pinfo) <= 0) then pastrace_log(Format('PASTRACE INITIALIZATION FAILED FOR: %s',[appname])) else begin pastrace_log(Format('PASTRACE INITIALIZED FOR: %s',[appname])); pastrace_log(Format('PASTRACE INFO (%s,%p)',[ExtractFileName(info.dli_fname), info.dli_fbase])); end; end; procedure pastrace_log(msg: String); begin __android_log_write(ANDROID_LOG_INFO,PASTRACE_TAG,pchar(msg)); end; end. So yes, it uses ansistrings. But once we return from this method, it shouldn't leave anything on the stack. So this is probably due to some weird way of JNI/JVM to call our program. ---------------------------------------------------------------------- Laksen · 2011-11-26 13:52 Right, my guess is still that it is because Java_com_example_exception_Exception_execute is called from a different thread in Java. That means that(because you don't use const msg: string or pchar) the program will copy the string. To do that it'll try to allocate memory on the heap, but the heap isn't created for this thread, so it screws a lot of stuff up instead procedure pastrace_log(msg: String); to procedure pastrace_log(msg: pchar); and see if that helps ---------------------------------------------------------------------- chronozphere · 2011-12-02 11:57 I posted this in google groups here: http://groups.google.com/group/android-developers/browse_thread/thread /b64c97626f129f14/86ac31502be3dc06?hl=nl&lnk=gst&q=chronozphere#86ac31 502be3dc06 The reply I got was a kind of discouraging. It makes me fee that I should just learn C++ and use it together with JAVA/C to make my apps/games. I've messed with these stacktraces for over a week and still I'm nowhere. ---------------------------------------------------------------------- felipemdc · 2011-12-02 12:42 Is that an official group from Google or just a place where trolls hang around? Why didn't you post in the android-ndk group like I said? I never got such ridiculous answers in android-ndk not android-sdk and Google employees were always very nice and helpful. Not to mention that the problem with the stacktraces is for all native code, in C++ you get the exact same thing when an exception happens. I don't know why Google didn't use a more normal format. Up to now I haven't needed much to debug in Android itself because in LCL-CustomDrawn-Android you can just switch backend, for example to X11 and then debug the application using the X11 backend. I am using that to implement LCL-CustomDrawn, so that spared me from having to debug directly in Android so far. ---------------------------------------------------------------------- Daniello · 2014-06-01 23:52 Hi guys, this topic is old, but I am interested, there was any progress in this? I would like to trap any exceptions in my Android game and display them in a error screen (or log the exception to a file), instead of just letting the app silently shut down ---------------------------------------------------------------------- CaptBill · 2014-06-02 02:53 There seems to be an ARM/Android port of gdbserver. Should be able to interface over USB/wifi to serial/tty. I plan to try gdbserver hosted on OpenWRT router software (embedded Linux) this week. It seems the Android only needs a gdb client configured. http://www.kandroid.org/online-pdk/guide/debugging_gdb.html http://www.kandroid.org/online-pdk/guide/debugging_gdb.html ---------------------------------------------------------------------- Daniello · 2014-06-09 23:05 CaptBill that seems promising to debug in Android yes, but what about exceptions support? It seems they are broken in FPC for Android, or has it been fixed? ---------------------------------------------------------------------- CaptBill · 2014-06-09 23:54 Good questions. I am waiting on my new 'hot rod' mini-router pre- flashed with OpenWrt and hope to give gdbserver a go. It is available in the 'OpenWrt repository'. Not sure of the state of the gdb support from the fpc side. ARM/Android gdb support seems to be getting better, it appears. I plan to turn the router into a type of 'universal IDE hub' to serve as my 'main server'. I still don't grasp the benefits/possibilities of gdbserver running in this context. Upsides? Downsides? Any thoughts, ideas to try? Also note, this router has a serial port also. How best to utilize all this? Should see mine in @ a week yet: http://www.ebay.com/itm/181078954797?ssPageName=STRK:MEWNX:IT&_trksid= p3984.m1439.l2649