Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ARM Assembly backtrace PC offset

The ARM manual mentions that:

During execution, PC does not contain the address of the currently executing instruction. The address of the currently executing instruction is typically PC-8 for ARM, or PC-4 for Thumb.

Does this apply for PC values in crash backtraces as well?

For example, if I have the following backtrace (from Android armv7 device using ARM instructions):

libSomeLib.so!SomeClass::someMethod [someFile.cpp : 638 + 0x4]
    r0 = 0x00000001    r1 = 0xffffffff    r2 = 0x00000000    r3 = 0xd4fcd71c
    r4 = 0xd39b9284    r5 = 0xd39b927c    r6 = 0xd39b9278    r7 = 0xc7025520
    r8 = 0xc5e1d7b0    r9 = 0xe01136a8   r10 = 0x00000012   r12 = 0xd39b9268
    fp = 0xd39b92d4    sp = 0xd39b9268    lr = 0xd4ea1f24    pc = 0xd4ea1f24
...
0xd47cb000 - 0xd5079fff  libSomeLib.so  ???

Should I look for the crashing instruction inside libSomeLib.so at 0xd4ea1f24-0xd47cb000=0x006D6F24 or 0xd4ea1f24-0xd47cb000-8=0x006D6F1C?

like image 246
gq3 Avatar asked Jul 06 '17 10:07

gq3


People also ask

What is offset in ARM assembly?

The ARM instruction set architecture has three addressing modes: Immediate. The offset is an unsigned integer that is stored as part of the instruction. It can be added to or subtracted from the value in the base register.

Which arm register is used to store the value of computer?

According to the ARM IC. In ARM state, the value of the PC is the address of the current instruction plus 8 bytes. In Thumb state: For B, BL, CBNZ, and CBZ instructions, the value of the PC is the address of the current instruction plus 4 bytes.


1 Answers

I made an intentional crash to investigate. Source code:

int* crashPointer = nullptr;
*crashPointer = 7;

Generated assembly:

11feb8: e3005007    movw    r5, #7
11febc: e3006000    movw    r6, #0 <--- r6 is #0
11fec0: e50b0014    str r0, [fp, #-20]  ; 0xffffffec
11fec4: e50b1018    str r1, [fp, #-24]  ; 0xffffffe8
11fec8: e51b0014    ldr r0, [fp, #-20]  ; 0xffffffec
    int* crashPointer = nullptr;
11fecc: e50b601c    str r6, [fp, #-28]  ; 0xffffffe4 <--- Stores #0 to [fp, #-28] from r6
    *crashPointer = 7;
11fed0: e51b101c    ldr r1, [fp, #-28]  ; 0xffffffe4 <--- Loads #0 from [fp, #-28] to r1
11fed4: e5815000    str r5, [r1] <--- This should crash since it's trying to dereference r1 which is #0

Predicted crash address is 11fed4

Actual crash dump:

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    r0 ea408800  r1 00000000  r2 00000006  r3 ea6ccfa0
    r4 ea6d1b2a  r5 00000007  r6 00000000  r7 ea3ff904
    r8 00000001  r9 e8b22ec0  sl ea6b5be9  fp ea3ff5c0
    ip ea6d1af8  sp ea3ff550  lr ea6d09aa  pc ea696ed4  cpsr 600f0010
...
ea577000-ea6d7000 r-xp 00000000 fe:01 1556782   libSomeLib.so

Conclusion: ea696ed4-ea577000=11fed4, which is equal to the predicted address.

To summarize: there's no need to add an offset to the PC value in the crash dump (for Android armv7 at least).

like image 88
gq3 Avatar answered Oct 20 '22 09:10

gq3