Отладка встроенного ASM с помощью LLDB – рассматривать инструкции как отдельные команды для команды шаг?

Вопрос или проблема

В LLDB команда step выполняет весь блок asm{} как одно “выражение”. Есть ли способ заставить ее обрабатывать каждую инструкцию отдельно, чтобы не приходилось использовать si для пошагового выполнения инструкций и переключаться в режим дизассемблирования, чтобы видеть текущее положение?


В рамках курса, который я посещаю, мы пишем встроенный ассемблер на C. Они используют Visual Studio на Windows для написания и отладки ассемблера MSVS. Я хотел запустить это на своем Macbook M2 (я могу запустить виртуальную машину, но это скучно).

Скомпилировать это было довольно легко. Я использую clang и компилирую так:

clang -fasm-blocks -target x86_64-apple-macos main.c -g -O0

Вот пример кода:

#include <inttypes.h>
#include <stdio.h>

uint8_t count1(uint32_t x) {
    uint8_t out;
    __asm {
        mov edx, x
        mov al, 0
next:   cmp edx, 0
        je done
        mov cl, dl
        and cl, 1
        add al, cl
        shr edx, 1
        jmp next
done:
        mov out, al
    }
    return out;
}

int main() {
    uint32_t x = 0x5789ABCD;
    uint8_t cnt = count1(x);
    printf("Количество единиц в 0x%X: %hhu\n", x, cnt);
}

Единственное, что мне нужно делать по-другому, это значение возвращаемого результата. Мне нужно вручную перенести его в переменную C и вернуть. Если вы знаете, как сделать это неявно, было бы здорово, но для меня это не так важно.

Проблема возникла с отладкой. Я использую neovim и имею хороший опыт отладки с nvim-dap и codelldb. Однако когда я пошагово выполняю код выше, блок asm выполняется за один шаг.
Я пробовал отладку с помощью сырого lldb в командной строке, и это делает то же самое. Я могу пошагово выполнять asm с помощью si и di -F intel, но это немного громоздко.

Я предполагаю, что мне просто не хватает флага на этапе компиляции для генерации отладочных символов для блока asm. Кто-нибудь знает, как пошагово выполнять блок __asm в LLDB, а следовательно и в neovim? Мое понимание проблемы верно?

Ответ или решение

Отладка встроенного ASM с использованием LLDB: Обработка инструкций как отдельных операторов

Отладка встроенного ассемблера в C с использованием LLDB может быть сложной задачей, особенно если вас не устраивает поведение команды step, которая обрабатывает блоки ассемблера как единое целое. В этой статье мы рассмотрим, как добиться более детализированного управления процессом отладки встроенного ассемблера.

Зачем это важно?

При работе с низкоуровневым кодом, таким как ассемблер, важно иметь возможность поочередно просматривать все инструкции. Это позволяет более точно отслеживать логику программы и выявлять потенциальные ошибки. Когда LLDB обрабатывает ассемблерные блоки в качестве одного оператора, это может усложнить отладку.

Проблема с step командой в LLDB

Как было указано, команда step в LLDB по умолчанию обрабатывает весь ассемблерный блок как единую инструкцию. Это несколько затрудняет процесс отладки, поскольку для просмотра отдельной инструкции необходимо использовать команду si (step instruction). Например, ваш код, написанный с использованием встроенного ASM, компилируется с помощью следующей команды:

clang -fasm-blocks -target x86_64-apple-macos main.c -g -O0

При этом код может выглядеть следующим образом:

uint8_t count1(uint32_t x) {
    uint8_t out;
    __asm {
        mov edx, x
        ...
        mov out, al
    }
    return out;
}

Возможные решения

1. Используйте si вместо step

Первый и самый простой способ — это продолжать использовать команду si для пошагового выполнения ассемблерных инструкций. Хотя это несколько неудобно, но это единственный способ в текущей реализации LLDB.

2. Измените способ написания ассемблера

К сожалению, встроенный ASM в C (как в вашем примере с __asm) обрабатывается как единый блок. Рассмотрите возможность разделения ваших ассемблерных инструкций на более мелкие структуры. Например, вы можете использовать отдельные функции для каждой логической группы инструкций, а затем просто вызывать эти функции. Это даст вам возможность использовать step, чтобы переходить между вызовами функций.

3. Используйте флаг компилятора для детальной отладки

Хотя ваши настройки с флагами компиляции выглядят нормально, возможно, флаг -g недостаточен для полной отладочной информации. Попробуйте добавить -gline-tables-only или другие флаги, такие как -ggdb. Например:

clang -fasm-blocks -target x86_64-apple-macos main.c -g -O0 -ggdb
4. Рассмотрите использование других отладчиков

Если LLDB не удовлетворяет ваши потребности в отладке, вы можете рассмотреть альтернативные инструменты. Например, такие отладчики, как GDB, могут предложить различный опыт работы, хотя они могут не поддерживать некоторые особенности, которые есть у LLDB.

Заключение

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

Мы надеемся, что этот обзор поможет вам лучше понять, как работать с отладкой ASM в среде LLDB на вашем Mac. Удачи в написании и отладке вашего кода!

Оцените материал
Добавить комментарий

Капча загружается...