Как переключить разборку iOS в Xcode 4.2 с Thumb на ARM?

#ios #xcode #debugging #gdb #assembly

#iOS #xcode #отладка #gdb #сборка

Вопрос:

Мое приложение для iOS построено с использованием компилятора Apple LLVM 3.0 в режиме Thumb. Для armv7 я почти уверен, что на самом деле это Thumb-2.

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

Разборка GDB верна для кода Thumb, но когда я нахожусь в режиме ARM, он разбирает инструкции ARM, как если бы каждая из них была парой совершенно бессмысленных инструкций Thumb. Есть ли какой-нибудь способ, которым я могу сказать GDB переключиться на разборку ARM, а затем, вернувшись к Thumb code, использовать Thumb disassembler?

Google не помогает. По-видимому, есть другие форки GDB, которые могут это сделать, но я не нашел способа сделать это с помощью GDB.

LLDB, по-видимому, поддерживает отладку ARM, но она еще не работает на устройствах iOS в Xcode 4.2. Когда я выбираю отладчик LLDB в Product -> Edit Scheme, затем устанавливаю точку останова в своем коде, мое приложение зависает, не достигнув точки останова.

Прошло много времени с тех пор, как я делал какую-либо сборку любого рода, поэтому я обновляю соглашения о вызовах ARM, реализуя функции, которые принимают различные параметры и возвращают различные типы результатов как в C, так и в ARM-сборке. Функции lower_case — это C, а функции camelCase — это сборка. Я вызываю abiTest самым первым из main () и использую assert (), чтобы убедиться, что он возвращает YES

 BOOL abiTest( void )
{
    void_no_args();
    VoidNoArgs();

    if ( 42 != int_no_args() )
        return NO;

    if ( 42 != IntNoArgs() )
        return NO;

    return YES;
}
  

Вот исходный код для IntNoArgs. .thumb_func — это директива для компоновщика. Мои исследования, похоже, указывают на то, что это нужно даже для функций ARM, если смешивать два типа кода

 .globl _IntNoArgs
.align 1
.code 16
.thumb_func _IntNoArgs

_IntNoArgs:
    @ int IntNoArgs( void );
    .loc 1 __LINE__ 0

    adr r0, Larm1     @ Larm1 is a PC-relative address.  r0's low bit will be cleared
    bx r0                   @ Switch to ARM mode then branch to Larm1.  That's the next instruction

    .align 2
    .code 32
Larm1:
    stmfd sp!, { r7, lr }

    mov r0, #42

    ldmfd sp!, { r7, lr }
    bx lr
  

Вот как GDB разбирает _IntNoArgs. Первые две строки верны, остальные полностью неверны

 0x000172c8  < 0000>  add    r0, pc, #0  (adr r0, 0x172cc <VoidNoArgs 4>)
0x000172ca  < 0002>  bx r0
0x000172cc  < 0004>  lsls   r0, r0
0x000172ce  < 0006>  stmdb  sp!, {r1, r3, r5}
0x000172d2  < 0010>  b.n    0x17a16
0x000172d4  < 0012>  lsls   r0, r0
0x000172d6  < 0014>  ldmia.w    sp!, {r1, r2, r3, r4, r8, r9, r10, r11, r12, sp, lr, pc}
  

На этом разборка останавливается, потому что инструкция ldmia.w, похоже, вводит новое значение в программный счетчик после извлечения его из стека, тем самым возвращаясь из подпрограммы. После того, как я перейду к этой инструкции с помощью «si», откроется панель разборки:

 0x000172d8  < 0016>  vrhadd.u16 d14, d14, d31
  

Инструкция si всегда выполняет правильные действия, продвигая только одну инструкцию, независимо от того, находимся ли мы в режиме Thumb или ARM. Итак, GDB должен знать текущую архитектуру набора команд, просто дизассемблер не получает эту информацию.

В одном из регистров ARM есть бит, который указывает текущий режим. Некоторые форки GDB имеют возможность использовать значение этого бита при определении того, какой ISA дизассемблировать, но, по-видимому, это не относится к GDB в Xcode 4.2.

В GDB Xcode есть команда «set arm disassembler» и соответствующая ей «show arm disassembler», которая выглядит так, как будто это помогло бы, но это не так. Это, по-видимому, предназначено для поддержки других вариантов ARM, отличных от того, что используют устройства iOS.

«установить резервный режим» может быть установлен на arm, thumb или auto в других форках GDB, но не в Xcodes. То же самое для «установить дизассемблер-вкус».

Чего бы мне ДЕЙСТВИТЕЛЬНО ОЧЕНЬ хотелось, так это машинного отладчика, который работал бы точно так же, как MacsBug в классической Mac OS. Хотя GDB обычно способна выполнять отладку на ассемблере, она совершенно не подходит для этой цели. На самом деле это не чья-то вина, потому что он предназначен для отладки исходного кода. Хороший отладчик сборки предназначен для того, чтобы делать это таким образом с нуля.

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

1. Почему это было перенесено сюда из programmers.stackexchange.com ? Я не жалуюсь, но мне кажется, что плата программиста была более подходящей для этого вопроса.

2. Похоже, что это ошибка в отладчике, и вы должны сообщить об этом Apple по bugreport.apple.com .

3. Грэм, хорошая идея, вроде. Я только что попытался, но не смог исправить ошибку # 10420051. К сожалению, не удалось отправить мою форму. Хотя Radar выдал мне номер ошибки, ошибка на самом деле не была введена, насколько я могу судить. Мне посоветовали сообщить о проблеме с радаром в devbugs@apple.com, что я только что сделал. Я подожду, получу ли я какой-либо ответ, а также дам системным администраторам Apple шанс исправить все, что не так, а затем повторно отправить ошибку.

Ответ №1:

В руководстве по вызову функций ABI указано, что переключение между режимом ARM и Thumb может быть выполнено только на границах функций в iOS. Убедитесь, что ваши функции доступны только для ARM или Thumb, и отладчик будет работать нормально.