Skip to content

ihex.py

ofrak.core.ihex

Ihex (Program) dataclass

Intel HEX is a binary blob packaging format encoded in ASCII. It splits binary data into records, which are lines of ASCII representing in hex the byte count, address, type, checksums of stored data. It is typically used for flashing firmware.

printf "Hello world!" | bin2hex.py -

:0C00000048656C6C6F20776F726C642197 :00000001FF

IhexAnalyzer (Analyzer)

Extracts and analyzes Intel HEX program metadata including the starting and ending addresses of all segments, individual segment sizes, the overall address range covered by the program, and any gaps between segments. Intel HEX files can have non-contiguous address ranges. Use to understand the memory layout described by an Intel HEX file, identify which memory regions contain data, find gaps that will be filled with padding, or determine the total memory space required. Useful before unpacking or when planning memory modifications.

analyze(self, resource, config=None) async

Analyze a resource for to extract specific ResourceAttributes.

Users should not call this method directly; rather, they should run Resource.run or Resource.analyze.

Parameters:

Name Type Description Default
resource Resource

The resource that is being analyzed

required
config None

Optional config for analyzing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None

Returns:

Type Description
Ihex

The analysis results

Source code in ofrak/core/ihex.py
async def analyze(self, resource: Resource, config: None = None) -> Ihex:
    ihex, _ = _binfile_analysis(await resource.get_data(), self)
    return ihex

IhexIdentifier (Identifier)

Regex-test the entire resource to check if it satisfies intel-hex formatting.

This identifier tags any Resource whose first two lines match the ihex format.

identify(self, resource, config=None) async

Perform identification on the given resource.

Users should not call this method directly; rather, they should run Resource.identify.

Parameters:

Name Type Description Default
resource Resource required
config

Optional config for identifying. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None
Source code in ofrak/core/ihex.py
async def identify(self, resource: Resource, config=None) -> None:
    matched_ihex = await resource.search_data(self._INTEL_HEX_PATTERN, 0, 0x2000, max_matches=1)
    if matched_ihex:
        offset, bytes = matched_ihex[0]
        # Only tag if pattern starts at offset 0 of resource
        if offset == 0:
            resource.add_tag(Ihex)

IhexPacker (Packer)

Pack the segments of an Intel HEX program back into a binary blob. Recomputes segment size and program address range based on the actual segments at the time of packing.

pack(self, resource, config=None) async

Pack the given resource.

Users should not call this method directly; rather, they should run Resource.run or Resource.pack.

Parameters:

Name Type Description Default
resource Resource required
config

Optional config for packing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None
Source code in ofrak/core/ihex.py
async def pack(self, resource: Resource, config=None) -> None:
    ihex = await resource.view_as(Ihex)
    binfile = BinFile()
    segments = await resource.get_children_as_view(
        CodeRegion, r_filter=ResourceFilter.with_tags(CodeRegion)
    )
    if len(list(segments)) == 0:  # probably means that the ihex was never unpacked
        raw_ihex = await resource.get_data()
        binfile.add_ihex(raw_ihex.decode("utf-8"))
    else:
        for segment_r in segments:
            seg_data = await segment_r.resource.get_data()
            binfile.add_binary(seg_data, segment_r.virtual_address)

    binfile.execution_start_address = ihex.start_addr
    new_data = binfile.as_ihex()
    if new_data.endswith("\n"):
        new_data = new_data[:-1]
    new_data = new_data.encode("utf-8")
    old_data_len = await resource.get_data_length()
    resource.queue_patch(Range(0, old_data_len), new_data)

IhexUnpacker (Unpacker)

Extracts individual memory segments from an Intel HEX program's binary representation, separating the continuous memory image into distinct addressable sections. Each segment corresponds to a contiguous region of memory defined in the original HEX file.

unpack(self, resource, config=None) async

Unpack the given resource.

Users should not call this method directly; rather, they should run Resource.run or Resource.unpack.

Parameters:

Name Type Description Default
resource Resource

The resource that is being unpacked

required
config

Optional config for unpacking. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run.

None
Source code in ofrak/core/ihex.py
async def unpack(self, resource: Resource, config=None):
    _, binfile = _binfile_analysis(await resource.get_data(), self)

    for segment in binfile.segments:
        segment_data = bytes(binfile.as_binary())[
            segment.minimum_address
            - binfile.minimum_address : segment.maximum_address
            - binfile.minimum_address
        ]
        await resource.create_child_from_view(
            CodeRegion(
                segment.minimum_address, segment.maximum_address - segment.minimum_address
            ),
            data=segment_data,
        )