Skip to content

Commit

Permalink
[fault] Use Build ID instead of CRC32 hash
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Jun 6, 2019
1 parent 729ae1f commit a607613
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 47 deletions.
9 changes: 4 additions & 5 deletions examples/nucleo_f103rb/hard_fault/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ main()
if (FaultReporter::hasReport())
{
MODM_LOG_ERROR << "\n\nHardFault! Copy the data into a 'coredump.txt' file, ";
MODM_LOG_ERROR << "then execute 'scons postmortem firmware=";
MODM_LOG_ERROR << modm::hex << FaultReporter::firmware() << "'.\n\n";
for (const uint8_t data : FaultReporter())
{
MODM_LOG_ERROR << "then execute\n\n\tscons postmortem firmware=" << modm::hex;
for (const auto data : FaultReporter::buildId()) MODM_LOG_ERROR << data;
MODM_LOG_ERROR << "\n\n";
for (const auto data : FaultReporter())
MODM_LOG_ERROR << modm::hex << data << modm::flush;
}
MODM_LOG_ERROR << "\n\n\n" << modm::flush;
FaultReporter::clearAndReboot();
}
Expand Down
7 changes: 4 additions & 3 deletions examples/stm32f072_discovery/hard_fault/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ main()
if (FaultReporter::hasReport())
{
MODM_LOG_ERROR << "\n\nHardFault! Copy the data into a 'coredump.txt' file, ";
MODM_LOG_ERROR << "then execute 'scons postmortem firmware=";
MODM_LOG_ERROR << modm::hex << FaultReporter::firmware() << "'.\n\n";
for (const uint8_t data : FaultReporter())
MODM_LOG_ERROR << "then execute\n\n\tscons postmortem firmware=" << modm::hex;
for (const auto data : FaultReporter::buildId()) MODM_LOG_ERROR << data;
MODM_LOG_ERROR << "\n\n";
for (const auto data : FaultReporter())
MODM_LOG_ERROR << modm::hex << data << modm::flush;
MODM_LOG_ERROR << "\n\n\n" << modm::flush;
FaultReporter::clearAndReboot();
Expand Down
9 changes: 4 additions & 5 deletions examples/stm32f469_discovery/hard_fault/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ main()
if (FaultReporter::hasReport())
{
MODM_LOG_ERROR << "\n\nHardFault! Copy the data into a 'coredump.txt' file, ";
MODM_LOG_ERROR << "then execute 'scons postmortem firmware=";
MODM_LOG_ERROR << modm::hex << FaultReporter::firmware() << "'.\n\n";
for (const uint8_t data : FaultReporter())
{
MODM_LOG_ERROR << "then execute\n\n\tscons postmortem firmware=" << modm::hex;
for (const auto data : FaultReporter::buildId()) MODM_LOG_ERROR << data;
MODM_LOG_ERROR << "\n\n";
for (const auto data : FaultReporter())
MODM_LOG_ERROR << modm::hex << data << modm::flush;
}
MODM_LOG_ERROR << "\n\n\n" << modm::flush;
FaultReporter::clearAndReboot();
}
Expand Down
5 changes: 3 additions & 2 deletions src/modm/platform/fault/crashcatcher/fault.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#pragma once
#include "fault_storage.hpp"
#include <modm/architecture/interface/build_id.hpp>

/**
* Called first after a HardFault occurred.
Expand Down Expand Up @@ -44,8 +45,8 @@ class FaultReporter

/// @returns report size > 0
static inline bool hasReport() { return begin() != end(); }
/// @returns a 32-bit hash of the firmware for identification
static inline uint32_t firmware() { return FaultStorage::firmwareHash(); }
/// @returns a 20-bytes SHA1 of the firmware for identification
static inline const std::array<uint8_t, 20>& buildId() { return modm::build_id(); }
/// Clears the report
static inline void clear() { FaultStorage::closeRead(); }
/// Clears the report and reboots the device
Expand Down
10 changes: 0 additions & 10 deletions src/modm/platform/fault/crashcatcher/fault_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

#include "fault_storage.hpp"
#include <modm/architecture/utils.hpp>
#include <modm/math/utils/crc32.hpp>

typedef struct
{
Expand All @@ -22,8 +21,6 @@ typedef struct

extern "C" const table_pool_t __table_heap_start[];
extern "C" const table_pool_t __table_heap_end[];
extern "C" const uint8_t __rom_start[];
extern "C" const uint8_t __rom_end[];

static constexpr uint32_t magic_start = 0xBAADC0DE;
static constexpr uint32_t magic_end = 0xC0FFEEEE;
Expand Down Expand Up @@ -76,13 +73,6 @@ FaultStorage::closeRead()
marker_end_ptr = nullptr;
}

uint32_t
FaultStorage::firmwareHash()
{
// Compute the CRC32 of the loaded binary image
return modm::math::crc32(__rom_start, __rom_end - __rom_start);
}

void
FaultStorage::openWrite()
{
Expand Down
1 change: 0 additions & 1 deletion src/modm/platform/fault/crashcatcher/fault_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ class FaultStorage
public:
static size_t openRead();
static void closeRead();
static uint32_t firmwareHash();

class Iterator
{
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/fault/crashcatcher/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def prepare(module, options):
enumeration=["core", "core+stack", "core+stack+data"],
default="core+stack+data"))

module.depends(":crashcatcher", ":cmsis:device", ":math:utils")
module.depends(":crashcatcher", ":cmsis:device", ":architecture:build_id")

return True

Expand Down
30 changes: 20 additions & 10 deletions src/modm/platform/fault/crashcatcher/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ int main()
if (FaultReporter::hasReport()) // Check first after boot
{
Application::partialInitialize(); // Initialize only the necessary
uint32_t id = FaultReporter::firmware();
reportBegin(id); // start your report with the firmware hash
reportBegin();
for (const uint8_t data : FaultReporter::buildId())
reportBuildId(data); // send each byte of Build ID
for (const uint8_t data : FaultReporter())
reportData(data); // send each byte of data
reportEnd(); // end the report
Expand Down Expand Up @@ -108,7 +109,7 @@ int main()
if (faultReport and applicationReady)
{
// Still valid AFTER clear, but BEFORE reboot
const uint32_t id = FaultReporter::firmware();
const auto id = FaultReporter::buildId();
auto begin = FaultReporter::begin();
auto end = FaultReporter::end();
//
Expand All @@ -133,8 +134,17 @@ arm-none-eabi-gdb -tui executable.elf -ex "set target-charset ASCII" \
-ex "target remote | CrashDebug --elf executable.elf --dump coredump.txt"
```

Note that the firmware identifier is the CRC32 hash of the ROM section, this can
help you find the right ELF file.
Note that the `FaultReporter::buildId()` contains the GNU Build ID, which can
help you find the right ELF file:

```
arm-none-eabi-readelf -n executable.elf
Displaying notes found in: .build_id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: 59f08f7a37a7340799d9dba6b0c092bc3c9515c5
```


### Post-Mortem Debugging with SCons
Expand All @@ -143,14 +153,14 @@ The `:build:scons` module provides a few helper methods for working with fault
reports. You still need to copy the coredump data manually, however, the firmware
selection is automated.

The SCons build system will automatically cache both the ELF and binary files
for the firmware ID for every firmware upload (using `scons artifact`).
When a fault is reported, you can tell SCons the firmware hash and it will use
The SCons build system will automatically cache the ELF file for the build id for
every firmware upload (using `scons artifact`).
When a fault is reported, you can tell SCons the firmware build id and it will use
the corresponding ELF file automatically.

```sh
# Copy data into coredump.txt
touch coredump.txt
# Start postmortem debugging of {hash}
scons postmortem firmware={hash}
# Start postmortem debugging of executable with this build id
scons postmortem firmware=59f08f7a37a7340799d9dba6b0c092bc3c9515c5
```
25 changes: 15 additions & 10 deletions tools/build_script_generator/scons/site_tools/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,28 @@
import shutil
from SCons.Script import *
import subprocess
import binascii
from elftools.elf.elffile import ELFFile

def run_store_artifact(target, source, env):
artifactpath = os.path.join(env["CONFIG_BUILD_BASE"], "artifacts")
try:
os.makedirs(artifactpath)
except:
pass
source = str(source[0])
binary = os.path.splitext(source)[0]+".bin"
subprocess.call(env.subst("$OBJCOPY -O binary {} {}".format(source, binary)), shell=True)
with open(binary, "rb") as binfile:
firmware = binascii.crc32(binfile.read()) & 0xFFFFFFFF

artifact = os.path.join(artifactpath, "{:08X}.elf".format(firmware))
shutil.copy2(source, artifact)
shutil.copy2(binary, os.path.splitext(artifact)[0]+".bin")

with open(source[0].path, "rb") as src:
elffile = ELFFile(src)
build_id = elffile.get_section_by_name(".build_id")
if build_id is not None:
for note in build_id.iter_notes():
if note['n_type'] == "NT_GNU_BUILD_ID":
build_id = note['n_desc']

if build_id is not None:
artifact = os.path.join(artifactpath, "{}.elf".format(build_id.lower()))
shutil.copy2(source[0].path, artifact)
else:
print("Unable to find Build ID for '{}'!".format(source[0].path))
return 0

def store_artifact(env, source, alias="store_artifact"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def run_post_mortem_gdb(target, source, env):
print("\n> Using the newest firmware may be inaccurate!\n"
"> Use 'firmware={hash}' argument to specify a specific firmware.\n")
else:
artifact = artifact.lower()
artifactpath = os.path.join(env["CONFIG_BUILD_BASE"], "artifacts", "{}.elf".format(artifact))
if os.path.isfile(artifactpath):
source = artifactpath
Expand Down

0 comments on commit a607613

Please sign in to comment.