Skip to content

iarsystems/crun-evaluation-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Evaluation Guide for IAR C-RUN

What is C-RUN?

C-RUN is an add-on runtime analysis tool completely integrated into IAR Embedded Workbench. It helps you to ensure code quality in your C and C++ code by inserting efficient instrumentation code into the application for automatic runtime error checking capabilities.

What is this guide?

This guide contains a walkthrough for evaluating the runtime error checking capabilities offered by C-RUN.

You can evaluate C-RUN right now free of charge with a 14-day time-limited trial version of IAR Embedded Workbench for Arm or IAR Embedded Workbench for Renesas RX. Register and download using the corresponding links provided in the Software Requirements table, under Required License Types, for the target architecture of your choosing.

Software requirements

This guide works for any of these products, given that the requirements are met:

Product Target architecture Required version Required license types
IAR Embedded Workbench Arm 8.11 or later - Cortex-M, or
- Standard, or
- Extended, or
- Time-limited trial version
IAR Embedded Workbench Renesas RX 5.10 or later - Standard, or
- Time-limited trial version

Note

No special action needs to be taken when you evaluate C-RUN in code-size-limited mode using the time-limited trial version. This special mode was created to allow customers to evaluate C-RUN using smaller pieces of code while exploring its tight integration with the IAR C-SPY Debugger.

Tip

For access to a non-limited license contact your IAR representative.

Exploring C-RUN

A number of example projects, created as demonstrations of the feature set offered by C-RUN, can be found in this repository.

To run the examples:

  1. Clone this repository, or download the latest release.
  2. Launch the IAR Embedded Workbench IDE for a supported target architecture.
  3. Open the Workspace.eww file, found in the folder for the desired target architecture.

The workspace will launch with a pre-selected project. In the workspace Overview there are tabs for switching from one project to another:

image

Tip

The arrow buttons scroll to tabs that did not fit into the window width. The window can be resized. Alternatively, right-click a project in the Overview and choose Set as active from the context menu.

Below you will find specific instructions for running each of these projects.

Arithmetic Checking

The first example explores the most straightforward functionality in C-RUN: the Arithmetic checks.

To run this example, do this:

  1. Select the Arithmetic project in the workspace window.

  2. Choose ProjectOptions (Alt+F7) → Runtime Checking.

  3. Make sure that C-RUN Runtime Checking is enabled

image

  1. Make sure all these checks are selected:

image

  1. Click OK to close the Project Options dialog box.

  2. Choose ProjectDownload and Debug (Ctrl+D) to start executing the application.

  3. The C-SPY Debugger will hit a breakpoint at main(). Press F5 to resume the program execution.

  4. The execution will Stop, with the following line of code highlighted:

image

In the editor window, C-SPY highlights in green the statement in which the execution stopped when the runtime error checking was triggered. In addition, C-RUN narrows the problem down and highlights the root cause of the runtime error.

image

Concurrently, the C-RUN Messages window (ViewC-RUNMessages) will break down the detected runtime error as well as its call stack. Clicking on the call stack takes you to the corresponding source code line.

  1. Examine the remaining detected errors by pressing F5 to resume the program execution until the next error message, or until the execution ends.

image

  1. Stop the debug session (Ctrl+Shift+D).

  2. When you create applications, there are situations where relying on the wrap-around property of overflown unsigned integers is efficient. In such cases, specific C-RUN checks can simply be deselected. In the project's Runtime checking options, disable these:

image

  1. Rebuild, Download and Debug (Ctrl+D) the application, and examine the changes in the error detection capabilities.

Note

  • Disabling the checks you do not need will generally make execution faster while decreasing the code size.
  • The Default Action for C-RUN is to Stop at each detected error. In the C-RUN Messages window, the Default action can be switched to Log or to Ignore.
  • C-RUN Messages can also be filtered by rules. For details, refer to the Creating rules for messages section in the C-SPY Debugging Guide.

Bounds checking

The second example explores the Bounds Checking capabilities provided by C-RUN.

To run this example, do this:

  1. Select the Bounds-checking project.

  2. Choose ProjectDownload and Debug (Ctrl+D) to start executing the application.

  3. After the execution reaches the breakpoint in the main() function, resume the execution (F5).

Note how the application finishes executing (exit()) without any apparent errors of any kind.

  1. Stop the debug session (Ctrl+Shift+D).

  2. Choose ProjectOptions (Alt+F7) → Runtime Checking and enable bounds checking:

image

  1. Rebuild and run the project.

image

Note that now C-RUN highlighted an out-of-bounds access for *(ap+2). However, the execution stopped earlier, at the first printf() statement. The reason is that the compiler determines that pointer addresses used as parameters for those printf() calls are related and, with that, C-RUN efficiently can test them in one go.

  1. Press F5 to resume the execution and inspect the remaining C-RUN Message:

image

Tip

It will stop at the last statement of the application, indicating that the assignment is performed out of bounds. From a bounds-checking perspective, dynamically allocated memory is no different from local pointers, static buffers, or buffers on the stack.

  1. Again, choose ProjectOptions (Alt+F7) → Runtime Checking and take a look at the Global bounds table group box.

image

Pointers that can be accessed through other pointers must have information in a table stored in memory. The Number of entries field allows you to fine-tune the number of slots available in the table.

Warning

Leaving Number of entries blank will remove the limit, resulting in a large global bounds table (4k slots!). The number of entries you need is often fairly low, so you might want to experiment with shrinking the global table, to lower the resource consumption for the instrumentation. Do not worry if you use a number that is too low; if this happens, you will get a warning message telling you that the global bounds table is running out of slots.

  1. Set the Number of entries to 1 and close the Project Options dialog box.

  2. Rebuild, and Download and Debug (Ctrl+D) the application.

In this example, there is only one pointer that needs to be kept in the table, so a single entry is enough.

Bounds checking and libraries

In scenarios where the main project relies on pre-built (third-party) libraries, bounds checking requires extra consideration for shared pointers.

The project Bounds-checking+libs is a modified version of the Bounds-checking project. The functionality available from the IntMax.c file was moved to a Library project that produced a static library named MaxLib.a, pre-built with no C-RUN bounds-checking instrumentation, typical for third-party libraries where the code cannot be changed.

When you use pointers and pointer arguments between the instrumented application code and the non-instrumented library code, you must inform the compiler (and linker) that functions in the library code do not have bounds-checking information. The best way to do so is to use the #pragma default_no_bounds directive when including a library header, to inform the compiler that the library was not built with C-RUN Bounds-checking information:

image

To run this example, do this:

  1. Select the Bounds-checking+libs project.

This project comes with two build configurations, with different options for C-RUN:

  • DoNotCheckPointersFromNonInstrumentedCode and
  • CheckPointersFromNonInstrumentedCode
  1. Begin with the DoNotcheckPointersFromNonInstrumentedCode build configuration.

At the top of the Workspace window, you can switch between existing build configurations.

  1. Choose ProjectOptions (Alt+F7) → Runtime Checking and confirm these settings:

image

  1. Close the Project Options dialog box, and choose ProjectDownload and Debug (Ctrl+D) to start executing the application.

You should get no C-RUN errors, or any other indications that something is wrong. In the DoNotCheckPointersFromNonInstrumentedCode build configuration, turning off bounds-checking information for library headers worked well- (As it should do in most cases; returned pointers will not be bounds-checked but will have associated bounds that are always "large enough" to accommodate them.) In other words, this means that pointers originating from your code will be checked, but not pointers from the library. This should normally be perfectly acceptable and the process is non-intrusive in terms of code changes.

  1. Stop the debug session (Ctrl+Shift+D).

  2. Switch to the CheckPointersFromNonInstrumentedCode build configuration.

The CheckPointersFromNonInstrumentedCode build configuration demonstrates a situation where it is desirable to have bounds checking for pointers and returned pointers defined in the library code.

  1. Choose ProjectOptions (Alt+F7) → Runtime Checking and make sure that the C-RUN Runtime Checking options are:

image

  1. Build and run the application again. This time you should see one C-RUN message for the third printf() statement.

Read the source code and compare the use of __as_make_bounds() for the pointer ap to how the bounds are set for the pointer used in the next printf() statement. We have also defined a project-specific macro to control the use of __as_make_bounds(). This built-in function is used when the returned pointer must be given sensible bounds. If no bounds are given for returned pointers, a bounds error will be generated on the first access made to the pointer. Note that this build configuration defines a preprocessor symbol called CONFIG that conditionally compiles with __as_make_bounds() calls to give pointers sensible bounds.

  1. Comment out one of the calls to the CRUN_MAKE_BOUNDS() macro, rebuild and run.

❔ Did it change the output in the C-RUN Messages window?

Heap checking capabilities

C-RUN can check for errors in how heap memory is being used. Heap checking can catch when the application tries to use already freed memory, non-matching deallocation attempts, and leaked heap blocks.

When you use heap checking, each memory block is expanded with bookkeeping information and a buffer area, so that the blocks as seen by the application are not located side-by-side.

The various checker functions examine the bookkeeping information and the buffer areas and report violations of correct heap usage.

Warning

  • Using heap checking makes it much easier to find heap usage errors, but it is not fail-safe.
  • Heap checking and bounds checking can complement each other in identifying dynamic memory usage errors. However, because of the potential impact in terms of performance and overhead, you are advised not to enable both at the same time.

To run this example, do this:

  1. Select the Heap project.

  2. Choose ProjectOptions (Alt+F7) → Runtime Checking.

  3. Make sure that Use checked heap is enabled:

image

  1. Choose ProjectDownload and Debug (Ctrl+D) to start executing the application.

  2. Examine the source code comments for each reported error.

image

  1. Stop the debug session (Ctrl+Shift+D).

Note

The function HeapFunc3() in Heap.c can be enabled by uncommenting the CRUN_FULL_EDITION macro definition. The function requires a full edition of C-RUN since its resource consumption will exceed the code size limitation in the time-limited trial version. Contact us in case you need the full license or a demonstration.

Using C-RUN in non-interactive mode

There are scenarios in which might not be possible to debug an application built with C-RUN information directly from the IDE. Below you will find some examples on how to use C-RUN in non-interactive mode.

C-RUN Runtime Analysis from the command line

The IAR C-SPY Command Line Utility (cspybat) can run applications directly from the command line. This utility is suitable for non-interactive debugging and can be used in conjunction with IAR C-RUN where runtime analysis is desired. One typical scenario for considering cspybat is within automated tests from a continuous integration environment. In this example, we will use the Heap project.

  1. Close the IDE, launch a Command Prompt shell and change to the Heap project's folder.
cd \path\to\crun-evaluation-guide\arm

Tip

You will notice that, in this project's settings/ folder, the IDE automatically generated four files for each project(/build configuration):

File Description Example
<project>.<cfg>.cspy.bat Batch script for executing the application using cspybat Heap.Debug.cspy.bat
<project>.<cfg>.cspy.ps1 PowerShell script for executing the application using cspybat Heap.Debug.cspy.ps1
<project>.<cfg>.general.xcl Extended command line (*.xcl) containing general options Heap.Debug.general.xcl
<project>.<cfg>.driver.xcl Extended command line (*.xcl) containing backend/driver options Heap.Debug.driver.xcl

Inspect the scripts and its accompanying files and you will see all project parameters that are needed to execute the application using cspybat.

  1. Use the option --rtc_enable to enable C-RUN in cspybat.
echo --rtc_enable >> settings\Heap.Debug.general.xcl
  1. Execute the batch script.
settings\Heap.Debug.cspy.bat
Expected output example (click to expand)
C:\crun-evaluation-guide\arm>settings\Heap.Debug.cspy.bat

C:\crun-evaluation-guide\arm\settings>"C:\IAR\EW\ARM\9.50.2\common\bin\cspybat"
-f "C:\crun-evaluation-guide\arm\settings\Heap.Debug.general.xcl"
--backend -f "C:\crun-evaluation-guide\arm\settings\Heap.Debug.driver.xcl"

    IAR C-SPY Command Line Utility V9.3.2.12345
    Copyright 2000-2024 IAR Systems AB.

Heap usage error @ 0x227a Core: 0
The address 0x20001249 does not appear to be the start of a heap block.
Call Stack:
   HeapFunc1 in "C:\crun-evaluation-guide\common\Heap.c", 32:3 - 32:10
   main in "C:\crun-evaluation-guide\common\Heap.c", 101:3 - 101:13
   [_call_main + 0xd]
Heap usage error @ 0x2280 Core: 0
The address 0x20001208 does not appear to be the start of a heap block.
Call Stack:
   HeapFunc1 in "C:\crun-evaluation-guide\common\Heap.c", 34:3 - 34:10
   main in "C:\crun-evaluation-guide\common\Heap.c", 101:3 - 101:13
   [_call_main + 0xd]
Heap usage error @ 0x2286 Core: 0
The address 0x20001249 does not appear to be the start of a heap block.
Call Stack:
   HeapFunc1 in "C:\crun-evaluation-guide\common\Heap.c", 35:1 - 35:1
   main in "C:\crun-evaluation-guide\common\Heap.c", 101:3 - 101:13
   [_call_main + 0xd]
Out of heap space @ 0x2292 Core: 0
There is no more heap space to allocate.
A request for 4120 bytes could not be satisfied.
A total of 36 bytes have been allocated in 1 heap blocks.
Call Stack:
   HeapFunc2 in "C:\crun-evaluation-guide\common\Heap.c", 44:3 - 44:9
   main in "C:\crun-evaluation-guide\common\Heap.c", 102:3 - 102:13
   [_call_main + 0xd]

    CSpyBat terminating.

Note

  • All cspybat options for C-RUN begin with --rtc_*. For more information about these options, see cspybat options for C-RUN in the C-SPY Debugging Guide.
  • The IDE might regenerate the project's *.xcl files, overwriting your changes. Use attrib +r settings/*.xcl if you wish to pin it and avoid further automatic changes performed by the IDE. Use attrib -r settings/*.xcl to remove the read-only attribute.

Redirecting C-RUN messages to a serial port

Now consider scenarios where there is a need for electrical insulation, or for running the device in its real operating environment where there should be no access to debug ports, etc. In this section you will find information on how to customize your applications to reroute C-RUN raw messages to the desired communications channel so that they can be captured during the field testing for post-mortem analysis.

Note

In this guide, we will not offer any source code that relies on hardware-specific communication peripherals. It is assumed that the Hardware Abstraction Layer (HAL) in the application has been correctly initialized and it is ready for operation, providing serial transmission support through a function such as serial_send(channel, unsigned char). Ultimately serial_send() can be replaced by an equivalent function for writing C-RUN raw messages to any suitable media (e.g., SPI, I2C, RAM, Flash, etc.).

Procedure

  1. Add the $EW_DIR$/<target>/src/lib/crun/ReportCheckFailedStdout.c source file to your project.

  2. Open ReportCheckFailedStdout.c.

On the editor window tab you might see [Read-Only] (or [RO]). This indicates that the file was added directly from the IAR Embedded Workbench installation directory, which is write-protected. Leave this file unchanged for future reference.

  1. Choose FileSave As.

  2. A message is displayed asking "The file is read-only. Would you like to remove the read-only attribute?". Click No, navigate to the project's folder and save a copy of the file there.

Now, [Read-Only] (or [RO]) should not be visible on the editor tab.

  1. In the function __iar_ReportCheckFailedStdout(), comment out the call to __write() and insert the following code:
  //__write(_LLIO_STDOUT, (unsigned char const *)buf, (size_t)(b - buf));
  for (size_t i = 0; i < (size_t)(b - buf); i++)
  {
    serial_send(USART7, (unsigned char)buf[i]);
  }
  1. Choose ProjectOptionsLinkerExtra Options and use this command line option:

image

--redirect __iar_ReportCheckFailed=__iar_ReportCheckFailedStdout

Note

Run the board in stand-alone mode

  1. Connect the Debug probe to the target.
  2. In the IDE, choose ProjectDownloadDownload Active Application to flash the device with the the application.
  3. Power off and disconnect the debug probe from the board.
  4. Launch a Virtual Terminal Emulator (such as Tera Term VT) and connect it to the target board's serial port.
  5. Power up the board and verify that the C-RUN raw messages are being displayed in your Virtual Terminal Emulator.

image

  1. Save the collected CRUN_ERROR messages to a text file (e.g., field-tests-with-crun.txt).

Filtering the collected messages

In possession of the C-RUN raw messages collected from the field, feed it back to C-RUN itself using cspybat. The cspybat utility provides the --rtc_raw_to_txt option for converting the raw messages to human-readable text.

  1. Append the --rtc_raw_to_txt="/path/to/field-tests-with-crun.txt" to the project's settings/<project>.<cfg>.general.xcl.

  2. Run cspybat:

settings/<project>.<cfg>.cspy.bat
Output example (click to expand)
C:\project\settings>"C:\IAR\EW\ARM\9.50.2\common\bin\cspybat"
-f "C:\project\settings\project.Debug.general.xcl"
--backend -f "C:\project\settings\project.Debug.driver.xcl"

    IAR C-SPY Command Line Utility V9.3.2.391
    Copyright 2000-2023 IAR Systems AB.

crun_fail Signed integer overflow
-- Result is greater than the largest representable number:
--   1 (0x1) + 2147483647 (0x7fffffff).
crun_fail Integer conversion failure
-- Conversion changes the value from -2147483648 (0x80000000)
-- to                                 2147483648 (0x80000000).

Note

Call Stack Information is not provided in this mode.

Summary

C-RUN is a robust runtime analysis add-on for IAR Embedded Workbench, designed to significantly improve your field testing. Interested in integrating C-RUN into your projects? Request a quote to find the licensing option that best fits your needs.

For comprehensive details on C-RUN, please refer to the C-RUN runtime error checking section in the C-SPY Debugging Guide included with your IAR product.

Follow us on GitHub to get updates about tutorials like this and more.

Issues

For technical support contact IAR Customer Support.

For questions or suggestions related to this tutorial: try the wiki or check earlier issues. If those don't help, create a new issue with detailed information.