def test_parse_maintenance_info_sections_with_file( gdb_base_fixture, maintenance_info_sections_fixture, fake_elf ): from memfault_gdb import parse_maintenance_info_sections, Section fn, sections = parse_maintenance_info_sections(maintenance_info_sections_fixture) assert fn == fake_elf.name assert len(sections) == 35 assert sections[0] == Section(0x26000, 0x6B784 - 0x26000, ".text", read_only=True) assert sections[20] == Section(0x20005C30, 0x2000B850 - 0x20005C30, ".bss", read_only=False)
def test_armv7_get_used_ram_base_addresses(gdb_base_fixture): from memfault_gdb import Section, armv7_get_used_ram_base_addresses sections = ( Section(0x30000000, 10, "", read_only=True), Section(0x70000000, 10, "", read_only=True), Section(0x90000000, 10, "", read_only=True), Section(0x00000000, 10, "", read_only=True), Section(0xE0000000, 10, "", read_only=True), ) assert {0x20000000, 0x60000000, 0x80000000} == armv7_get_used_ram_base_addresses(sections)
def test_parse_maintenance_info_sections_with_file(): with mock.patch.dict("sys.modules", gdb=MagicMock()): from memfault_gdb import parse_maintenance_info_sections, Section fixture = """Exec file: `/Users/mthe/memfault/memfault/sdk/embedded/platforms/nrf5/memfault_test_app/build/mf_test_app_nrf52840_s140.out', file type elf32-littlearm. [0] 0x26000->0x6b784 at 0x00006000: .text ALLOC LOAD READONLY CODE HAS_CONTENTS [1] 0x2003d800->0x2003e878 at 0x0005d800: .rtt ALLOC [2] 0x6b784->0x6b7a8 at 0x0004b784: .gnu_build_id ALLOC LOAD READONLY DATA HAS_CONTENTS [3] 0x2003fe00->0x2003fe14 at 0x0005fe00: .fw_install_info ALLOC [4] 0x2003ff00->0x20040000 at 0x0005ff00: .noinit ALLOC [5] 0x6b7a8->0x6b7c8 at 0x0004b7a8: .sdh_soc_observers ALLOC LOAD READONLY DATA HAS_CONTENTS [6] 0x6b7c8->0x6b850 at 0x0004b7c8: .sdh_ble_observers ALLOC LOAD READONLY DATA HAS_CONTENTS [7] 0x6b850->0x6b860 at 0x0004b850: .sdh_stack_observers ALLOC LOAD READONLY DATA HAS_CONTENTS [8] 0x6b860->0x6b868 at 0x0004b860: .sdh_req_observers ALLOC LOAD READONLY DATA HAS_CONTENTS [9] 0x6b868->0x6b880 at 0x0004b868: .sdh_state_observers ALLOC LOAD READONLY DATA HAS_CONTENTS [10] 0x6b880->0x6b8a8 at 0x0004b880: .nrf_queue ALLOC LOAD READONLY DATA HAS_CONTENTS [11] 0x6b8a8->0x6b8d0 at 0x0004b8a8: .nrf_balloc ALLOC LOAD READONLY DATA HAS_CONTENTS [12] 0x6b8d0->0x6b8f8 at 0x0004b8d0: .cli_command ALLOC LOAD READONLY DATA HAS_CONTENTS [13] 0x6b8f8->0x6b908 at 0x0004b8f8: .crypto_data ALLOC LOAD READONLY DATA HAS_CONTENTS [14] 0x6b908->0x6b9e0 at 0x0004b908: .log_const_data ALLOC LOAD READONLY DATA HAS_CONTENTS [15] 0x6b9e0->0x6ba00 at 0x0004b9e0: .log_backends ALLOC LOAD READONLY DATA HAS_CONTENTS [16] 0x6ba00->0x6ba08 at 0x0004ba00: .ARM.exidx ALLOC LOAD READONLY DATA HAS_CONTENTS [17] 0x200057b8->0x20005bf0 at 0x000557b8: .data ALLOC LOAD DATA HAS_CONTENTS [18] 0x20005bf0->0x20005c04 at 0x00055bf0: .cli_sorted_cmd_ptrs ALLOC LOAD DATA HAS_CONTENTS [19] 0x20005c04->0x20005c2c at 0x00055c04: .fs_data ALLOC LOAD DATA HAS_CONTENTS [20] 0x20005c30->0x2000b850 at 0x00055c2c: .bss ALLOC [21] 0x2000b850->0x2000d850 at 0x00055c30: .heap READONLY HAS_CONTENTS [22] 0x2000b850->0x2000d850 at 0x00057c30: .stack_dummy READONLY HAS_CONTENTS [23] 0x0000->0x0030 at 0x00059c30: .ARM.attributes READONLY HAS_CONTENTS [24] 0x0000->0x00f4 at 0x00059c60: .comment READONLY HAS_CONTENTS [25] 0x0000->0xf3d30 at 0x00059d54: .debug_info READONLY HAS_CONTENTS [26] 0x0000->0x1eeec at 0x0014da84: .debug_abbrev READONLY HAS_CONTENTS [27] 0x0000->0x59416 at 0x0016c970: .debug_loc READONLY HAS_CONTENTS [28] 0x0000->0x2c10 at 0x001c5d88: .debug_aranges READONLY HAS_CONTENTS [29] 0x0000->0x121a8 at 0x001c8998: .debug_ranges READONLY HAS_CONTENTS [30] 0x0000->0x37f3a at 0x001dab40: .debug_macro READONLY HAS_CONTENTS [31] 0x0000->0x708cb at 0x00212a7a: .debug_line READONLY HAS_CONTENTS [32] 0x0000->0xcee28 at 0x00283345: .debug_str READONLY HAS_CONTENTS [33] 0x0000->0x91f0 at 0x00352170: .debug_frame READONLY HAS_CONTENTS [34] 0x0000->0x00df at 0x0035b360: .stabstr READONLY HAS_CONTENTS """ fn, sections = parse_maintenance_info_sections(fixture) assert ( fn == "/Users/mthe/memfault/memfault/sdk/embedded/platforms/nrf5/memfault_test_app/build/mf_test_app_nrf52840_s140.out" ) assert len(sections) == 35 assert sections[0] == Section(0x26000, 0x6B784 - 0x26000, ".text", read_only=True) assert sections[20] == Section(0x20005C30, 0x2000B850 - 0x20005C30, ".bss", read_only=False)
def test_armv7_get_used_ram_base_addresses(gdb_base_fixture): from memfault_gdb import ArmCortexMCoredumpArch, Section sections = ( Section(0x30000000, 10, "", read_only=True), Section(0x70000000, 10, "", read_only=True), Section(0x90000000, 10, "", read_only=True), Section(0x00000000, 10, "", read_only=True), Section(0xE0000000, 10, "", read_only=True), ) collection_size_arm = 1 * 1024 * 1024 # 1MB assert [ (0x20000000, collection_size_arm), (0x60000000, collection_size_arm), (0x80000000, collection_size_arm), ] == ArmCortexMCoredumpArch().guess_ram_regions(sections)
def test_armv7_get_used_ram_base_addresses(gdb_base_fixture): from memfault_gdb import Section, ArmCortexMCoredumpArch sections = ( Section(0x30000000, 10, "", read_only=True), Section(0x70000000, 10, "", read_only=True), Section(0x90000000, 10, "", read_only=True), Section(0x00000000, 10, "", read_only=True), Section(0xE0000000, 10, "", read_only=True), ) COLLECTION_SIZE_ARM = 1 * 1024 * 1024 # 1MB assert [ (0x20000000, COLLECTION_SIZE_ARM), (0x60000000, COLLECTION_SIZE_ARM), (0x80000000, COLLECTION_SIZE_ARM), ] == ArmCortexMCoredumpArch().guess_ram_regions(sections)
def test_coredump_writer(gdb_base_fixture, snapshot): from memfault_gdb import ArmCortexMCoredumpArch, MemfaultCoredumpWriter, Section arch = ArmCortexMCoredumpArch() cd_writer = MemfaultCoredumpWriter(arch) cd_writer.device_serial = "device_serial" cd_writer.firmware_version = "1.2.3" cd_writer.hardware_revision = "gdb-proto" cd_writer.trace_reason = 5 cd_writer.regs = [ { "r0": 4 * b"\x00", "r1": 4 * b"\x01", "r2": 4 * b"\x02", "r3": 4 * b"\x03", "r4": 4 * b"\x04", "r5": 4 * b"\x05", "r6": 4 * b"\x06", "r7": 4 * b"\x07", "r8": 4 * b"\x08", "r9": 4 * b"\x09", "r10": 4 * b"\x0A", "r11": 4 * b"\x0B", "r12": 4 * b"\x0C", "sp": 4 * b"\x0D", "lr": 4 * b"\x0E", "pc": 4 * b"\x0F", "xpsr": 4 * b"\x10", "msp": 4 * b"\x11", "psp": 4 * b"\x12", "primask": 4 * b"\x13", "control": 4 * b"\x14", }, ] section = Section(4, 32, ".test", "") section.data = b"hello world" cd_writer.add_section(section) f_out = BytesIO() cd_writer.write(f_out) f_out.seek(0) snapshot.assert_match(f_out.read().hex())
def test_coredump_writer(): with mock.patch.dict("sys.modules", gdb=MagicMock()): from memfault_gdb import Section, MemfaultCoredumpWriter cd_writer = MemfaultCoredumpWriter() cd_writer.device_serial = "device_serial" cd_writer.firmware_version = "1.2.3" cd_writer.hardware_revision = "gdb-proto" cd_writer.trace_reason = 5 cd_writer.regs = { "r0": 4 * b"\x00", "r1": 4 * b"\x01", "r2": 4 * b"\x02", "r3": 4 * b"\x03", "r4": 4 * b"\x04", "r5": 4 * b"\x05", "r6": 4 * b"\x06", "r7": 4 * b"\x07", "r8": 4 * b"\x08", "r9": 4 * b"\x09", "r10": 4 * b"\x0A", "r11": 4 * b"\x0B", "r12": 4 * b"\x0C", "sp": 4 * b"\x0D", "lr": 4 * b"\x0E", "pc": 4 * b"\x0F", "xpsr": 4 * b"\x10", } section = Section(4, 32, ".test", "") section.data = b"hello world" cd_writer.add_section(section) f_out = BytesIO() cd_writer.write(f_out) f_out.seek(0) fixture_bin = open(os.path.join(script_dir, "fixture.bin"), "rb").read() assert f_out.read() == fixture_bin
def test_should_capture_section(gdb_base_fixture): from memfault_gdb import Section, should_capture_section # Never capture .text, even when NOT marked READONLY: assert False == should_capture_section(Section(0, 10, ".text", read_only=False)) # Never capture .debug_... assert False == should_capture_section(Section(0, 10, ".debug_info", read_only=True)) # Never capture 0 length sections assert False == should_capture_section(Section(0, 0, ".dram0.data", read_only=False)) # Always capture sections with .bss, .heap, .data or .stack in the name, even when marked READONLY: assert True == should_capture_section(Section(0, 10, ".foo.bss", read_only=True)) assert True == should_capture_section(Section(0, 10, ".stack_dummy", read_only=True)) assert True == should_capture_section(Section(0, 10, ".heap_psram", read_only=True)) assert True == should_capture_section(Section(0, 10, ".dram0.data", read_only=True))
def test_should_capture_section(): with mock.patch.dict("sys.modules", gdb=MagicMock()): from memfault_gdb import Section, should_capture_section # Never capture .text, even when NOT marked READONLY: assert False == should_capture_section(Section(0, 0, ".text", read_only=False)) # Never capture .debug_... assert False == should_capture_section(Section(0, 0, ".debug_info", read_only=True)) # Always capture sections with .bss, .heap, .data or .stack in the name, even when marked READONLY: assert True == should_capture_section(Section(0, 0, ".foo.bss", read_only=True)) assert True == should_capture_section(Section(0, 0, ".stack_dummy", read_only=True)) assert True == should_capture_section(Section(0, 0, ".heap_psram", read_only=True)) assert True == should_capture_section(Section(0, 0, ".dram0.data", read_only=True))