iter
iter

Reputation: 4313

OpenOCD exit on breakpoint

I'm developing an application on an STM32F042. I drive everything from a makefile, including my unit tests. I use OpenOCD and ST-LINK to flash the target. My unit tests run on the host and on the target. The host unit test driver returns 0 from main() on success and non-zero on failure, so the makefile knows if the tests pass. The makefile flashes and starts tests on the target, but doesn't know if they succeed or fail. The embedded test application turns on a red LED for fail and green for pass, so I know--now I want to automate this step.

I want to set two breakpoints in the code, one in the failure handler and one at the end of main, and tell OpenOCD to exit with zero or non-zero status if it hits one or the other breakpoint.

So my question boils down to two specific ones:

  1. To set a breakpoint, I need to know the PC value at a specific line of code. How do I get that value from the arm-gcc toolchain?

  2. Can I configure OpenOCD to exit on specific breakpoints, and with specific status?

Upvotes: 3

Views: 1113

Answers (1)

iter
iter

Reputation: 4313

Here's what I ended up with. For each target unit test, I start an OpenOCD server and connect to it with gdb. Gdb runs a script that sets two breakpoints, one for success, one for failure. If it hits either breakpoint, it shuts down the OCD server and exits with a code that communicates success and failure to the shell. To run the same tests on the host, I simply compile them as regular executables.

Makefile:

# target unit test binaries
foo_tests.elf bar_tests.elf baz_tests.elf bop_tests.elf: unit_test_runner.ao

# disable optimization for target unit test driver to avoid optimizing
# away functions that serve as breakpoint labels
unit_test_runner.ao: CFLAGS += -O0 -g

# link target unit test binaries for semihosting
%_tests.elf: ARM_LDLIBS += -specs=rdimon.specs -lrdimon

# host unit test binaries
foo_tests bar_time_tests baz_tests bop_tests: unit_test_runner.o

# run target unit test binaries through gdb and OpenOCD; redirecting stderr
# leaves printf output from `assert()' clearly visible on the console
%.tut: %.elf
    openocd -f interface/stlink-v2-1.cfg -f target/stm32f0x.cfg 2> [email protected] &
    gdb-multiarc -batch-silent -x tut.gdb $< 2> [email protected]

# run host binary
%.run: %
    ./$*

tests: foo_tests.run bar_time_tests.run baz_tests.run bop_tests.run \
       foo_tests.tut bar_time_tests.tut baz_tests.tut bop_tests.tut

tut.gdb:

target remote localhost:3333

monitor arm semihosting enable   # let assert()'s printf() through
monitor reset halt
load
monitor reset init

break success                    # set breakpoint on function `sucess()'
commands                         # on hitting this bp, execute the following:
monitor shutdown                 # shutdown OpenOCD server
quit 0                           # exit GDB with success code
end

break failure                    # set breakpoint on function `sucess()'
commands
monitor shutdown
quit 1                           # exit GDB with failure code
end

continue

unit_test_runner.c:

#include <stdlib.h>

/* These two functions serve as labels where gdb can place
   breakpoints. */
void success() {}
void failure() {}

/* Implementation detail for `assert()' macro */
void assertion_failure(const char *file,
                       int line,
                       const char *function,
                       const char *expression)
{
  printf("assertion failure in %s:%d (%s): `%s'\n",
         file, line, function, expression);
  failure();
  exit(1);
}

/* This function is necessary for ARM semihosting */
extern void initialise_monitor_handles(void);

int main(int argc, char* argv[])
{
#ifdef __arm__
  initialise_monitor_handles();
#endif

  tests();  /* client code implements this function */

  success();
  return 0;
}

Upvotes: 3

Related Questions