Cortex M0 HardFault_Handler и получение адреса ошибки

У меня возникает HardFault при выполнении моей программы. Я нашел десятки способов повысить ценность ПК, но я использую Keil uVision 5, и ни один из них не сработал.

Насколько я знаю, я не нахожусь в контексте многозадачности, а PSP содержит 0xFFFFFFFF1, поэтому добавление к нему 24 приведет к переполнению.

Вот что мне удалось заставить работать (например, оно компилируется и выполняется):

enum { r0, r1, r2, r3, r12, lr, pc, psr};

extern "C" void HardFault_Handler()
{
  uint32_t *stack;
  __ASM volatile("MRS stack, MSP");

  stack += 0x20;

  pc = stack[pc];
  psr = stack[psr];
  __ASM volatile("BKPT #01");   
}

Обратите внимание на «+= 0x20», который здесь компенсирует стек функций C.

Всякий раз, когда я читаю значение ПК, оно равно 0. У кого-нибудь есть рабочий код для этого?

В противном случае, вот как я делаю это вручную:

  • Поставьте точку останова на HardFault_Handler (исходный)
  • Когда он сломается, посмотрите, как MSP
  • Добавьте 24 к его значению.
  • Дамп памяти по этому адресу. И вот он, 0x00000000.

Что я делаю не так?


person user1532080    schedule 03.02.2017    source источник


Ответы (1)


Несколько проблем с вашим кодом

uint32_t *stack;
__ASM volatile("MRS stack, MSP");

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

Если вы используете какую-то многозадачную систему, она может использовать PSP вместо MSP. См. связанный код ниже, чтобы узнать, как это можно отличить.

pc = stack[pc];
psr = stack[psr];

Он использует предыдущие значения pc и psr в качестве индекса. Должно быть

pc = stack[6];
psr = stack[7];

Всякий раз, когда я читаю значение ПК, оно равно 0.

Ваша программа могла на самом деле перейти к адресу 0 (например, через нулевой указатель функции), попытаться выполнить найденное там значение, которое, вероятно, было не допустимой инструкцией, а начальным значением SP из таблицы векторов, и ошиблась в этом. Этот код

void (*f)(void) = 0;
f();

делает именно это, я вижу 0x00000000 по смещению 24.

У кого-нибудь есть рабочий код для этого?

У меня это работает. Обратите внимание на код выбор между psp и msp и директива __attribute__((naked)). Вы можете попытаться найти эквивалент для своего компилятора, чтобы компилятор вообще не выделял кадр стека.

person followed Monica to Codidact    schedule 03.02.2017
comment
Спасибо, я добавил некоторую точность и отсутствующий код. Мой компилятор/ассемблер на самом деле не поддерживает MRS R0, MSP, однако результат моего стека MRS, MSP тот же. Это меня сильно ограничивает, похоже, он не понимает ни одного регистра. До сих пор я не нашел эквивалентов __attribute__((naked)), которые бы работали с компилятором, но в любом случае вы подтвердили, что это в целом правильно. И большое спасибо за подсказку о вызове нулевого указателя, не подумал об этом, может быть отсутствующий обратный вызов... - person user1532080; 03.02.2017
comment
Основываясь на вашем ответе, я посмотрел на значение LR, помещенное в стек. Он указывает на действительное местоположение, так что я думаю, что это оно, спасибо! - person user1532080; 03.02.2017