Обратная трассировка ARM64 из регистра ссылок

#arm #sp #backtrace #lr

#arm #sp #обратная трассировка #lr

Вопрос:

В настоящее время я пытаюсь получить обратную трассировку на основе указателя стека и регистра ссылок на устройстве 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)amp;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 amp; 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

 

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

1. Я не понимаю вашего вопроса. Вы уже знаете об lr этом, так чего же вам не хватает?

2. Я обновил вопрос. Допустим, мой lr равен 23f9ec, и сохраните его в списке трассировки как последнюю процедуру, теперь из приведенного выше ассемблерного кода, как вычислить, чтобы получить предыдущую процедуру с помощью lr is 23fe14, используя язык C.

Ответ №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, перейдя вперед от предыдущей инструкции или явно перейдятам откуда-то еще.

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

1. Как насчет того, чтобы в случае, если доступен 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]

2.@NgocHoangNguyen Если вы посмотрите bar@@Base , то увидите, что при сохранении fp он не создает новый fp . Так fp что, если он не используется в качестве указателя кадра. Ничего нет.