реклама на сайте
подробности

 
 
5 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Hard Fault Exception на кортексе м3, как узнать откуда прилезло
klen
сообщение Feb 4 2010, 10:37
Сообщение #1


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



Здравствуйте.
работает программа на stm32f107 uIP+DHCP+HTTPD+TELNETD.

все просто замечательно работает, но не долго - минуту, через примерно одинаковый интервал времени - systick показывает очень близкие значения, все вываливается в HardFaultException с вероятностью 1. видимо гдето чето кончаетсо, буфер например. пытаюсь понять.

как высчитать в обработчике адрес с которого все это прилитело?

нагугленная конструкция
asm volatile ("MRS R0,PSP") ;
asm volatile ("LDR R1,[R0,#24] \n");
выдает чето мне непонятное.

спасибо.
Go to the top of the page
 
+Quote Post
klen
сообщение Feb 4 2010, 17:12
Сообщение #2


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



проблему я пофиксил - SNTP клиент косячил. все прекрасно заработато.

но вопрос то отался - как в обработчике исключительной ситуации Hard Fault получить адрес инструкции котороая привела к эксепшену? Ну вопрос то наверно простой, гдето ячето неправильно даташит понимаю.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 5 2010, 11:23
Сообщение #3


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Вот так у меня сработало:

Код
void hard_fault_handler(unsigned int * hardfault_args)
{
    rs_puts("\r\nhard_fault_handler!\r\nPC=");
    rs_put_hex(hardfault_args[6]);
    for(;;);
}

void HardFault_Handler(void) __attribute__ (( naked ));

// собственно обработчик
void HardFault_Handler(void)
{
    asm volatile (
        "TST LR, #4              \n"
        "ITE EQ                    \n"
        "MRSEQ R0, MSP        \n"
        "MRSNE R0, PSP         \n"
        "B hard_fault_handler    "
    );
}

//Проверка:
void test1()
{
    __asm volatile
    (
        "MOVS r0, #1         \n"
        "LDM r0,{r1-r2}        \n"
        "BX LR                \n"
    );
}


Вывод в UART почему-то не сработал, но в отладчике видно, что в hardfault_args[6] - адрес строчки ldmia.w r0, {r1, r2}.

Взято отсюда.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
klen
сообщение Feb 5 2010, 14:45
Сообщение #4


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



очень хорошо будем смотреть в "бубен около костра"

только с ходу вроде бы то что я вставлял
asm volatile ("MRS R0,PSP") ;
asm volatile ("LDR R1,[R0,#24]");
почти тоже самое? что Вы привели, - выдавало в r1 бред.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 5 2010, 14:58
Сообщение #5


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(klen @ Feb 5 2010, 19:45) *
только с ходу вроде бы то что я вставлял
asm volatile ("MRS R0,PSP") ;
asm volatile ("LDR R1,[R0,#24]");
почти тоже самое? что Вы привели, - выдавало в r1 бред.


Почтиsmile.gif Во-первых, там идёт выбор между PSP и MSP. Может не угадали. И, во-вторых (я забыл это указать), используется naked HardFault_Handler - чтоб не портить указатель стека.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
klen
сообщение Feb 5 2010, 15:23
Сообщение #6


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912



yeah.gif
уря уря уря!!!
naked действительно во вторых!! потому что во первых я тупой - не обратилвнимание на то что стек пересчитывается......
все остально включая асм - ничего ценного, к вопросу топика ценны тока "во первых" и "во вторых" в моей нумерации.

спасибо. я б еще наверно долго тупил бы и искал проблему совершенно в другом месте.
ну вот, еще одно подтверждление того что простые загадки имеюют простые решения но очень сложный "этого решения" процесс
Go to the top of the page
 
+Quote Post
juvf
сообщение Feb 25 2014, 18:54
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Выпадаю в Hard Fault Exception. описал обработчик, получил вывод

[Hard fault handler]
R0 = 0x200014a0
R1 = 0x20001498
R2 = 0x2000123c
R3 = 0x20001980
R12 = 0x10003
LR = 0x8002c09
PC = 0x20001498
PSR = 0x8000000f

1)как понять от куда ноги растут у проблемы? Подозреваю что не хватает кучи. при увеличении кучи в HF не попадаю. но может есть утечка, и увеличив кучу я просто оттянул конец.

LR = 0x8002c09 - по этому адресу в дизассемблере нет команды. есть команда по адресу

Код
0x8002c08: 0x2800  CMP R0,#0


PC = 0x20001498 это похоже куча, из мэпа
Код
"P2", part 3 of 3:                         0x6d8
  HEAP                        0x20001480   0x300  <Block>
    HEAP             uninit   0x20001480   0x300  <Block tail>
  CSTACK                      0x20001780   0x200  <Block>
    CSTACK           uninit   0x20001780   0x200  <Block tail>
  .noinit            uninit   0x20001980   0x1d8  config.o [1]
                            - 0x20001b58   0x6d8


2)В какой документации описан регистр LR?

3)в документации на М3 "STM32F10xxx Cortex-M3 programming manual" есть описание регистра
Цитата
Hard fault status register (SCB_HFSR)
Address offset: 0x2C
Reset value: 0x0000 0000
Required privilege: Privileged
The HFSR gives information about events that activate the hard fault handler.

Почему среди регистров в дебаггире в EW IAR нет регистра HFSR?


ps EW IAR, STM32F100C8T6
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 26 2014, 11:30
Сообщение #8


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Судя по
Цитата(juvf @ Feb 26 2014, 00:54) *
LR = 0x8002c09
PC = 0x20001498

, при возникновении исключения выполнялся код в ОЗУ (0x20001498). Посмотрите команду, которая находится перед 0x8002c08, возможно дело в ней.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
juvf
сообщение Feb 26 2014, 12:28
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



спасибо.

перед 0x8002c09 такой код

Код
LDR R1, [R1]
LDR R1,[R1, #0x8]
BLX R1
CMP R0,#0

по адресу 0x8002c08 команда CMP R0,#0. Зметил ещё что как раз в R1 = 0x20001498

в стеке есть список классов созданный через new. от сюда и рс на кучу кажет. падает в перегруженном операторе --

if(--(*(MyClass*)p) )
{
}

ошибки в операторе -- нет. указатель р всегда указывает на нужное место (есди его только не портят в паралельном месте). Если увеличиваю в линкере кучу с 0х400 до 0х600, то больше HF не наблюдаю. Подозрене что не хватает кучи. Как это проверить?
Go to the top of the page
 
+Quote Post
MALLOY2
сообщение Feb 26 2014, 12:47
Сообщение #10


Знающий
****

Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317



Если это иар и используется его алокатор, то вам http://supp.iar.com/Support/?note=28545
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 26 2014, 12:54
Сообщение #11


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(juvf @ Feb 26 2014, 18:28) *
перед 0x8002c09 такой код

Код
LDR R1, [R1]
LDR R1,[R1, #0x8]
BLX R1
CMP R0,#0

Команда BLX R1 должна прыгать на код вашего перегруженного оператора, а вместо этого прыгает в ОЗУ. Да, похоже, что память портится.
Как посмотреть переполнение кучи в ИАРе - не знаю, не пользуюсь им.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Axel
сообщение Feb 26 2014, 14:00
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 480
Регистрация: 21-11-04
Пользователь №: 1 188



Цитата(juvf @ Feb 26 2014, 16:28) *
Подозрене что не хватает кучи. Как это проверить?


Да вроде бы несложно. После каждого вызова new (или malloc) сравнивать выделенный адрес с ранее полученными и запоминать максимальный, а в обработчике посмотреть, что получилось. Или, если есть что-нибудь типа debug_printf (IARом не пользуюсь, поэтому не знаю) - печатать в окне дебагера.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Feb 27 2014, 02:20
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(AHTOXA @ Feb 26 2014, 17:30) *
Судя по
, при возникновении исключения выполнялся код в ОЗУ (0x20001498). Посмотрите команду, которая находится перед 0x8002c08, возможно дело в ней.

Почему Вы решили, что в LR - адрес возврата из функции, в которой произошло исключение? Имхо - там может быть что угодно.
Пример:
PUSH {...,LR} ;стандартный вход в функцию, вызывающую другие функции
...
BL some_func
С этого места в LR - может быть, что угодно, может адрес этой инструкции, а может и что-то другое если возврат из some_func осуществлялся чем-то вроде POP {..., PC}, а не BX LR.
А ещё - оптимизатор может использовать LR как обычный РОН.
После улёта исполнения кода в произвольное место в ОЗУ, определить можно только адрес (PC), где произошло исключение.
Об остальном - только гадать.

Когда я боролся с подобной проблемой, я сделал монитор регистров CPU, повесил его на высокочастотное IRQ от таймера (такое чтобы давало >90% загрузки CPU).
В ISR просто писал дамп регистров CPU (и ближайшего стека) в FIFO таких дампов в ОЗУ. При наступлении сбоя - смотрел последовательность этих дампов и определял где
было последнее валидное состояние. Расстояние между такими дампами получалось всего несколько десятков команд - место сбоя ловилось довольно точно.

Ну или нужен какой-то аппаратный трэйсер с запоминанием потока команд и возможностью отмотать назад.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Feb 27 2014, 05:21
Сообщение #14


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(jcxz @ Feb 27 2014, 08:20) *
Почему Вы решили, что в LR - адрес возврата из функции, в которой произошло исключение? Имхо - там может быть что угодно.

Потому что обычно там находится адрес возвратаsm.gif И обычно компилятор использует LR именно для этих целей.
Цитата(jcxz @ Feb 27 2014, 08:20) *
Пример:
PUSH {...,LR} ;стандартный вход в функцию, вызывающую другие функции
...
BL some_func
С этого места в LR - может быть, что угодно

С этого места в LR как раз адрес возврата. Так работает инструкция BL.
Цитата(jcxz @ Feb 27 2014, 08:20) *
А ещё - оптимизатор может использовать LR как обычный РОН.

Не встречал такого. Компилятор знает, что там находится адрес возврата (он сам его туда положил). Поэтому обычно старается его не трогать. Если вы встречали такое, то приведите пример.
Цитата(jcxz @ Feb 27 2014, 08:20) *
После улёта исполнения кода в произвольное место в ОЗУ, определить можно только адрес (PC), где произошло исключение.

А вот это обычно как раз бесполезная инфа. Ибо в случае, когда исключение вызвано улётом в несуществующие адреса, значение этого несуществующего адреса не представляет никакого интереса. А вот откуда мы прыгнули на этот несуществующий адрес - это информация очень нужная. И эта информация как раз с хорошей вероятностью лежит в регистре LR.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Feb 27 2014, 05:51
Сообщение #15


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



При прерываниях адрес возврата сохраняется в стек (там его можно и найти, положение известно). А в LR заносится специальное слово EXC_RETURN (там почти одни единицы).
Go to the top of the page
 
+Quote Post

5 страниц V   1 2 3 > » 
Reply to this topicStart new topic
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 9th July 2025 - 22:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.0152 секунд с 7
ELECTRONIX ©2004-2016