ARM64 Backtrace из реестра ссылок

В настоящее время я пытаюсь получить обратную трассировку на основе указателя стека и регистра ссылок на устройстве ARM64 с помощью программы C.

Ниже приведен пример вызова objdump bar() foo() с 240444: ebfffd68 bl 23f9ec ‹foo@@Base›

Я могу получить регистр ссылок (lr) и, получив 23f9ec, сохранить его в списке обратной трассировки как последнюю процедуру.

Мой вопрос: Из приведенного ниже ассемблерного кода с текущим lr 0023f9ec ‹foo@@Base›: как рассчитать, чтобы получить предыдущую процедуру с lr 0023fe14 ‹bar@ @Base› с использованием языка C?

вот моя реализация, но я ошибаюсь в предыдущем LR

int bt(void** backtrace, int max_size) {
    unsigned long* sp = __get_SP();
    unsigned long* ra = __get_LR();
    int* funcbase = (int*)(int)&bt;
    int spofft = (short)((*funcbase));
    sp = (char*)sp-spofft;
    unsigned long* wra = (unsigned long*)ra;
    int spofft; 
    int depth = 0;
    while(ra) {
        wra = ra;
        while((*wra >> 16) != 0xe92d) {
            wra--;
        }
        if(wra == 0)
            return 0;
        
            spofft = (short)(*wra & 0xffff);
        
        if(depth < max_size)
            backtrace[depth] = ra;
        else 
            break;
     
        ra =(unsigned long *)((unsigned long)ra + spofft);
        sp =(unsigned long *)((unsigned long)sp + spofft);

        
        depth++;
    }
    return 1;
}
0023f9ec <foo@@Base>:
  23f9ec:   e92d42f3    push    {r0, r1, r4, r5, r6, r7, r9, lr}
  23f9f0:   e1a09001    mov r9, r1
  23f9f4:   e1a07000    mov r7, r0
  23f9f8:   ebfffff9    bl  23f9e4 <__get_SP@@Base>
  23f9fc:   e59f4060    ldr r4, [pc, #96]   ; 23fa64 <foo@@Base+0x78>
  23fa00:   e08f4004    add r4, pc, r4
  23fa04:   e1a05000    mov r5, r0
  23fa08:   ebfffff3    bl  23f9dc <__get_LR@@Base>
  23fa0c:   e59f3054    ldr r3, [pc, #84]   ; 23fa68 <foo@@Base+0x7c>
  23fa10:   e3002256    movw    r2, #598    ; 0x256
  23fa14:   e59f1050    ldr r1, [pc, #80]   ; 23fa6c <foo@@Base+0x80>
  23fa18:   e7943003    ldr r3, [r4, r3]
  23fa1c:   e08f1001    add r1, pc, r1
  23fa20:   e5934000    ldr r4, [r3]
  23fa24:   e1a03005    mov r3, r5
  23fa28:   e6bf4074    sxth    r4, r4
  23fa2c:   e58d4004    str r4, [sp, #4]
  23fa30:   e1a06000    mov r6, r0
  23fa34:   e58d0000    str r0, [sp]
  23fa38:   e59f0030    ldr r0, [pc, #48]   ; 23fa70 <foo@@Base+0x84>
  23fa3c:   e08f0000    add r0, pc, r0
  23fa40:   ebfd456d    bl  190ffc <printf@plt>
  23fa44:   e1a03009    mov r3, r9
  23fa48:   e1a02007    mov r2, r7
  23fa4c:   e1a01006    mov r1, r6
  23fa50:   e0640005    rsb r0, r4, r5
  23fa54:   ebffff70    bl  23f81c <get_prev_sp_ra2@@Base>
  23fa58:   e3a00000    mov r0, #0
  23fa5c:   e28dd008    add sp, sp, #8
  23fa60:   e8bd82f0    pop {r4, r5, r6, r7, r9, pc}
  23fa64:   003d5be0    eorseq  r5, sp, r0, ror #23
  23fa68:   000026c8    andeq   r2, r0, r8, asr #13
  23fa6c:   002b7ba6    eoreq   r7, fp, r6, lsr #23
  23fa70:   002b73e5    eoreq   r7, fp, r5, ror #7

0023fe14 <bar@@Base>:
  23fe14:   e92d4ef0    push    {r4, r5, r6, r7, r9, sl, fp, lr}
  23fe18:   e24dde16    sub sp, sp, #352    ; 0x160
  23fe1c:   e59f76a8    ldr r7, [pc, #1704] ; 2404cc <bar@@Base+0x6b8>
  23fe20:   e1a04000    mov r4, r0
  23fe24:   e59f66a4    ldr r6, [pc, #1700] ; 2404d0 <bar@@Base+0x6bc>
  23fe28:   e1a03000    mov r3, r0
  23fe2c:   e59f26a0    ldr r2, [pc, #1696] ; 2404d4 <bar@@Base+0x6c0>
  23fe30:   e08f7007    add r7, pc, r7
  23fe34:   e08f6006    add r6, pc, r6
  23fe38:   e3a00000    mov r0, #0
  23fe3c:   e08f2002    add r2, pc, r2
  23fe40:   e1a05001    mov r5, r1
  23fe44:   e3a01003    mov r1, #3
  23fe48:   e59f9688    ldr r9, [pc, #1672] ; 2404d8 <bar@@Base+0x6c4>
.....................................................................
  24043c:   e3a0100f    mov r1, #15
  240440:   e1a0000a    mov r0, sl
  240444:   ebfffd68    bl  23f9ec <foo@@Base>
  240448:   e59f2108    ldr r2, [pc, #264]  ; 240558 <bar@@Base+0x744>
  24044c:   e3a01003    mov r1, #3
  240450:   e08f2002    add r2, pc, r2
  240454:   e1a05000    mov r5, r0
  240458:   e1a03000    mov r3, r0
  24045c:   e3a00000    mov r0, #0


person Ngoc Hoang Nguyen    schedule 23.02.2021    source источник
comment
Я не понимаю вашего вопроса. Вы уже знаете о lr, так чего же вам не хватает?   -  person Siguza    schedule 23.02.2021
comment
Я обновил вопрос. Предположим, что мой lr — 23f9ec, и сохраните его в списке обратной трассировки как последнюю процедуру, теперь из приведенного выше ассемблерного кода, как вычислить, чтобы получить предыдущую процедуру с lr — 23fe14, используя язык C.   -  person Ngoc Hoang Nguyen    schedule 23.02.2021


Ответы (1)


Я не думаю, что есть простой способ сделать это.

Обычно регистр ABI любой операционной системы содержит регистр указателя кадра. Например, в Apple armv7 ABI это r7:

0x10006fc0      b0b5           push {r4, r5, r7, lr}
0x10006fc2      02af           add r7, sp, 8
0x10006fc4      0448           ldr r0, [0x10006fd8]
0x10006fc6      d0e90c45       ldrd r4, r5, [r0, 0x30]
0x10006fca      0020           movs r0, 0
0x10006fcc      fff7a6ff       bl 0x10006f1c
0x10006fd0      0019           adds r0, r0, r4
0x10006fd2      6941           adcs r1, r5
0x10006fd4      b0bd           pop {r4, r5, r7, pc}

Если вы разыменуете там r7, вы получите пару указателей, второй из которых — lr, а первый — r7 вызывающей функции, что позволит вам повторять этот процесс до тех пор, пока вы не достигнете нижней части стека.

Судя по опубликованной вами сборке, кодовая база, на которую вы смотрите, этого не имеет. Это означает, что единственный способ получить адрес возврата — тот же, что и сам код: пройти вперед по каждой инструкции и анализировать/интерпретировать их, пока не дойдете до того, что загружается в pc. Это, конечно, несовершенно, поскольку в вашем стеке вызовов могут быть функции, которые никогда не возвращаются, но вы мало что можете с этим поделать.

Вместо этого может возникнуть соблазн поискать в обратном направлении, и хотя вы можете использовать эвристический подход и, возможно, получить с его помощью вполне приемлемые результаты, это еще менее надежно, чем поиск вперед, поскольку у вас нет абсолютно никакого способа определить, достигли ли вы адреса X путем шаг вперед от предыдущей инструкции или явный переход туда из другого места.

person Siguza    schedule 23.02.2021
comment
Как насчет того, если fp доступен, получить из него lr и предыдущий fp, как показано ниже: cl.cam.ac.uk/~fms27/teaching/2001-02/arm-project/02-sort/ Данные трассировки стека структура имеет формат, показанный ниже: сохранить указатель кода [fp] ‹-fp указывает сюда вернуть значение ссылки [fp, #-4] вернуть значение sp [fp, #-8] вернуть значение fp [fp, #-12] - person Ngoc Hoang Nguyen; 25.02.2021
comment
@NgocHoangNguyen Если вы посмотрите на bar@@Base, то увидите, что пока он сохраняет fp, он не устанавливает новый fp. Итак, fp, если он не используется в качестве указателя кадра. Ничего. - person Siguza; 25.02.2021