diff --git a/tools/tests/test_unwrap_self.py b/tools/tests/test_unwrap_self.py index 0d5bf8caf0..aff38128e5 100644 --- a/tools/tests/test_unwrap_self.py +++ b/tools/tests/test_unwrap_self.py @@ -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)} diff --git a/tools/unwrap_self.py b/tools/unwrap_self.py index 7225820aaa..b03fd9bfe2 100644 --- a/tools/unwrap_self.py +++ b/tools/unwrap_self.py @@ -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