Инструменты отладки нужны каждому разработчику. Однако, не существует универсальных решений, подходящих и тем, кто создаёт приложения пользовательского уровня, и тем, кто пишет низкоуровневые программы, вроде драйверов оборудования. Чем ближе к «железу» — тем больше хардкора в отладке и тестировании.

Из этого материала вы узнаете о том, как отлаживать код и анализировать исключения на уровне ядра Linux ОС Android в системах, основанных на архитектуре Intel. А именно, мы рассмотрим отладочный инструмент JTAG Debugger, который является частью пакета Intel System Studio Ultimate Edition. Мы расскажем о стандарте JTAG, о вышеупомянутом JTAG-отладчике Intel, об обработке исключений. В качестве примера мы будем использовать мини-компьютер MinnowBoard MAX с Intel Atom на борту.

Обзор JTAG


JTAG (произносится как «джей-таг», «jay-tag») – это сокращение от Joint Test Action Group. Обычно, когда говорят «JTAG», подразумевают стандарт IEEE 1149.1-1990 (IEEE Standard Test Access Port and Boundary-Scan Architecture). Этот стандарт устанавливает правила отладки и тестирования однокристальных систем (SoC, System on Chip) и программного обеспечения микропроцессоров (Microprocessor Software).

При JTAG-отладке используется набор инструментов, состоящий из трёх частей: программный JTAG-отладчик, установленный на главном компьютере, аппаратный JTAG-адаптер (датчик) и внутрисхемный отладчик (OCD, On Chip Debug), которым оснащена тестируемая микросхема.

Программный JTAG-отладчик


JTAG-отладчик – это программный инструмент, установленный на главном компьютере. Он получает данные и сведения об адресах от JTAG-адаптера и отображает их в пользовательском интерфейсе. Разработчик, в свою очередь, может отправлять команды JTAG-адаптеру, который подключен к основному компьютеру по USB или с помощью другого интерфейса.

Пользуясь этим инструментом, можно контролировать выполнение программы и отлаживать её на уровне исходного кода. Подобное реализуется благодаря файлам символов, которые соответствуют двоичным образам, загружаемым на целевые системы. Эти средства дают разработчику следующие возможности: запуск (run) и остановка (stop) исполнения кода, выполнение в ходе отладки шага с обходом (step over) и шага с заходом (step into), указание точек останова (breakpoints), доступ к памяти.

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

Intel JTAG Debugger (известный как XDB), входит в состав Intel System Studio Ultimate Edition. XDB – это тот самый программный инструмент JTAG-отладки, который должен быть установлен на главном компьютере.

Аппаратный JTAG-адаптер


JTAG-адаптер – это устройство, которое преобразует JTAG-сигналы в формат, подходящий для передачи компьютеру. Для сопряжения адаптеров и ПК используются такие интерфейсы, как USB, параллельный порт, RS-232, Ethernet. USB – самый популярный среди них. Именно он применяется для связи многих JTAG-адаптеров с компьютерами. Стандартом предусмотрено минимальное число JTAG-контактов для подключения целевых устройств к JTAG-адаптерам, однако, на практике применяются самые разные интерфейсы. Например, это 10- и 20-контактные разъемы для ARM, 14-контактный для ST, 16-контактный для OCDS.

В связке из отладчика Intel JTAG и MinnowBoard MAX, о которой идёт речь в этом материале, используется 60-контактный разъем для подключения целевого устройства. В качестве JTAG-адаптера для MinnowBoard MAX применяется Intel ITP-XDP3. Отладчик Intel JTAG совместим и с JTAG-адаптерами других производителей. Например – с Macraigor Systems usb2Demon и OpenOCD.

Внутрисхемный отладчик (целевой микрочип)


Главные компоненты внутрисхемного отладчика – это TAP (Test Access Point, тестовый порт) и TDI (Test Data In, вход тестовых данных)/TDP (Test Data Out, выход тестовых данных). Используя TAP можно сбрасывать, читать и записывать состояние регистров, пользоваться инструкцией BYPASS. Основная технология, которая применяется в JTAG – это так называемое граничное сканирование (Boundary Scan) с использованием сигнальных линий TDI/TDO.


Конфигурация из JTAG-адаптера и целевой системы. Здесь же показана плата расширения, которая используется для соединения Intel ITP-XDP3 и MinnowBoard MAX

Обзор исключений в архитектуре Intel


Исключение (exception) – это синхронное событие, которое генерируется, когда процессор, при выполнении инструкций, обнаруживает одно или несколько предопределенных условий. Архитектура IA-32 предусматривает три класса исключений: отказ (fault), ловушка (trap) и авария (abort). Обычно при возникновении отказов и ловушек возможно продолжение прерванной работы, в то время как при авариях – нет. Когда возникает исключение, оно обрабатывается так же, как обрабатываются прерывания. Это означает, что после остановки и сохранения текущего процесса, система переключается на обработчик исключения, а после того, как обработчик завершил работу, возвращается к исполняемой ранее задаче.

Исключения и прерывания защищенного режима
Вектор Сокращённое наименование Описание Тип Код ошибки Источник
0
#DE
Ошибка деления
Отказ
Нет
Инструкции DIV и IDIV
1
#DB
Зарезервировано
Отказ / ловушка
Нет
Только для использования Intel
2
Прерывание NMI
Прерывание
Нет
Внешнее немаскируемое прерывание
3
#BP
Точка останова
Ловушка
Нет
Инструкция INT 3
4
#OF
Переполнение
Ловушка
Нет
Инструкция INT0
5
#BR
Выход за границы диапазона
Отказ
Нет
Инструкция BOUND
6
#UD
Неправильный (неопределенный) код операции
Отказ
Нет
Инструкция UD2 или зарезервированный код операции
7
#NM
Устройство недоступно (Нет математического сопроцессора)
Отказ
Нет
Инструкции вычислений с плавающей точкой или инструкции WAIT/FWAIT
8
#DF
Двойной отказ
Авария
Да (ноль)
Любая инструкция, которая может сгенерировать исключение, NMI или INTR
9
Выход за пределы сегмента сопроцессора (зарезервировано)
Отказ
Нет
Инструкция, выполняющая вычисления с плавающей точкой
10
#TS
Неверный TSS
Отказ
Да
Переключение задач или доступ к TSS
11
#NP
Сегмент отсутствует
Отказ
Да
Загрузка сегментных регистров или доступ к системным сегментам
12
#SS
Отказ сегмента стека
Отказ
Да
Операции со стеком и загрузка регистра SS
13
#GP
Общая ошибка защиты
Отказ
Да
Ошибки, связанные с памятью, проверками защиты
14
#PF
Отказ страницы
Отказ
Да
Работа с памятью
15

Зарезервировано Intel, не предназначено для использования
Нет
16
#MF
Ошибка вычислений с плавающей точкой x87 FPU (Ошибка вычислений)
Отказ
Нет
Вычисления с плавающей точкой на x87 FPU или инструкции WAIT/FWAIT
17
#AC
Ошибка проверки выравнивания
Отказ
Да (ноль)
Работа с данными в памяти
18
#MC
Аппаратная ошибка
Авария
Нет
Коды ошибок (если они есть) и их источник зависят от аппаратного обеспечения
19
#XM
Исключения вычислений с плавающей точкой SIMD
Отказ
Нет
Инструкции вычислений с плавающей точкой SSE, SSE2, SSE3
20
#VE
Исключение виртуализации
Отказ
Нет
EPT-нарушения
21 – 31
Зарезервировано Intel, не предназначено для использования
32 – 255
Прерывания, заданные разработчиком (не зарезервированы)
Прерывание
Внешние прерывания или инструкции INT n.

Подготовка MinnowBoard MAX и Intel ITP-XDP3 к подключению к главному компьютеру по USB


Для начала надо установить на MinnowBoard MAX ОС Android. Для того чтобы это сделать, обратитесь к материалу «Статья разработчика Intel System Studio: настройка, сборка и профилировка Linux-ядра Android с помощью VTune». Он содержит инструкцию по сборке, установке и настройке Android на MinnowBoard MAX.

После установки ОС подключим MinnowBoard MAX к JTAG-адаптеру Intel ITP-XDP3 с помощью платы расширения. JTAG-адаптер присоединим к ПК по USB. На главном компьютере должна быть установлена Intel System Studio Ultimate Edition, в состав которой входит USB-драйвер для Intel ITP-XDP3.


MinnowBoard MAX подключён к JTAG-адаптеру Intel ITP-XDP3, который, в свою очередь, подключён к хост-компьютеру с установленным на нём JTAG-отладчиком от Intel (XDB)

Использование JTAG-отладчика Intel (XDB) для отладки ядра Android на MinnowBoard MAX


Рассмотрим пошаговую процедуру использования XDB в деле отладки Linux-ядра ОС Android.

1. Запустим JTAG-отладчик Intel. Для этого нужно перейти в папку, где он установлен, и запустить пакетный файл (например – start_xdb_legacy_products.bat).

2. Подключимся к целевому устройству. Для этого нужно, в интерфейсе JTAG-отладчика, выполнить команду File > Connect и выбрать, во-первых, аппаратный JTAG- адаптер. В нашем случае это Intel ITP-XPD3. Во-вторых – надо указать целевую платформу. Нас интересует Intel Atom Processor E38xx, Z3680, X37xx – 2 cores (ValleyView).


Выбор аппаратного JTAG-адаптера и целевой платформы в XDB

3. Загрузим файлы символов и укажем директорию файлов исходного кода. Для этого нужно выполнить в JTAG-отладчике Intel команду File > Load / Unload Symbol и указать файлы символов. Для файлов исходного кода нужно выполнить команду Options > Source Directories и указать правила сопоставления файлов исходного кода и файлов символов, а так же соответствующие директории. Правила позволяют настроить соответствие путей в файле символов, которые записываются во время компиляции, и текущих мест расположения файлов исходного кода.

4. Найдём entry-файл, в котором имеется обработчик исключений. Воспользуемся командой меню JTAG-отладчика Intel View > Source files и откроем файл entry_64.S.


Поиск файла entry_64.S

5. Установим точку останова на точке входа исключения. Для этого найдём строку ENTRY(error_entry), которая является точкой входа исключения с кодом ошибки в регистре RAX. Каждый обработчик исключения определён как макрос zeroentry или errorentry. Таким образом, можно установить точку останова в error_entry или в каком-то конкретном обработчике. В данном материале мы используем для тестирования «zeroentry invalid_op do_invalid_op».

ENTRY(error_entry)
	XCPT_FRAME
	CFI_ADJUST_CFA_OFFSET 15*8
	/* oldrax contains error code */
	cld
	movq_cfi rdi, RDI+8
	movq_cfi rsi, RSI+8
	movq_cfi rdx, RDX+8
	movq_cfi rcx, RCX+8
	movq_cfi rax, RAX+8
	movq_cfi  r8,  R8+8
	movq_cfi  r9,  R9+8
	movq_cfi r10, R10+8
	movq_cfi r11, R11+8
	movq_cfi rbx, RBX+8
	movq_cfi rbp, RBP+8
	movq_cfi r12, R12+8
	movq_cfi r13, R13+8
	movq_cfi r14, R14+8
	movq_cfi r15, R15+8
	xorl %ebx,%ebx
	testl $3,CS+8(%rsp)
	je error_kernelspace
error_swapgs:
	SWAPGS
error_sti:
	TRACE_IRQS_OFF
	ret
<....>
zeroentry divide_error do_divide_error
zeroentry overflow do_overflow
zeroentry bounds do_bounds
zeroentry invalid_op do_invalid_op
zeroentry device_not_available do_device_not_available
paranoiderrorentry double_fault do_double_fault
zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
errorentry invalid_TSS do_invalid_TSS
errorentry segment_not_present do_segment_not_present
zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
zeroentry coprocessor_error do_coprocessor_error
errorentry alignment_check do_alignment_check
zeroentry simd_coprocessor_error do_simd_coprocessor_error

Теперь, в качестве примера, вызовем исключение, и проверим, сработал ли обработчик, на котором мы установили точку останова. Установим точку останова на «zeroentry invalid_op do_invalid_op» и вызовем блок кода BUG(), который выполняет инструкцию ud2, вызывающую отказ (fault) «Неправильный код операции».

#define BUG()							do {									asm volatile("ud2");						unreachable();						} while (0)

Вызов BUG()


Макрос BUG() надо добавить в собственный тестовый код уровня ядра для того, чтобы было вызвано исключение. В данном примере мы добавили его в keyboard.c для того, чтобы исключение вызывалось при появлении особых последовательностей символов, вводимых с клавиатуры.


Результат вызова макроса BUG()


Результат вызова макроса BUG(), увеличенный фрагмент копии экрана

Остановка на точке останова Invalid_op


Если установить точку останова в обработчике исключения «Неправильный код операции» или на входе в обработчик исключения, можно увидеть сообщение об исключении, и, в ходе отладки, добраться до места возникновения ошибки.


Точка останова в обработчике исключения «Неправильный код операции»


Точка останова в обработчике исключения «Неправильный код операции», увеличенный фрагмент копии экрана

Заключение


Некоторые исключения – это критические ошибки аппаратного и программного обеспечения системы. Поэтому очень важно знать – как, почему и где они происходят. Используя JTAG-отладчик Intel, такие ошибки легко обнаружить и добраться до причины их возникновения. Всё это возможно потому, что данный отладчик предоставляет разработчику мощные возможности. Среди них – лёгкий доступ к скомпилированному и исходному коду, просмотр стека вызовов и регистров.

Полезные ссылки


Intel 64 and IA-32 Architectures Software Developer’s Manual
JTAG Tutorial: IEE 1149.x and Software Debug

Комментарии (13)


  1. grafmishurov
    14.09.2015 20:14

    Все же я за kgdb на рабочей машине, и дебажить на любом таргете ядро с символами. Кстати сам Торвальдс не любит дебаггеры, gdb использует как дизассемблер на стероидах, дескать без них разработчик более детально вникает в суть кода, решая проблему.


    1. antoxar
      16.09.2015 10:34

      Нет универсального софтварного дебаггера. Всегда найдется несколько usecase'ов в которых будешь отлаживать ядро printf'aми или придется пользоватся JTAG.


  1. grafmishurov
    14.09.2015 20:59

    Еще про табличку исключений:
    1 #DB Зарезервировано Только для использования Intel

    По моим данным:
    1- “Debug” (trap or fault)
    Raised when the TF flag of eflags is set (quite useful to implement single-step
    execution of a debugged program) or when the address of an instruction or
    operand falls within the range of an active debug register.

    И в исходниках (ядро 3.18.19) все в том же entry_64.S вот какую строчку нашел:
    idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK


  1. CodeRush
    14.09.2015 21:13
    +1

    Все это здорово, но простому энтузиасту недоступно.
    Стоитмость XDP3 — около 3 тыс. долларов, лицензия на год использования System Studio — еще две, а в результате получаем отладочную платформу, которая не нужна даже при разработке прошивки и bare-metal OS, ибо там хватает Port80h-кодера и одного UART'а.


    1. resetnow
      15.09.2015 10:49

      Может быть, оно с OpenOCD заводится? С поддерживаемым адаптером.


      1. antoxar
        16.09.2015 10:38

        Нет, OpenOCD не поддерживает Atom.


  1. grafmishurov
    14.09.2015 21:23

    И еще про табличку исключений:
    15 Зарезервировано Intel, не предназначено для использования

    Смотрю в исходники, теперь уже в хендлеры исключений (arch / x86 / include / asm / traps.h):
    X86_TRAP_SPURIOUS, /* 15, Spurious Interrupt */

    Интернет отправляет в Вики про The Intel 8259 is a Programmable Interrupt Controller (PIC) designed for the Intel 8085 and Intel 8086 microprocessors.

    Spurious interrupts[edit]
    The 8259 generates spurious interrupts in response to a number of conditions.

    The first is an IRQ line being deasserted before it is acknowledged. This may occur due to noise on the IRQ lines. In edge triggered mode, the noise must maintain the line in the low state for 100 ns. When the noise diminishes, a pull-up resistor returns the IRQ line to high, thus generating a false interrupt. In level triggered mode, the noise may cause a high signal level on the systems INTR line… итд.

    Написано, что не предназначено для использования, но почему тогда хендлер в исходниках ядра есть для этого исключения?


    1. grafmishurov
      14.09.2015 21:28

      Точнее в данном случае уже прерывания.


    1. alecv
      17.09.2015 00:04

      Оно не предназначено для нормального использования, а скорее просто для индикации, что в системе не все нормально.

      Но если честно, это очень старинная вещь, тянется во времен i8259 и ISA шины. Legacy.


      1. grafmishurov
        17.09.2015 01:41

        Про шумы в IRQ и про контроллер понятно, меня удивляет, что официальная таблица скрывает от нас правду. И в коде ядра обработчик этого прерывания все таки есть.

        do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
        {
        	conditional_sti(regs);
        #if 0
        	/* No need to warn about this any longer. */
        	pr_info("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
        #endif
        }
        
        


        1. alecv
          17.09.2015 21:59

          Дак это не заморочка Intel, а проблема ранней архитектуры IBM PC. Для Intel — это совершенно обычное прерывание. Но поскольку для PC потребляется 99.99% чипов x86 Inel, отсюда имеем что имеем. Никто ничего не скрывает.

          Не-PC архитектур на x86 было крайне мало, даже ноуты Apple теперь — обычные писишки, Можно вспомнить например SGI Visual Workstation.


      1. grafmishurov
        17.09.2015 01:51

        Т.е. в коде ядра обрабатываются все 20 векторов + iret на 32-м.


  1. tsafin
    19.09.2015 13:33

    А что произошло со старым добрым ITP отладчиком, который мы применяли Н-лет назад? XDB это реинкарнация на Eclipse старого ITP? Или это совсем другая (не DTS) команда?