Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Catching Rogue Memory Accesses With ARM Watchpoint Comparators

DZone 's Guide to

Catching Rogue Memory Accesses With ARM Watchpoint Comparators

Want to learn more about catching rogue memory accesses? Check out this tutorial to learn how with ARM watchpoint comparators and Eclipse.

· IoT Zone ·
Free Resource

In my "Tutorial: Catching Rogue Memory Accesses with Eclipse and GDB Watchpoints," I used Eclipse/CDT and GDB watchpoints. I used a conditional watchpoint, but this comes with a performance hit. In this article, I will demonstrate how to use the ARM Cortex trace hardware to catch specific writes to a memory location without severe performance degradation. But for this, I need a little helper — the Deadbeef catcher!

Image title

Outline

Compared to the previous article, Tutorial: Catching Rogue Memory Accesses with Eclipse and GDB Watchpoints, I was going beyond the normal watchpoint usage. I'm going to use dedicated plugins and views in the free-of-charge Eclipse-based NXP MCUXpresso IDE 10.2.1. As a board, I'm using the NXP FRDM-K64F with an external NXP LPC-Link debug probe attached to it — see " Custom 3D Printed Enclosure for NXP LPC-Link2 Debug Probes."

Be aware that not every ARM Cortex-M device implements the capabilities used in this article. I'm using instruction trace with watchpoint triggers, which do need the ARM MTB (Micro Trace Buffer) to be implemented, which can be augmented with the ARM ETM (Embedded Trace Macrocell).

This uses a trace buffer in RAM, which can be configured as a ring buffer. On the plus side, I don't need any dedicated trace pins or expensive debug probes; I can use normal debug probes, which are able to read/write the memory on the device.

That's why I can use for example the NXP OpenSDA with Segger J-Link, P&E Multilink, or the NXP LPC-Link2:

Image title

The needed trace configuration and knowledge are in the debugger and IDE. That way, I have special views for configuration and trace viewing available in the NXP MCUXpresso IDE.

It would be possible to configure the trace and watchpoint hardware with GDB commands/scripting or directly in the application, but this would be beyond this article.

For further information, have a look at the provided IDE documentation:

Image title

Test Code

As in the previous article, I'm going to use the following function as a test case, emulating rogue access to memory.

static uint32_t testVar;
static void bar(void) {
    for(counter=0; counter<5000000; counter++) {
        testVar++;
        if (counter==134566) { /* emulating something else corrupting my testVar */
            PRINTF("catch me...");
            testVar = 0xdeadbeef; /* outsch! */
            PRINTF("if you can!");
        }
        __asm("nop"); /* just doing something */
    }
}


What I want to catch with the debugger is a write to testVarwith a value of 0xdeadbeef.

Getting Started

Note that the views used below are the ones from the NXP MCUXpresso IDE 10.2.1 and are not available in other Eclipse distributions.

First, open the Instruction trace Config view:

Image title

You can open that view from the IDE Window > Show View menu:

Image title

As noted in the view, I need a working debug connection to the board, so make sure that you start a debug session, and have it halted/suspended. Then, the view should look like this:

Image title

Configuring Trace and Triggers

With the connection to the target, use the Refresh button:

Image title

This loads the current settings from the target:

Image title

Next, inside the 'Enable trace' tab, make sure that trace is enabled:

Image title

Keep that tab in the foreground/visible, as this defines the setting!

Next, we want to stall the ETM on the processor if the FIFO buffer is getting full. Below, I have configured it with 14 free bytes free, it shall stall the processor:

Image title

Next, I'm going to create the trigger event, if something writes to my variable in question. In my case, I see that my variable is located at 0x2000'001c:

Image title

I click on the 'Request' button to get a comparator. I configure it for 'Data Write' at the address 0x2000001c. The mask is optional — with this, I catch an address range.

Image title

This would trigger for any writes to that address (range). I'm interested in a piece of code that writes the 0xdeadbeef pattern. So, I'm going to add this as for the second comparator.

I use a second comparator with 'Data Value Write' and the data pattern as match value. I have it linked back to my address (data write) comparator ID 1 (for both links) to build a linked/combined comparator. Don't forget to specify the data size (Word or 32bits in my case):

Image title

Now, I have to specify what shall happen if the comparator triggers. Switch the "Trigger condition" to the tab with One Input. I'm using only one input to the condition, so I specify that the comparator ID 2, which is linked to ID 1. I have set up in one of the previous steps:

Image title

Keep that tab in the foreground/visible, as this defines the setting!

Next I’m going to configure how many words are written to the buffer after the trigger fires to get some context around the trigger event. I have configured it for 50 words below so I still have 462 words in the trace buffer to see where the code is coming from:

Image title

As the last set, I want the trigger to raise a debug request. This will stop the debugger, and I can inspect what happened:

Image title

Finally, use the green checkmark icon to store the settings on the target:

Image title

This configures the trace and trigger registers on the microcontroller. With the settings stored, the green button will turn grey:

Image title

Additionally, that toolbar has saved and restored buttons to save my precious configuration in a text/XML file (default is etmConfig.xml) on the disk.

If the view does not show the loaded values (I had this in 10.2.1) after loading from the XML file, close the Instruction Trace Config view and re-open it again. Change a value (e.g. disable trace) and store it on the target, then enable trace again and store it again on the target with the green button. You still have to enable the comparators. Make sure you cross-check the values in the settings.

In summary, below is my configuration with all the settings:

Image title

Catching It

Continue running the application with the debugger. If the trigger condition gets true, be aware that the debugger will halt the running application with a screeching stop:

Image title

As explained in " Tutorial: Catching Rogue Memory Accesses with Eclipse and GDB Watchpoints, " there will be some jitter and the target will stop a few instructions after the event, so you have to go back a few lines of code. In my application above, the target finally came to a stop while executing instructions inside  _printf().

Excellent! We have found the place! But, it does not stop here as we are using trace, so we have recorded the instructions leading to this memory corruption. Let's have a look!

Instruction Trace

For this, open the Instruction Trace view (if not opened already):

Image title

Image title

Press the button in the toolbar of that view to get the data from the target (ETB content):

Image title

The toolbar has an icon, which I can use to jump to the trigger packet:

Image title

That way, the offending instruction is easily identifiable:

Image title

The view has two buttons that sync with the source and disassembly view. Because of this, I can go through the trace sequence and have the source for it (if available) synced:

Image title

Now, with knowing that location changing my memory location, all that I need to do now is to fix the bug behind it.

Watchpoints with gdb are good, but hardware watchpoint triggers are better. But, they are not easily accessible and might be complicated to set up. Using the MCUXpresso IDE helps because it provides a convenient access to the ARM MTB/ITM hardware. Due to this, I can configure a watchstop trigger and, as an extra benefit, I get instruction trace. I hope you find this tutorial useful!

Happy DeadBeef'ing!

Links

Topics:
iot ,performance ,tutorial ,arm ,watchpoint ,mcuxpresso ide ,deadbeef ,eclipse

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}