mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-27 02:45:53 +00:00
95bde56cb7
read_memory() is one of the hottest functions in profiles of tight loops over lists of items, and it can be done much more efficiently in C.
139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
import base64
|
|
import contextlib
|
|
import struct
|
|
import tempfile
|
|
import unittest
|
|
|
|
from drgn.corereader import CoreReader
|
|
from drgn.dwarf import ElfFormatError
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def tmpfile(data):
|
|
file = tempfile.NamedTemporaryFile()
|
|
try:
|
|
file.write(data)
|
|
file.flush()
|
|
yield file
|
|
finally:
|
|
file.close()
|
|
|
|
|
|
def make_elf_file(segments=None):
|
|
if segments is None:
|
|
segments = [(0xffff0000, b'foobar\0\0')]
|
|
buf = bytearray(64 + 56 * len(segments))
|
|
struct.pack_into(
|
|
'<16sHHLQQQLHHHHHH', buf, 0,
|
|
b'\x7fELF\x02\x01\x01\0\0\0\0\0\0\0\0\0', # e_ident
|
|
4, # e_type (ET_CORE)
|
|
62, # e_machine (EM_X86_64)
|
|
1, # e_version (EV_CURRENT)
|
|
0, # e_entry
|
|
64, # e_phoff (right after the header)
|
|
0, # e_shoff
|
|
0, # e_flags
|
|
64, # e_ehsize
|
|
56, # e_phentsize
|
|
len(segments), # e_phnum
|
|
0, # e_shentsize
|
|
0, # e_shnum
|
|
0, # e_shstrndx
|
|
)
|
|
for i, segment in enumerate(segments):
|
|
if len(buf) % 4096:
|
|
buf.extend(bytes(4096 - len(buf) % 4096))
|
|
struct.pack_into(
|
|
'<LLQQQQQQ', buf, 64 + i * 56,
|
|
1, # p_type (PT_LOAD)
|
|
0x7, # p_flags (PF_R | PF_W | PF_X)
|
|
len(buf), # p_offset
|
|
segment[0], # p_vaddr
|
|
0xffffffffffffffff, # p_paddr
|
|
len(segment[1]), # p_filesz
|
|
len(segment[1]), # p_memsz
|
|
4096, # p_align
|
|
)
|
|
buf.extend(segment[1])
|
|
return buf
|
|
|
|
|
|
class TestCoreReader(unittest.TestCase):
|
|
def test_short_file(self):
|
|
elf_file = make_elf_file()
|
|
with tmpfile(elf_file[:3]) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'not an ELF file',
|
|
CoreReader, file.name)
|
|
|
|
def test_invalid_elf_magic(self):
|
|
elf_file = make_elf_file()
|
|
elf_file[0] = 88
|
|
with tmpfile(elf_file) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'not an ELF file',
|
|
CoreReader, file.name)
|
|
|
|
def test_invalid_elf_version(self):
|
|
elf_file = make_elf_file()
|
|
elf_file[6] = 2
|
|
with tmpfile(elf_file) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'ELF version',
|
|
CoreReader, file.name)
|
|
|
|
def test_truncated_elf_header(self):
|
|
elf_file = make_elf_file()
|
|
with tmpfile(elf_file[:16]) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'ELF header is truncated',
|
|
CoreReader, file.name)
|
|
|
|
def test_no_segments(self):
|
|
elf_file = make_elf_file([])
|
|
with tmpfile(elf_file) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'ELF file has no segments',
|
|
CoreReader, file.name)
|
|
|
|
def test_program_header_table_overflow(self):
|
|
elf_file = make_elf_file()
|
|
elf_file[32:40] = b'\xff\xff\xff\xff\xff\xff\xff\xff'
|
|
with tmpfile(elf_file) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'ELF program header table is beyond EOF',
|
|
CoreReader, file.name)
|
|
|
|
def test_truncated_program_header_table(self):
|
|
elf_file = make_elf_file()
|
|
with tmpfile(elf_file[:64]) as file:
|
|
self.assertRaisesRegex(ElfFormatError, 'ELF program header table is beyond EOF',
|
|
CoreReader, file.name)
|
|
|
|
def test_simple_read(self):
|
|
data = b'hello, world!'
|
|
elf_file = make_elf_file([(0xffff0000, data)])
|
|
with tmpfile(elf_file) as file:
|
|
core_reader = CoreReader(file.name)
|
|
self.assertEqual(core_reader.read(0xffff0000, len(data)), data)
|
|
|
|
def test_bad_address(self):
|
|
elf_file = make_elf_file()
|
|
with tmpfile(elf_file) as file:
|
|
core_reader = CoreReader(file.name)
|
|
self.assertRaisesRegex(ValueError, 'could not find memory segment',
|
|
core_reader.read, 0x0, 4)
|
|
|
|
def test_segment_overflow(self):
|
|
data = b'hello, world!'
|
|
elf_file = make_elf_file([(0xffff0000, data)])
|
|
with tmpfile(elf_file) as file:
|
|
core_reader = CoreReader(file.name)
|
|
self.assertRaisesRegex(ValueError, 'could not find memory segment',
|
|
core_reader.read, 0xffff0000, len(data) + 1)
|
|
|
|
def test_contiguous_segments(self):
|
|
data = b'hello, world!'
|
|
elf_file = make_elf_file([
|
|
(0xffff0000, data[:4]),
|
|
(0xfffff000, b'foobar'),
|
|
(0xffff0004, data[4:]),
|
|
])
|
|
with tmpfile(elf_file) as file:
|
|
core_reader = CoreReader(file.name)
|
|
self.assertEqual(core_reader.read(0xffff0000, len(data)), data)
|