| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- from dataclasses import dataclass, field
- from typing import Dict, Optional
- import gdb
- # Must match FuriHalRtcRegisterVersion index in FuriHalRtcRegister enum
- RTC_BACKUP_VERSION_REGISTER_IDX = 0x2
- RTC_BASE = 0x40002800
- RTC_BACKUP_BASE = RTC_BASE + 0x50
- VERSION_REGISTER_ADDRESS = RTC_BACKUP_BASE + RTC_BACKUP_VERSION_REGISTER_IDX * 4
- VERSION_STRUCT_MAGIC = 0xBE40
- @dataclass
- class VersionData:
- git_hash: str
- git_branch: str
- build_date: str
- version: str
- target: int
- build_is_dirty: bool
- extra: Optional[Dict[str, str]] = field(default_factory=dict)
- class VersionLoader:
- def __init__(self, version_ptr):
- self.version_ptr = version_ptr
- self._cstr_type = gdb.lookup_type("char").pointer()
- self._uint_type = gdb.lookup_type("unsigned int")
- version_signature = version_ptr.dereference().cast(self._uint_type)
- is_versioned = (version_signature & (0xFFFF)) == VERSION_STRUCT_MAGIC
- if is_versioned:
- self._version_data = self.load_versioned(
- major=version_signature >> 16 & 0xFF,
- minor=version_signature >> 24 & 0xFF,
- )
- else:
- self._version_data = self.load_unversioned()
- @property
- def version(self) -> VersionData:
- return self._version_data
- def load_versioned(self, major, minor):
- if major != 1:
- raise ValueError("Unsupported version struct major version")
- # Struct version 1.0
- extra_data = int(self.version_ptr[5].cast(self._uint_type))
- return VersionData(
- git_hash=self.version_ptr[1].cast(self._cstr_type).string(),
- git_branch=self.version_ptr[2].cast(self._cstr_type).string(),
- build_date=self.version_ptr[3].cast(self._cstr_type).string(),
- version=self.version_ptr[4].cast(self._cstr_type).string(),
- target=extra_data & 0xF,
- build_is_dirty=bool((extra_data >> 8) & 0xF),
- )
- def load_unversioned(self):
- """Parse an early version of the version struct."""
- extra_data = int(self.version_ptr[5].cast(self._uint_type))
- return VersionData(
- git_hash=self.version_ptr[0].cast(self._cstr_type).string(),
- git_branch=self.version_ptr[1].cast(self._cstr_type).string(),
- # branch number is #2, but we don't care about it
- build_date=self.version_ptr[3].cast(self._cstr_type).string(),
- version=self.version_ptr[4].cast(self._cstr_type).string(),
- target=extra_data & 0xF,
- build_is_dirty=bool((extra_data >> 8) & 0xF),
- )
- class FlipperFwVersion(gdb.Command):
- """Print the version of Flipper's firmware."""
- def __init__(self):
- super(FlipperFwVersion, self).__init__("fw-version", gdb.COMMAND_USER)
- def invoke(self, arg, from_tty):
- void_ptr_type = gdb.lookup_type("void").pointer().pointer()
- version_ptr_ptr = gdb.Value(VERSION_REGISTER_ADDRESS).cast(void_ptr_type)
- if not version_ptr_ptr:
- print("RTC version register is NULL")
- return
- version_ptr = version_ptr_ptr.dereference()
- if not version_ptr:
- print("Pointer to version struct is NULL")
- return
- version_struct = version_ptr.cast(void_ptr_type)
- v = VersionLoader(version_struct)
- print("Firmware version on attached Flipper:")
- print(f"\tVersion: {v.version.version}")
- print(f"\tBuilt on: {v.version.build_date}")
- print(f"\tGit branch: {v.version.git_branch}")
- print(f"\tGit commit: {v.version.git_hash}")
- print(f"\tDirty: {v.version.build_is_dirty}")
- print(f"\tHW Target: {v.version.target}")
- FlipperFwVersion()
|