Merge pull request #7782 from parl0v/fix/unwrap-self-unstored-version-segment

fix(tools): unwrap SELF dumps that leave out the version segment
This commit is contained in:
Dean authored and GitHub committed 2026-10-19 20:21:32 +13:00
commit fb0dc118f3
2 files changed
+32 -2

No files matched your search

+25
View File
@@ -168,6 +168,31 @@ class UnwrapTest(unittest.TestCase):
self.assertEqual(data[version[2]:version[2] + version[5]], pattern(13, 0x10))
self.assertEqual(note[5], 0)
def test_a_version_segment_the_container_does_not_store_is_emitted_without_file_bytes(self):
segments = default_segments() + [(SCE_COMMENT, 4, 0x15A0, 0x0, 0x20, 0x10), (PT_NOTE, 4, 0x15C0, 0x0, 0x18, 4),
(SCE_VERSION, 4, 0x15D8, 0x0, 0x10, 0x10)]
records = default_records() + [(0x410004, 0xA80, 0x20), (0x302804, 0xAA0, 0x20)]
for stored in (0, 8):
with self.subTest(stored=stored):
payloads = dict(default_payloads())
payloads[0xAA0] = pattern(11, 0x20)
if stored:
payloads[0xAC0] = pattern(13, stored)
container = build_container(segments, records, payloads)
self.assertEqual(len(container), 0xAC0 + stored)
result, output = self.convert(container)
self.assertEqual(result.returncode, 0, result.stderr)
data, headers = read_program_headers(output)
loads = [header for header in headers if header[0] == PT_LOAD]
self.assertEqual(data[loads[0][2]:loads[0][2] + loads[0][5]], pattern(1, 0x100))
self.assertEqual(data[loads[1][2]:loads[1][2] + loads[1][5]], pattern(9, 0x80))
comment = [header for header in headers if header[0] == SCE_COMMENT][0]
self.assertEqual(data[comment[2]:comment[2] + comment[5]], pattern(11, 0x20))
version = [header for header in headers if header[0] == SCE_VERSION][0]
self.assertEqual((version[2], version[5]), (0, 0))
for header in headers:
self.assertLessEqual(header[2] + header[5], len(data))
def test_declared_offsets_are_used_when_the_container_has_no_records(self):
segments = [(PT_LOAD, 1, 0x800, 0x0, 0x40, 0x1000), (PT_LOAD, 4, 0x900, 0x1000, 0x40, 0x1000)]
payloads = {0x800: pattern(3, 0x40), 0x900: pattern(5, 0x40)}
+7 -2
View File
@@ -14,8 +14,10 @@ differ inside a container:
mapping of the PT_LOAD that contains them. Segments without a vaddr that
follow the last recorded one in the ELF are stored right after it, back to
back in ELF order, except a PT_NOTE, which the container leaves out and which
is emitted without file bytes. Other segments without a vaddr carry the shift
of the last placed one.
is emitted without file bytes. Some dumps end right after the recorded ones
and leave out the version segment as well, so one that would run past the
end of the file is emitted without file bytes too. Other segments without a
vaddr carry the shift of the last placed one.
- The segments are packed without honouring p_align, while ELF requires
p_offset % p_align == p_vaddr % p_align. Every region is copied to an offset
that satisfies it, which the relinker enforces on guest modules.
@@ -156,6 +158,9 @@ def place_segments(data, headers, records):
continue
header["source"] = cursor
cursor += header["size"]
if cursor > len(data):
header["source"] = 0
header["size"] = 0
for header in loads:
if header["size"] == 0 or header["index"] in placed:
continue