Often I see ARM stack traces (read: Android NDK stack traces) that terminate with an lr pointer, like so:
#00 pc 001c6c20 /data/data/com.audia.dev.qt/lib/libQtGui.so
#01 lr 80a356cc /data/data/com.audia.dev.rta/lib/librta.so
I know that lr stands for link register on ARM and other architectures, and that it’s a quick way to store a return address, but I don’t understand why it always seems to store a useless address. In this example, 80a356cc cannot be mapped to any code using addr2line or gdb.
Is there any way to get more information? Why must the trace stop at the lr address anyway?
Stumbled on the answer finally. I just had to be more observant. Look at the following short stack trace and the information that comes after it:
Now the
lraddress is still a80xxxxxxaddress that isn’t useful to us.The address it prints from the
pcis000099d6, but look at the next section,code around pc. The first column is a list of addresses (you can tell from the fact that it increments by 16 each time.) None of those addresses looks like thepcaddress, unless you chop off the first 16 bits. Then you’ll notice that thea9d899d4must correspond to000099d4, and the code where the program stopped is two bytes in from that.Android’s stack trace seems to have “chopped off” the first 2 bytes of the
pcaddress for me, but for whatever reason it does not do it for addresses in the leaf register. Which brings us to the solution:In short, I was able to chop off the first 16 bits from the
80b6c17caddress to make it0000c17c, and so far that has given me a valid code address every time that I can look up withgdboraddr2line. (edit: I’ve found it’s actually usually the first 12 bits or first 3 hexadecimal digits. You can decide this for yourself by looking at the stack trace output like I described above.) I can confirm that it is the right code address as well. This has definitely made debugging a great bit easier!