2023 08 08 18 10 如何在arm64 gdb中從core dump拿到errno的值

這次研究如何在arm64中用gdb從core dump去找到errno的位置.
目前沒有直接找到的方法,只能間接去推算位址.

(gdb) disassemble __errno_location
Dump of assembler code for function __errno_location:
   0x0000007fb6bef660 <+0>:    adrp    x0, 0x7fb6c04000
   0x0000007fb6bef664 <+4>:    ldr    x0, [x0, #3976]
   0x0000007fb6bef668 <+8>:    mrs    x1, tpidr_el0
   0x0000007fb6bef66c <+12>:    add    x0, x1, x0
   0x0000007fb6bef670 <+16>:    ret
End of assembler dump.
(gdb) p/x *(int *)(0x7fb6c04000+3976)
$2 = 0x20

到這邊我們知道errno是在 $tpidr_el0 + 0x20 的位置.
但是我找不到怎樣拿到 $tpidr_el0 的位址.
不過我有發現一個方法.

(gdb) disassemble pthread_self
Dump of assembler code for function pthread_self:
   0x0000007fb6adafd0 <+0>:    mrs    x0, tpidr_el0
   0x0000007fb6adafd4 <+4>:    sub    x0, x0, #0x700
   0x0000007fb6adafd8 <+8>:    ret

pthread的context是位在 $tpidr_el0 - 0x700的位址上.

(gdb) thread
[Current thread is 1 (Thread 0x7fb6c2c040 (LWP 20610))]

因為我們就可以把 0x7fb6c2c040 + 0x700 + 0x20 = 0x7fb6c2c760 這個位址就是 errno 的位置了.

(gdb) p/x *(int *)0x7fb6c2c760
$4 = 0x2

這就是我們要找的errno的值了.
但是這有個限制,
編譯程式時需要有加上 -lpthread 才有 pthread 的 context 可以使用.

參考程式:
#include <stdint.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char* argv[]) {
  uint64_t tpidr_el0;
  asm volatile("mrs %0, TPIDR_EL0" : "=r"(tpidr_el0));
  printf("$tpidr_el0: %p ",tpidr_el0);
  printf("errno:      %p ",__errno_location());
  return 0;
}