Skip to main content

pygbl

A parser for the EBL and GBL (v3 and v4) firmware image formats used by the Silicon Labs Gecko bootloader.

Images are parsed into structured tags and round-trip byte-for-byte, with anything following the end tag handed back separately rather than folded into the image.

Installation

pip install pygbl

The base install is pure Python and covers parsing, serializing, building images from ELFs, and LZMA. Signing, encryption and LZ4 need optional dependencies:

pip install pygbl[crypto]  # signing and encryption
pip install pygbl[lz4]     # LZ4 compression
pip install pygbl[all]

Calling those features without their dependency raises MissingDependencyError.

Usage

Parse an image and inspect its tags:

import pathlib

from pygbl import GBL3ApplicationInfo, parse_firmware_image

data = pathlib.Path("ncp-uart-hw.gbl").read_bytes()
image = parse_firmware_image(data)

for tag in image.tags:
    print(tag)

print(image.get_first_tag(GBL3ApplicationInfo).version)
print(image.get_metadata())  # opaque bytes, the schema is vendor defined

serialize pads up to a word boundary, as commander does. parse_firmware_image discards anything after the end tag; deserialize hands it back:

image, trailing = GBL3Image.deserialize(data)

assert image.serialize(block_size=1) + trailing == data

Modify an image. Tags are frozen dataclasses, so dataclasses.replace works, and regenerate_crc fixes up the end tag afterwards:

import dataclasses

from pygbl import GBL3End, GBL3Metadata

modified = dataclasses.replace(
    image,
    tags=[t for t in image.tags if not isinstance(t, GBL3End)]
    + [GBL3Metadata(metadata=b'{"fw_type": "zigbee_ncp"}')],
).regenerate_crc()

Compress, encrypt and sign, in the order the bootloader expects:

from cryptography.hazmat.primitives.serialization import load_pem_private_key

from pygbl import GBL3Compression

private_key = load_pem_private_key(
    pathlib.Path("vendor_sign.key").read_bytes(), password=None
)
key = bytes.fromhex("7F8FE53979B31BC556FCB131AFF42414")

sealed = image.compress(GBL3Compression.LZMA).encrypt(key).sign(private_key)
pathlib.Path("signed.gbl").write_bytes(sealed.serialize())

The bootloader decompresses into fixed buffers, so compress uses the only LZMA parameters it can accept. Overriding them past what it can allocate raises ValueError.

And unwrap it again:

assert sealed.verify_signature(private_key.public_key())
assert sealed.decrypt(key).decompress().serialize() == image.serialize()

Building images from an ELF

Images can be built straight from a linked ELF, without commander. Program data comes from the loadable segments (keyed by physical address, since initialized data is stored in flash but linked at its RAM address) and the application info tag is read from the SDK's application_properties_t struct:

from pygbl import build_application_gbl3, build_bootloader_gbl3

with open("zigbee_ncp.out", "rb") as f:
    image = build_application_gbl3(f, metadata=b'{"fw_type": "zigbee_ncp"}')

with open("bootloader.out", "rb") as f:
    bootloader = build_bootloader_gbl3(f)

GBLv4

Series 3 parts use GBLv4, a different format that nests tags inside a signed manifest and can bundle several updates in one file.

from pygbl import GBL4Image, GBL4MemorySectionInfo, GBL4UpdateMemorySection

data = pathlib.Path("light-simg301.gbl4").read_bytes()
image, trailing = GBL4Image.deserialize(data)

assert image.serialize() + trailing == data

# `get_tags` searches the whole tree, at any depth
for update in image.get_tags(GBL4UpdateMemorySection):
    print(f"{update.target_address:#010x} {update.plain_image_size} bytes")

for info in image.get_tags(GBL4MemorySectionInfo):
    print(info.compression_scheme, info.encryption_scheme, info.nonce.hex())

Reading and writing are supported; building a v4 image from an ELF is not, the ELF helpers are GBLv3 only.

EBL

EBL images, used by older EM3xx parts, work the same way:

from pygbl import EBLEraseProgram, parse_firmware_image

image = parse_firmware_image(pathlib.Path("ncp-uart-sw.ebl").read_bytes())

for tag in image.get_tags(EBLEraseProgram):
    print(f"{tag.address:#010x} {len(tag.data)} bytes")

Bootloader and application images

A GBL can contain a bootloader, an application, or both. Combined images can be split apart and recombined, which is useful because some bootloaders cannot flash a combined image in one pass:

bootloader, application = combined.split_bootloader_app()
recombined = application.combine_bootloader_app(bootloader)

Release files for pygbl 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygbl 1.2.0
File Size Uploaded
pygbl-1.2.0.tar.gz 8.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pygbl 1.2.0
File Interpreter ABI Platform
pygbl-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 8.0 MB

Release files / pygbl-1.2.0.tar.gz

Download URL pygbl-1.2.0.tar.gz
Size 8.0 MB
Tags Source
SHA-256 checksum
How to use checksums
fd3ec9afbb4fffaae602d3ac2401da378f1868eb53f7dc22203f93dea6f5d3b5
BLAKE2b-256 checksum
How to use checksums
9949b15b3fdbd1e3249db5c1294285654c859c1d87540927ba34de64ceb73c98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.

Transparency log

Release files / pygbl-1.2.0-py3-none-any.whl

Download URL pygbl-1.2.0-py3-none-any.whl
Size 29.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a3fe099fb5ecda44e650f589a6c4b51bb7c8d98f15e97f779ad6b634b9c0642b
BLAKE2b-256 checksum
How to use checksums
4086180182ccb6f1158535b158eb44f4c99ff09264cbb9746822f242a3cb9dc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page