We are now going to create a simple application that crashes under specific conditions:
- In your working directory, ~/test, create a subdirectory called loop.
- Use your favorite text editor to create a loop.cpp file in the loop subdirectory.
- Let's put some code into the loop.cpp file. We start with includes:
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
- Now, we define three functions that our program will consist of. The first one is runner:
void runner(std::chrono::milliseconds limit,
std::function<void(int)> fn,
int value) {
auto start = std::chrono::system_clock::now();
fn(value);
auto end = std::chrono::system_clock::now();
std::chrono::milliseconds delta =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if (delta > limit) {
throw std::runtime_error("Time limit exceeded");
}
}
- The second function is delay_ms:
void delay_ms(int count) {
for (int i = 0; i < count; i++) {
std::this_thread::sleep_for(std::chrono::microseconds(1050));
}
}
- And finally, we add the entry-point function, main:
int main() {
int max_delay = 10;
for (int i = 0; i < max_delay; i++) {
runner(std::chrono::milliseconds(max_delay), delay_ms, i);
}
return 0;
}
- Create a file called CMakeLists.txt in the loop subdirectory with the following content:
cmake_minimum_required(VERSION 3.5.1)
project(loop)
add_executable(loop loop.cpp)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_CXX_FLAGS "-g --std=c++11")
set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
- Now, switch to the build system terminal and change the current directory to /mnt/loop by running the following command.
$ cd /mnt/loop
- Build the application as follows:
$ cmake . && make
- Switch back to your native environment, find the loop output file in the loop subdirectory, and copy it over ssh to the target system. Use the user account. Switch to the target system terminal. Log in using the user credentials if needed. Now, run the loop executable binary using gdb:
$ gdb ./loop
- The debugger has been started and shows the command-line prompt (gdb). To run the application, type the run command:
(gdb) run
- You can see that the application terminated abnormally due to the runtime exception. The exception message, Time limit exceeded, gives us a clue, but does not indicate under what specific conditions it happened. Let's try to establish this. Firstly, let's check the stack trace of the crashing application:
(gdb) bt
- This shows seven stack frames from the top-level function, main, down to the library function, __GI_abort, which actually terminates the application. As we can see, only frames 7 and 6 belong to our application, since only they are defined in loop.cpp. Let's take a close look at frame 6, since this is the function that throws the exception:
(gdb) frame 6
- Run the list command to see the nearby code:
(gdb) list
- As we can see, the exception is thrown if the value of the delta variable exceeds the value of the limit variable. But what are what are these values?. These are the values of variable ‘delta’ and ‘limit Run the info locals command to figure this out:
(gdb) info locals
- We cannot see the value of the limit variable here. Use the info args command to see it:
(gdb) info args
- Now, we can see that the limit is 10, and the delta 11. The crash happens when the function is called with the fn parameter set to the delay_ms function and the value of the value parameter set to 7.