About breakpoints and watchpoints

Breakpoints and watchpoints enable you to stop the target when certain events occur, and when certain conditions are met. When execution stops you can then choose to examine the contents of memory, registers, or variables, or you might have specified other actions to be taken before execution resumes.

The debugger provides the following types:

Breakpoints

A breakpoint enables you to interrupt your application when execution reaches a specific address. A breakpoint is always related to a particular memory address, regardless of what might be stored there. When execution reaches the breakpoint, normal execution stops before any instruction stored there is performed.

You can set:

  • software breakpoints that trigger when a particular instruction is executed at a specific address

  • hardware breakpoints that trigger when the processor attempts to execute an instruction that is fetched from a specific memory address

  • conditional breakpoints that trigger when an expression evaluates to true or when an ignore counter is reached

  • temporary software or hardware breakpoints that are subsequently deleted when the breakpoint is hit.

The type of breakpoints you can set depends on the:

  • memory region and the related access attributes

  • hardware support provided by your target processor

  • debug interface used to maintain the target connection

  • running state if you are debugging an OS-aware application.

Watchpoints

A watchpoint is similar to a breakpoint, but it is the address or value of a data access that is monitored rather than an instruction being executed from a specific address. You specify a register or a memory address to identify a location that is to have its contents tested. Watchpoints are sometimes known as data breakpoints, emphasizing that they are data dependent. Execution of your application stops when the address being monitored is accessed by your application.

You can set:

  • watchpoints that trigger when a particular memory location is accessed in a particular way

  • conditional watchpoints that trigger when an expression evaluates to true or when an ignore counter is reached.

Show/hideConsiderations when setting breakpoints and watchpoints

Be aware of the following when setting breakpoints and watchpoints:

  • The number of hardware breakpoints available depends on the target.

  • If an image is compiled with a high optimization level or perhaps contains C++ templates then the effect of setting a breakpoint in the source code depends on where you set the breakpoint. For example, if you set a breakpoint on an inlined function or a C++ template, then a breakpoint is created for each instance of that function or template. Therefore the target can run out of breakpoint resources.

  • Enabling a Memory Management Unit (MMU) might set a memory region to read-only. If that memory region contains a software breakpoint, then that software breakpoint cannot be removed. Therefore, make sure you clear software breakpoints before enabling the MMU.

  • Watchpoints are only supported on global/static data symbols because they are always in scope. Local variables are not available when you step out of a function.

  • Some targets do not support watchpoints. Currently you can only use watchpoint commands on a hardware target using a debug hardware agent.

  • The address of the instruction that triggers the watchpoint might not be the address shown in the PC register. This is because of pipelining effects in the processor.

  • When debugging an application that uses shared objects, breakpoints that are set within a shared object are deleted when the shared object is unloaded.

  • If a breakpoint is set by function name then only inline instances that have been already demand loaded are found. To find all the inline instances of a function you must disable on-demand loading.

 

Hardware and Software Breakpoints

Every developer uses breakpoints to debug their software. It’s fundamental. Double click on the line of code that you want to break program execution on and then let it go (or is it break?). Quite a few developers that I encounter don’t realize that there are different breakpoint mechanisms occurring in the background that provide this critical functionality. In this post, we’ll examine the difference between a hardware and software breakpoint and how it can effect us as developers.

The first breakpoint type that is used and generally preferred is a hardware breakpoint. Every microcontroller has comparators which are part of the debugging module. For example, the ARM Cortex-M microcontrollers can have 2 – 4 comparators in their debugging module. The comparator is set with a program counter value and when a match occurs, a debug event is raised and the program halts. Hardware breakpoints are the fastest and the most used breakpoint. (Note: ARM Cortex-M3 has build-in 6 breakpoints and 4 watchpoints)

Hardware breakpoints have a problem. A microcontroller will typically only have 2 – 4 comparators which means once they are used up, no more breakpoints can be added! I can’t tell you how many times I’ve wanted three or more breakpoints in my application only to have to strategically switch in and out which breakpoints are active. It’s annoying and also time consuming. Thankfully, there are also software breakpoints.

A software breakpoint is typically an instruction that temporarily replaces an instruction in RAM that is either an illegal instruction and causes a fault or is designed to cause the application to break. A perfect example is the BKPT instruction in the ARM instruction set. When the CPU reaches this instruction, it halts execution. Software breakpoints can only be used for application code that reside in RAM. The reason is that an instruction is literally swapped out for the breakpoint instruction. Once a developer steps past the BKPT, the originally code that would have executed at that location is ran.

Developers can use a nearly endless number of software breakpoints but the major issue is that again they are designed for code running in RAM. On a modern microcontroller such as an ARM Cortex-M, the odds are that the code is executing from flash. This brings us to a third breakpoint type, the flash breakpoint.

Flash breakpoints allow a developer to create unlimited breakpoints for applications that are running from flash. Just like a regular software breakpoint, a flash breakpoint has the ability to have a nearly endless number of breakpoints. They also can work on a microcontrollers internal and external flash memory! An example debugger that has this capability is the Seggar J-Link (usually the Pro or Ultra+ version but I understand licenses can be purchased for other version as well). There are numerous methods that debugger vendors use to create flash breakpoints and the best are nearly as fast as a typical hardware breakpoint.

From a developers standpoint, which breakpoint type that is used almost doesn’t matter. It’s important for developers to understand though the breakpoint type that is being used and the maximum number of hardware breakpoints that their system is capable of. Purchasing a high quality, professional debugger is always a great idea to ensure that the necessary number of breakpoints are available and that they are fast enough for the application at hand. If that isn’t an option, careful microcontroller selection can also help make sure that you maximize how many hardware breakpoints are available to you.

 

Making the best use of the available breakpoints

https://www.iar.com/support/resources/articles/making-the-best-use-of-the-available-breakpoints/

 

The concept of a breakpoint is very simple since it only interrupts the execution of a program right before a specified instruction. The implementation can be in hardware or software but this will not be discussed here. Being simple doesn’t mean that it can’t be used in complex combinations that can solve a bug in an easy way. The fact is that software developers cannot live without breakpoints, but how to make the best use of them?

In IAR Embedded Workbench, we have the possibility to use the following breakpoints:

  • Code breakpoints
  • Conditional code breakpoints
  • Data breakpoints with read and write access
  • Data Log breakpoints
  • Log breakpoints
  • Power breakpoints
  • Trace Start and Stop breakpoints

This text will try to give the best hints on how to debug your application faster and make use of each one of the available breakpoints.

Code breakpoints

This is the simplest use of a breakpoint. You only need to choose the C line or the ASM instruction in the disassembly windows and toggle the breakpoint. Once the breakpoint is hit, your application will stop. At this time, you can check the values of variables, flags and registers. In other words, you have full control.

The number of code breakpoints is limited to the number of hardware breakpoints but can be unlimited if you make use of software breakpoints or run the application in RAM. Even with a limited number, for example for Arm Cortex-M where we have 6-8 breakpoints, you could save the location and disable and enable the breakpoint when needed. Just choose to show the View ->Breakpoints window and you will be able to set/clear the box, which means enabling or disabling the breakpoint.

In this case, you can have more than 6-8 breakpoints but not all active at the same time.

By default, the IDE will set code breakpoints. If you have an I-jet debug probe you can explicitly choose a flash breakpoint when right clicking on the line of code. This is useful if you already made use of all the existing hardware breakpoints. Notice the “F” in the breakpoint symbol. The flash breakpoints feature is available in version 7.60 or later of IAR Embedded Workbench for Arm.

Conditional Code breakpoints

A conditional breakpoint is the combination of a code breakpoint with some flag or variable as a condition. Once a breakpoint is set, you can again use the View ->Breakpoints window to see all breakpoints, but also set extra parameters by right clicking and select Edit option.

The syntax to be used is similar to the C syntax and you can use ==, >= and <=. For example, if you want the application to halt at the breakpoint when the counter is equal to 10, you use “counter==10”.

This is very useful when a breakpoint is needed inside an interrupt routine. Without a condition, it would be impossible to debug your application since it would halt all the time. Using a flag or variable as a condition makes things much easier. You can also go a bit further using the skip counter and a condition check like true or changed.

Data breakpoints with read and write access

Data breakpoints are a bit different compared to other breakpoints since they monitor the read and write access to a specific memory address, flag, variable or register. Using this breakpoint is very straightforward. Simply right-click the flag or variable and select the option Set data Breakpoint. By default, the read and write accesses will be monitored. If you want to add extra setting you can do it through the View->Breakpoints window and Edit option. Aside from the accesses, it is possible to monitor if the data matches. This means that the write or read access would only trigger the halt if the data matches. By choosing the Edit button, you open an extra window that makes it possible to select absolute addresses or even a source line. In case of a variable or flag, it is recommended to use the auto size. If a bigger range needs to be monitored, the manual size should be used with the desired size.

The data breakpoint is very useful to debug flags and variables that are being corrupted by the application. Once there is some access the application halts. Another approach is the stack overflow investigation. Just set a data breakpoint at 80-90% of the stack size and when the overflow is near, you can halt the application and go step by step to find the root of the problem.

Data Log Breakpoints

In addition to data breakpoints with read and write accesses, you can also use data log breakpoints. The idea with these is to monitor and plot graphically the value of a specific variable or address in memory in the timeline. This makes it easy to compare two or more variables and consider the time variant or some interrupts that are being triggered.

The timeline and the additional data log and data log summary are available under the probe options, for example as seen in the screenshot below.

Log Breakpoints

Aside from the code and data breakpoints, you also have the log breakpoints. This is a special breakpoint since it will only temporarily halt the application to print a message. It will only show the selected message once the breakpoint is hit.

Every time the breakpoint is hit, a message will be displayed in the debug log window. An added counter makes it is possible to know how many times the application passed that part of the source code.

Power breakpoints

Thanks to the power debugging technology in IAR Embedded Workbench, you can monitor the energy consumption and correlate it with the source code. This makes it possible to know the energy consumption of the entire application. This concept also makes it possible to add power breakpoints. It is possible to set a threshold, like 25mA, and the debugger will halt once the energy is above this value.

Setting the threshold is very simple. You only need to open the I-jet/JTAGJet->PowerLog window and then set the value and desired option as shown above or below the value.

The feature is useful to guarantee to not have any peaks of power consumption or higher values than specified, and the battery will last longer with this kind of analysis. You can just leave your application running for a long period of time. The timeline window is not necessary but it gives you the complete information about the energy that is being used.

Trace Start and Stop breakpoints

The last breakpoints that I would like to point out are the trace start and stop breakpoints. These are possible to take advantage if you have access to an advanced trace probe, like I-jet Trace for Arm Cortex-M or I-jet Trace for Cortex-A/R/M. This is especially useful when trying to analyze a reduced part of the application or if you have a trace probe with a smaller buffer. In most cases, the probe has 64 Mbyte - 256 Mbyte of trace memory size. The usage of trace start and trace stop breakpoints is straightforward and the only think you need to do is to right-click in the lines of the source code and decide where the trace should start and end. The trace buffer will only have the instructions between the desired lines of code in the application.

You can also have a graphical overview of the call stack from the trace instructions in the timeline that have been captured between the trace start and stop breakpoints. 

A trace probe, like I-jet Trace, is always more powerful than a standard JTAG/SWD probe but sometimes it can become tricky to interpret all the information correctly. In order to avoid collecting millions of unnecessary instructions and make the debug with trace straightforward, IAR Embedded Workbench offers the capability of start and stop trace breakpoints.

posted on 2019-11-28 12:30  荷树栋  阅读(569)  评论(0编辑  收藏  举报

导航