I want to avoid or recover from a hardfault when addressing a non-existent memory location.
Other than not accessing non-existing memory in the first place (the best option) the fault can't be prevented.
It can be detected with a hard fault handler. I attached the code that I use it. It is based on these sources:
* https://github.com/feabhas/CM3_Fault_Handler
* http://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
* http://mcuoneclipse.com/2012/12/28/a-processor-expert-component-to-help-with-hard-faults/
* https://mcuoneclipse.com/2012/11/24/debugging-hard-faults-on-arm-cortex-m/
* https://community.nxp.com/thread/304064#comment-315205 KL25 Freedom Board HardFaults, un-used interrupts and finding outi
Use attached as example, it is incomplete without the other supporting functions, how things are on the stack is really what you want to know.
Also you may find that what you really want to know is impossible to discern from the information that is actually available.
I probably should have said more about what I am doing.
I usually add some backdoor to my projects which allows a user to, among other things, view MCU memory from a PC as the real program is executing in the MCU. The PC user might specify some non-existent memory address and I do not want this to cause the MCU program to crash.
So the MCU that facilitates this doesn’t just load the memory directly in to its transmit buffer but rather calls a routine that is supposed to return the contents of the desired memory location, or if that location doesn’t exist, return 0xff (or whatever). The ‘C’ code looks like this:
TxBuf[n1] = LookupByte(DumpAddressn);
Knowing this could generate a fault, I wrote LookupByte in assembly language:
.global LookupByte
LookupByte:
ldrb r0,[R0]
bx lr
.global HardFault_Handler
HardFault_Handler:
push {r7, lr}
add r7,sp,#0
ldr r0,LookupByteAdr
ldr r1,[sp,#0x020] // Get address of faulting intruction
cmp r0,r1 // If it's not LookupByte
HFH10: // then loop forever
bne HFH10
adds r1, r1, #2 // If it is our LookupByte intruction
str r1,[sp,#0x020] // add two and store back so we
// continue on
movs r0,#0xff // We rturn 0xff for non-existent locations
str r0,[sp,#8] // Store at locn from where r0 will be restored
mov sp, r7
pop {r7, pc}
LookupByteAdr: .word LookupByte
This works just fine if I single step through the code in KDS. It also works fine if I set a breakpoint in the Disassembly window at the first instruction of HardFaultHandler (HFH) and hit CONTINUE each time the breakpoint is reached. (For some reason setting the same breakpoint in the source window doesn’t work.) But if I set the breakpoint at the second instruction of HFH or if I set no breakpoint at all the processor regularly resets; probably when the processor tries to execute that second instruction of HFH.
I would also point out that if I set the breakpoint at the first instruction of LookupByte (LB) and press CONTINUE, the program breaks again at the second instruction of LB. CONTINUing there gets back to the breakpoint at the first instruction of LB, and this sequence can be CONTINUEd indefinitely.
Apart from getting my code to work, I would like to understand what is happening. I have experience with debuggers probably since there have been debuggers and I am not used to having a debugger change the behavior of a program not related to timing when a breakpoint is hit or when single-stepping, except that interrupts are usually blocked when single-stepping.
I look forward to receiving your response.
What is the -O optimization level set at?
Does it work as you expect at -O0 (Oh Zero) as far as debugger?
Any Watchdogs involved?
Can't say I understand why the saving of SP in R7 to be restored at exit?
The valid memory address ranges are a known at compile time, could they not be validated before accessed?
I did not really have any other ideas, which was why no response.
I do disagree with turning optimization off as a mater of course.
For GCC -O2 works fine with any modern version of the compiler.
As you said it is assembly language anyway.
Looking at your assembly language again, why add two here (Thumb Code?) I would have expected to add four (ARM Code)?.
Are not faults always ARM mode?
adds r1, r1, #2 // If it is our LookupByte intruction
str r1,[sp,#0x020] // add two and store back so we
// continue on
This recovery is also assuming that the hardware fault handler has not in someway altered the state of the processor.
I do not know if that assumption is valid. Does more need to be done than a simple return to recover?
As to single stepping debugging issues, no idea. I've always found it fickle at best as to if it works.
I wonder if you could discuss this with, or forward my question to, a colleague.
Regarding YOUR questions: I add two to the address of the offending instruction because the offending code is Thumb Code. I hadn’t really thought about the processor switching to ARM Code. I don’t know if it does. I suppose that might be a key to understanding why I am getting reset as I am. But I was hoping you or one of your colleagues might point me in the right direction here. Same comment about pointing me in the right direction if I am overlooking some processor state that needs to be restored. If I knew about any, it would have been restored.
Regarding optimization, I’ve been doing this stuff for about 50 years now. It is my experience that optimization very much gets in the way while debugging, and sometimes introduces errors on its own. I suppose that these can be understood and eliminated but why bother if the processor isn’t heavily loaded.
I'm an other user here like yourself, no affiliation with ARM/Freescale/NXP etc.
Perhaps this would help:
"Reading from or writing to invalid address Data Access Memory Abort (Data Abort)"
I have to thank you.
Something you said about ARM and Thumb made me recall that address transfers in Thumb must have the LSB of the address set. I looked at the addresses in my vector table and all had the LSB set except my HardFault_Handler. I set it by hand but that didn’t fix things. So I copied the two directives in front of the default HardFault_Hander (“ .thumb_func” and “ .type HardFault_Handler, %function” neither of which I could find any documentation about) in front of my HardFault_Handler and everything worked ! (Including the LSB being set in the vector table)
Optimization – all turned off (I don’t trust it, and besides this is assembly code.)
Watchdog – disabled, I think. I’ve never enabled it; and it hasn’t been a problem during the month or two I’ve been experimenting with this processor.
saving of SP in R7 – I don’t know why it’s there either. I just copied what the compiler did for ‘C’ based interrupt routines. I figured it couldn’t hurt.
valid memory address ranges known at compile time – I’m not sure this is true. I think faults occur when looking at device registers if the clock for the device is not enabled. In any case the mapping of device register addresses isn’t so simple.
I would note that whenever the memory browser window is asked to display a non-existent location, it displays question marks, so it knows; or seems to. There are times when it displays question marks for valid device register addresses that are visible when trying to view these same addresses in the expressions window.