суббота, 15 июня 2024 г.

stack frames size in DWARF

As you might suspect, the stack size in the kernel is quite meager so it's very important to know how much of stack occupy your driver. So I conducted inhumane experiments on my own driver lkcd to check if stack frame size can be extracted from DWARF debug info. Biggest function in my driver is lkcd_ioctl so lets explore it

mips

Prolog of lkcd_ioctl looks like:
addiu   sp,sp,-688
 
Lets try to find this number in output of objdump -g
<1><3ca44>: Abbrev Number: 258 (DW_TAG_subprogram)
    <3ca46>   DW_AT_name        : (indirect string, offset: 0x1356f): lkcd_ioctl
    <3ca4a>   DW_AT_decl_file   : 1
    <3ca4b>   DW_AT_decl_line   : 1654
    <3ca4d>   DW_AT_decl_column : 13
    <3ca4e>   DW_AT_prototyped  : 1
    <3ca4e>   DW_AT_type        : <0x1ef>
    <3ca52>   DW_AT_low_pc      : 0x1cdc
    <3ca56>   DW_AT_high_pc     : 0xc8e4
    <3ca5a>   DW_AT_frame_base  : 1 byte block: 9c      (DW_OP_call_frame_cfa)
    <3ca5c>   DW_AT_GNU_all_tail_call_sites: 1
    <3ca5c>   DW_AT_sibling     : <0x5405d>
 
Whut? Just DW_OP_call_frame_cfa? Next check section .debug_frame with pc=1cdc:
00000450 00000038 00000000 FDE cie=00000000 pc=00001cdc..0000e5c0
  DW_CFA_advance_loc: 4 to 00001ce0
  DW_CFA_def_cfa_offset: 688
  ...

Ok, for mips it was easy


aarch64

Prolog:
paciasp
sub     sp, sp, #0x350 ; 848

output of objdump -g
<1><66a8>: Abbrev Number: 63 (DW_TAG_subprogram)
    <66a9>   DW_AT_name        : (indirect string, offset: 0x4056): lkcd_ioctl
    <66ad>   DW_AT_decl_file   : 1
    <66ae>   DW_AT_decl_line   : 1654
    <66b0>   DW_AT_decl_column : 13
    <66b1>   DW_AT_prototyped  : 1
    <66b1>   DW_AT_type        : <0x124>
    <66b5>   DW_AT_low_pc      : 0x1d7c
    <66bd>   DW_AT_high_pc     : 0xa8e0
    <66c5>   DW_AT_frame_base  : 1 byte block: 9c       (DW_OP_call_frame_cfa)
    <66c7>   DW_AT_GNU_all_tail_call_sites: 1
    <66c7>   DW_AT_sibling     : <0x19b6a> 

Again check section .debug_frame:

000007f0 00000000000009dc 00000000 FDE cie=00000000 pc=0000000000001d7c..000000000000c65c
  DW_CFA_advance_loc: 4 to 0000000000001d80
  DW_CFA_GNU_window_save
  DW_CFA_advance_loc: 4 to 0000000000001d84
  DW_CFA_def_cfa_offset: 848

It may seem that we have found a universal reliable solution, right?

 

x86_64

Prolog (I prefer use option -M intel for Intel syntax):
17b0:       e8 00 00 00 00          call   17b5 <lkcd_ioctl+0x5>
17b5:       55                      push   rbp
17b6:       48 89 e5                mov    rbp,rsp
17b9:       41 57                   push   r15
17bb:       41 56                   push   r14
17bd:       41 55                   push   r13
17bf:       41 54                   push   r12
17c1:       49 89 d4                mov    r12,rdx
17c4:       53                      push   rbx
17c5:       48 81 ec d8 02 00 00    sub    rsp,0x2d8

output of objdump -g

<1><37b4c>: Abbrev Number: 254 (DW_TAG_subprogram)
    <37b4e>   DW_AT_name        : (indirect string, offset: 0x11d24): lkcd_ioctl
    <37b52>   DW_AT_decl_file   : 1
    <37b53>   DW_AT_decl_line   : 1654
    <37b55>   DW_AT_decl_column : 13
    <37b56>   DW_AT_prototyped  : 1
    <37b56>   DW_AT_type        : <0x1dc>
    <37b5a>   DW_AT_ranges      : 0x553
    <37b5e>   DW_AT_frame_base  : 1 byte block: 9c      (DW_OP_call_frame_cfa)
    <37b60>   DW_AT_call_all_tail_calls: 1
    <37b60>   DW_AT_sibling     : <0x4e456>
 
Wait, where is address of function? Well, everyone loves DWARF for its simplicity, consistency & unambiguity, he-he. Lets try to search in section .debug_rnglists with value from DW_AT_ranges:

    00000553 00000000000017b0 000000000000e14d
    0000055f 00000000000002fd 00000000000004d6

I see familiar numbers! It's unclear why there are two addresses range. Check again section .debug_frame for both:

000008c0 000000000000003c 00000000 FDE cie=00000000 pc=00000000000017b0..000000000000e14d
  DW_CFA_advance_loc: 6 to 00000000000017b6
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 00000000000017b9
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 8 to 00000000000017c1
  DW_CFA_offset: r15 (r15) at cfa-24
  DW_CFA_offset: r14 (r14) at cfa-32
  DW_CFA_offset: r13 (r13) at cfa-40
  DW_CFA_offset: r12 (r12) at cfa-48
  DW_CFA_advance_loc: 11 to 00000000000017cc
  DW_CFA_offset: r3 (rbx) at cfa-56
  DW_CFA_advance_loc2: 3124 to 0000000000002400
  DW_CFA_remember_state
  DW_CFA_restore: r3 (rbx)
  DW_CFA_advance_loc: 2 to 0000000000002402
  DW_CFA_restore: r12 (r12)
  DW_CFA_advance_loc: 2 to 0000000000002404
  DW_CFA_restore: r13 (r13)
  DW_CFA_advance_loc: 2 to 0000000000002406
  DW_CFA_restore: r14 (r14)
  DW_CFA_advance_loc: 2 to 0000000000002408
  DW_CFA_restore: r15 (r15)
  DW_CFA_advance_loc: 1 to 0000000000002409
  DW_CFA_restore: r6 (rbp)
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_advance_loc: 5 to 000000000000240e
  DW_CFA_restore_state

Can you find something similar to 0x2d8/728? I can't - DW_CFA_def_cfa_offset is 16 and obviously this is wrong value. Numbers argument like 17c1 are addresses in code, but for 17c5 there is no records at all! Ok, check address from second range:

00000900 0000000000000014 00000368 FDE cie=00000368 pc=00000000000002fd..00000000000004d6
And this is all - no more strings for this range


 

Комментариев нет:

Отправить комментарий