[cper-lib] Implement CperDecoder and refactor safe accessors

Introduces a `CperDecoder` library to safely parse UEFI CPER records and
refactors the codebase to centralize safe memory access patterns. This ensures
full compatibility with UBSan and strict alignment toolchains.

Key Changes:
- CperDecoder: Added a new `uefi::cper::CperDecoder` class that provides a
robust interface for parsing CPER records. It performs signature validation,
boundary checks for section descriptors, and provides safe access to section
bodies via std::span.
- Centralized getField: Moved the `getField<T>` helper to `include/cper.hpp`.
This allows the decoder and unit tests to share a single implementation for
safely reading members of unaligned packed structs using memcpy.
- Hardened gmtime_r: Added explicit return value checks for `gmtime_r` calls,
throwing `std::runtime_error` on failure to ensure reliability when processing
timestamps.
- Refactored Tests: Updated `cper_encoder_test.cpp` to use the new
`CperDecoder` for its assertions. This simplifies the test logic and verifies
the decoder's functionality through round-trip testing.
- New Test Coverage: Added unit tests for the decoder to verify handling of
truncated headers, invalid signatures, and malformed section counts.

Tested:
- All 9 unit tests passed via Meson inside the gbmc_dev container.
- All tests passed via Bazel/Blaze using the Google cc_toolchain.
- Built an experimental cli tool on google3 using the decoder on AsicCper logs
from sdhb and compared the output to the CFA

Google-Bug-Id: 505395424
Change-Id: I02a385a591f7ccee8fc9e3e28ee4e79755170656
Signed-off-by: Aryk Ledet <arykledet@google.com>
6 files changed
tree: 2b9292b0af3a7729266fe3e3dcaa43574f59aa9d
  1. include/
  2. test/
  3. .clang-format
  4. LICENSE
  5. meson.build
  6. meson.options
  7. README.md
README.md

cper-lib

This is a header-only library which provides a generic interface for users to write application specific UEFI CPER log encoders.

How to use this library

The UEFI specification for CPER logs allows for many combinations of Record Header and Section Descriptor properties based on the application. However, the underlying data structure does not change from application to application. To make it easier for gBMC applications to log faults in the CPER format the user only needs to specify the type of Record and Section type(s) that the encoder will need to create.

When developing and testing your application specific encoders, you will need to install this library into your development container.

Below is some pseudo code of how a user would setup their application specific CPER encoder which takes in char array types.

class MyCperEncoder : public CperEncoder<char>
{
    RecordHeader createRecordHeader(...) override
    {...}

    SectionDescriptor createSectionDescriptor(...) override
    {
        if (sectionType == kPlatformMemory)
        {
            return createPlatformMemoryDescriptor();
        }
        else if (sectionType == kOemSection)
        {
            return createOemDescriptor();
        }
        ...
    }

    SectionDescriptor createPlatformMemoryDescriptor()
    {...}

    SectionDescriptor createOemDescriptor()
    {...}
}

To install

meson setup -C builddir
meson install -C builddir

To run unit tests

meson test -C builddir