mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 01:03:07 +00:00
tests: test compressed debug sections
Test both .zdebug_* sections and SHF_COMPRESSED .debug_* sections. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
2ee625fc74
commit
104a14781d
@ -22,6 +22,7 @@ def main() -> None:
|
||||
for name in (
|
||||
"ET",
|
||||
"PT",
|
||||
"SHF",
|
||||
"SHN",
|
||||
"SHT",
|
||||
"STB",
|
||||
@ -32,13 +33,16 @@ def main() -> None:
|
||||
for match in re.finditer(
|
||||
r"^\s*#\s*define\s+(?P<enum>"
|
||||
+ "|".join(enums)
|
||||
+ r")_(?P<name>\w+)\s+(?P<value>0x[0-9a-fA-F]+|[0-9]+)",
|
||||
+ r")_(?P<name>\w+)\s+(?:(?P<value>0x[0-9a-fA-F]+|[0-9]+)|(?:\(\s*1U?\s*<<\s*(?P<bitshift>[0-9]+)\s*\)))",
|
||||
contents,
|
||||
re.MULTILINE,
|
||||
):
|
||||
enum = match.group("enum")
|
||||
name = match.group("name")
|
||||
value = int(match.group("value"), 0)
|
||||
if match.group("value"):
|
||||
value = int(match.group("value"), 0)
|
||||
else:
|
||||
value = 1 << int(match.group("bitshift"), 10)
|
||||
enums[enum].append((name, value))
|
||||
|
||||
f = sys.stdout
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
import os.path
|
||||
from typing import Any, NamedTuple, Optional, Sequence, Union
|
||||
import zlib
|
||||
|
||||
from tests.assembler import _append_sleb128, _append_uleb128
|
||||
from tests.dwarf import DW_AT, DW_FORM, DW_TAG
|
||||
@ -232,7 +233,13 @@ _UNIT_TAGS = frozenset({DW_TAG.type_unit, DW_TAG.compile_unit})
|
||||
|
||||
|
||||
def dwarf_sections(
|
||||
dies, little_endian=True, bits=64, *, lang=None, use_dw_form_indirect=False
|
||||
dies,
|
||||
little_endian=True,
|
||||
bits=64,
|
||||
*,
|
||||
lang=None,
|
||||
use_dw_form_indirect=False,
|
||||
compress=None,
|
||||
):
|
||||
if isinstance(dies, DwarfDie):
|
||||
dies = (dies,)
|
||||
@ -263,29 +270,47 @@ def dwarf_sections(
|
||||
unit_dies, little_endian, bits, use_dw_form_indirect
|
||||
)
|
||||
|
||||
if compress == "zlib-gnu":
|
||||
|
||||
def debug_section(name, data):
|
||||
assert name.startswith(".debug")
|
||||
compressed_data = bytearray(b"ZLIB")
|
||||
compressed_data.extend(len(data).to_bytes(8, "big"))
|
||||
compressed_data.extend(zlib.compress(data))
|
||||
return ElfSection(
|
||||
name=".z" + name[1:], sh_type=SHT.PROGBITS, data=compressed_data
|
||||
)
|
||||
|
||||
else:
|
||||
assert compress is None or compress == "zlib-gabi", compress
|
||||
compressed = compress is not None
|
||||
|
||||
def debug_section(name, data):
|
||||
return ElfSection(
|
||||
name=name, sh_type=SHT.PROGBITS, data=data, compressed=compressed
|
||||
)
|
||||
|
||||
sections = [
|
||||
ElfSection(
|
||||
name=".debug_abbrev",
|
||||
sh_type=SHT.PROGBITS,
|
||||
data=_compile_debug_abbrev(unit_dies, use_dw_form_indirect),
|
||||
debug_section(
|
||||
".debug_abbrev", _compile_debug_abbrev(unit_dies, use_dw_form_indirect)
|
||||
),
|
||||
ElfSection(name=".debug_info", sh_type=SHT.PROGBITS, data=debug_info),
|
||||
ElfSection(
|
||||
name=".debug_line",
|
||||
sh_type=SHT.PROGBITS,
|
||||
data=_compile_debug_line(unit_dies, little_endian),
|
||||
),
|
||||
ElfSection(name=".debug_str", sh_type=SHT.PROGBITS, data=b"\0"),
|
||||
debug_section(".debug_info", data=debug_info),
|
||||
debug_section(".debug_line", _compile_debug_line(unit_dies, little_endian)),
|
||||
debug_section(".debug_str", b"\0"),
|
||||
]
|
||||
if debug_types:
|
||||
sections.append(
|
||||
ElfSection(name=".debug_types", sh_type=SHT.PROGBITS, data=debug_types)
|
||||
)
|
||||
sections.append(debug_section(".debug_types", debug_types))
|
||||
return sections
|
||||
|
||||
|
||||
def compile_dwarf(
|
||||
dies, little_endian=True, bits=64, *, lang=None, use_dw_form_indirect=False
|
||||
dies,
|
||||
little_endian=True,
|
||||
bits=64,
|
||||
*,
|
||||
lang=None,
|
||||
use_dw_form_indirect=False,
|
||||
compress=None,
|
||||
):
|
||||
return create_elf_file(
|
||||
ET.EXEC,
|
||||
@ -295,6 +320,7 @@ def compile_dwarf(
|
||||
bits=bits,
|
||||
lang=lang,
|
||||
use_dw_form_indirect=use_dw_form_indirect,
|
||||
compress=compress,
|
||||
),
|
||||
little_endian=little_endian,
|
||||
bits=bits,
|
||||
|
42
tests/elf.py
42
tests/elf.py
@ -63,6 +63,48 @@ class PT(enum.IntEnum):
|
||||
return hex(value)
|
||||
|
||||
|
||||
class SHF(enum.IntEnum):
|
||||
WRITE = 0x1
|
||||
ALLOC = 0x2
|
||||
EXECINSTR = 0x4
|
||||
MERGE = 0x10
|
||||
STRINGS = 0x20
|
||||
INFO_LINK = 0x40
|
||||
LINK_ORDER = 0x80
|
||||
OS_NONCONFORMING = 0x100
|
||||
GROUP = 0x200
|
||||
TLS = 0x400
|
||||
COMPRESSED = 0x800
|
||||
MASKOS = 0xFF00000
|
||||
MASKPROC = 0xF0000000
|
||||
GNU_RETAIN = 0x200000
|
||||
ORDERED = 0x40000000
|
||||
EXCLUDE = 0x80000000
|
||||
MIPS_GPREL = 0x10000000
|
||||
MIPS_MERGE = 0x20000000
|
||||
MIPS_ADDR = 0x40000000
|
||||
MIPS_STRINGS = 0x80000000
|
||||
MIPS_NOSTRIP = 0x8000000
|
||||
MIPS_LOCAL = 0x4000000
|
||||
MIPS_NAMES = 0x2000000
|
||||
MIPS_NODUPE = 0x1000000
|
||||
PARISC_SHORT = 0x20000000
|
||||
PARISC_HUGE = 0x40000000
|
||||
PARISC_SBP = 0x80000000
|
||||
ALPHA_GPREL = 0x10000000
|
||||
ARM_ENTRYSECT = 0x10000000
|
||||
ARM_COMDEF = 0x80000000
|
||||
IA_64_SHORT = 0x10000000
|
||||
IA_64_NORECOV = 0x20000000
|
||||
|
||||
@classmethod
|
||||
def str(cls, value: int) -> Text:
|
||||
try:
|
||||
return f"SHF_{cls(value).name}"
|
||||
except ValueError:
|
||||
return hex(value)
|
||||
|
||||
|
||||
class SHN(enum.IntEnum):
|
||||
UNDEF = 0x0
|
||||
LORESERVE = 0xFF00
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
import struct
|
||||
from typing import List, NamedTuple, Optional, Sequence
|
||||
import zlib
|
||||
|
||||
from tests.elf import ET, PT, SHN, SHT, STB, STT, STV
|
||||
from tests.elf import ET, PT, SHF, SHN, SHT, STB, STT, STV
|
||||
|
||||
|
||||
class ElfSection:
|
||||
@ -21,14 +22,16 @@ class ElfSection:
|
||||
sh_link: int = 0,
|
||||
sh_info: int = 0,
|
||||
sh_entsize: int = 0,
|
||||
compressed=False,
|
||||
):
|
||||
self.data = data
|
||||
self.name = name
|
||||
self.sh_type = sh_type
|
||||
self.sh_flags = SHF.COMPRESSED if compressed else 0
|
||||
self.p_type = p_type
|
||||
self.vaddr = vaddr
|
||||
self.paddr = paddr
|
||||
self.memsz = len(self.data) if memsz is None else memsz
|
||||
self.memsz = memsz
|
||||
self.p_align = p_align
|
||||
self.sh_link = sh_link
|
||||
self.sh_info = sh_info
|
||||
@ -36,6 +39,7 @@ class ElfSection:
|
||||
|
||||
assert (self.name is not None) or (self.p_type is not None)
|
||||
assert (self.name is None) == (self.sh_type is None)
|
||||
assert self.p_type is None or not compressed
|
||||
|
||||
|
||||
class ElfSymbol(NamedTuple):
|
||||
@ -122,12 +126,14 @@ def create_elf_file(
|
||||
ehdr_struct = struct.Struct(endian + "16BHHIQQQIHHHHHH")
|
||||
shdr_struct = struct.Struct(endian + "IIQQQQIIQQ")
|
||||
phdr_struct = struct.Struct(endian + "IIQQQQQQ")
|
||||
chdr_struct = struct.Struct(endian + "IIQQ")
|
||||
e_machine = 62 if little_endian else 43 # EM_X86_64 or EM_SPARCV9
|
||||
else:
|
||||
assert bits == 32
|
||||
ehdr_struct = struct.Struct(endian + "16BHHIIIIIHHHHHH")
|
||||
shdr_struct = struct.Struct(endian + "10I")
|
||||
phdr_struct = struct.Struct(endian + "8I")
|
||||
chdr_struct = struct.Struct(endian + "III")
|
||||
e_machine = 3 if little_endian else 8 # EM_386 or EM_MIPS
|
||||
|
||||
sections = list(sections)
|
||||
@ -189,6 +195,15 @@ def create_elf_file(
|
||||
|
||||
shdr_offset += shdr_struct.size
|
||||
for section in sections:
|
||||
ch_addralign = 1 if section.p_type is None else bits // 8
|
||||
memsz = len(section.data) if section.memsz is None else section.memsz
|
||||
if section.sh_flags & SHF.COMPRESSED:
|
||||
sh_addralign = bits // 8
|
||||
compressed_data = zlib.compress(section.data)
|
||||
sh_size = chdr_struct.size + len(compressed_data)
|
||||
else:
|
||||
sh_addralign = ch_addralign
|
||||
sh_size = memsz
|
||||
if section.p_align:
|
||||
padding = section.vaddr % section.p_align - len(buf) % section.p_align
|
||||
buf.extend(bytes(padding))
|
||||
@ -198,13 +213,13 @@ def create_elf_file(
|
||||
shdr_offset,
|
||||
shstrtab.index(section.name.encode()), # sh_name
|
||||
section.sh_type, # sh_type
|
||||
0, # sh_flags
|
||||
section.sh_flags, # sh_flags
|
||||
section.vaddr, # sh_addr
|
||||
len(buf), # sh_offset
|
||||
section.memsz, # sh_size
|
||||
sh_size, # sh_size
|
||||
section.sh_link, # sh_link
|
||||
section.sh_info, # sh_info
|
||||
1 if section.p_type is None else bits // 8, # sh_addralign
|
||||
sh_addralign, # sh_addralign
|
||||
section.sh_entsize, # sh_entsize
|
||||
)
|
||||
shdr_offset += shdr_struct.size
|
||||
@ -220,7 +235,7 @@ def create_elf_file(
|
||||
section.vaddr, # p_vaddr
|
||||
section.paddr, # p_paddr
|
||||
len(section.data), # p_filesz
|
||||
section.memsz, # p_memsz
|
||||
memsz, # p_memsz
|
||||
section.p_align, # p_align
|
||||
)
|
||||
else:
|
||||
@ -232,11 +247,32 @@ def create_elf_file(
|
||||
section.vaddr, # p_vaddr
|
||||
section.paddr, # p_paddr
|
||||
len(section.data), # p_filesz
|
||||
section.memsz, # p_memsz
|
||||
memsz, # p_memsz
|
||||
flags, # p_flags
|
||||
section.p_align, # p_align
|
||||
)
|
||||
phdr_offset += phdr_struct.size
|
||||
buf.extend(section.data)
|
||||
if section.sh_flags & SHF.COMPRESSED:
|
||||
ELFCOMPRESS_ZLIB = 1
|
||||
if bits == 64:
|
||||
buf.extend(
|
||||
chdr_struct.pack(
|
||||
ELFCOMPRESS_ZLIB, # ch_type
|
||||
0, # ch_reserved
|
||||
memsz, # ch_size
|
||||
ch_addralign, # ch_addralign
|
||||
)
|
||||
)
|
||||
else:
|
||||
buf.extend(
|
||||
chdr_struct.pack(
|
||||
ELFCOMPRESS_ZLIB, # ch_type
|
||||
memsz, # ch_size
|
||||
ch_addralign, # ch_addralign
|
||||
)
|
||||
)
|
||||
buf.extend(compressed_data)
|
||||
else:
|
||||
buf.extend(section.data)
|
||||
|
||||
return buf
|
||||
|
@ -6490,3 +6490,13 @@ class TestProgram(TestCase):
|
||||
*labeled_int_die,
|
||||
)
|
||||
self.assertIsNotNone(repr(dwarf_program(dies).type("TEST").type.parameters[0]))
|
||||
|
||||
|
||||
class TestCompressedDebugSections(TestCase):
|
||||
def test_zlib_gnu(self):
|
||||
prog = dwarf_program(wrap_test_type_dies(int_die), compress="zlib-gnu")
|
||||
self.assertIdentical(prog.type("TEST").type, prog.int_type("int", 4, True))
|
||||
|
||||
def test_zlib_gabi(self):
|
||||
prog = dwarf_program(wrap_test_type_dies(int_die), compress="zlib-gabi")
|
||||
self.assertIdentical(prog.type("TEST").type, prog.int_type("int", 4, True))
|
||||
|
Loading…
Reference in New Issue
Block a user