Skip to content

Instantly share code, notes, and snippets.

@wyattearp
Created April 8, 2022 01:10
Show Gist options
  • Save wyattearp/d937c1e1a5c5902263fcaf86cd0d4457 to your computer and use it in GitHub Desktop.
Save wyattearp/d937c1e1a5c5902263fcaf86cd0d4457 to your computer and use it in GitHub Desktop.
import os
import sys
import gdb
def run_cmd(cmd):
#tmpfile = '/tmp/tmp_cmd.txt'
#os.system(f'rm -f {tmpfile}')
#gdb.execute(f'set logging file {tmpfile}')
#gdb.execute(f'set logging on')
result = gdb.execute(cmd, False, True)
#gdb.execute(f'set logging off')
#result = open(tmpfile).read()
#os.system(f'rm -f {tmpfile}')
return result
class Mapping:
def __init__(self, start, end, size, offset, file, attrs=[]):
self.start = start
self.end = end
self.size = size
self.offset = offset
self.file = file
self.attrs = attrs
def __repr__(self):
return f'{hex(self.start):>20} {hex(self.end):>18} {hex(self.size):>10} {hex(self.offset):>10} {self.file}' # + f' {self.attrs}'
def inside(self, other):
if other.start == self.start and self.end == other.end:
return False
if other.start <= self.start and self.end <= other.end:
return True
return False
def round_page(self):
PAGE_MASK = 0xfff
start_mask = self.start & PAGE_MASK
self.start -= start_mask
self.offset -= start_mask
self.size += start_mask
end_mask = self.end & PAGE_MASK
end_short = (0x1000 - end_mask) if end_mask else 0
self.end += end_short
self.size += end_short
def parse_info_proc_mappings(text):
mappings = []
for line in text.split('\n'):
line = line.lstrip()
if not line.startswith('0x'):
continue
parts = line.split()
start = int(parts[0], 16)
end = int(parts[1], 16)
size = int(parts[2], 16)
offset = int(parts[3], 16)
file = ''
if len(parts) >= 5:
file = parts[4]
mappings.append(Mapping(start, end, size, offset, file))
return mappings
def parse_maintenance_info_sections(text):
mappings = []
current_obj_file = ''
for line in text.split('\n'):
if 'Object file:' in line:
current_obj_file = line.split('Object file:')[1].strip()
#print(f'Object file "{current_obj_file}"')
elif ' at ' in line:
before_at, after_at = line.split(' at ')
split_line = after_at.split()
#print(f"split_line={before_at} {split_line}")
start, end = before_at.split('->')
start = int(start.split()[-1], 16)
end = int(end, 16)
size = end - start
offset = int(split_line[0].rstrip(':'), 16)
section_name = split_line[1]
attrs = split_line[2:]
if start and not ' ' in current_obj_file: # and 'CODE' in attrs:
mappings.append(Mapping(start, end, size, offset, current_obj_file, [section_name] + attrs))
return mappings
def dedup_mappings(mappings):
mappings = sorted(mappings, key=lambda m:(m.start, m.end))
deduped = mappings[:1]
for a, b in zip(mappings[:-1],mappings[1:]):
if a.start == b.start and a.end == b.end:
continue
deduped.append(b)
return deduped
def remove_subsections(mappings):
return [m for m in mappings if not any(m.inside(other) for other in mappings)]
def fix_overlap(mappings):
mappings = sorted(mappings, key=lambda m:(m.start, m.end))
for m in mappings:
overlaps = [m2 for m2 in mappings if m != m2 and m2.start <= m.start and m.start < m2.end]
if overlaps:
new_start = max([m2.end for m2 in overlaps])
m.offset = m.offset + (new_start - m.start)
m.start = new_start
if m.start > m.end:
m.end = m.start
m.size = m.end - m.start
return mappings
'''
#result = gdb.execute('maintenance info sections ALLOBJ')
result = run_cmd('info proc mappings')
mappings = parse_info_proc_mappings(result)
print("info proc mappings output:")
for mapping in mappings:
print(mapping)
'''
def define_info_proc_mapping_equivalent():
maint_sec = run_cmd('maintenance info sections ALLOBJ')
sections = parse_maintenance_info_sections(maint_sec)
for mapping in sections:
mapping.round_page()
sections = [s for s in sections if s.offset >= 0]
sections = [s for s in sections if '/usr/lib/debug' not in s.file]
deduped_sections = dedup_mappings(sections)
cleaned_sections = remove_subsections(deduped_sections)
non_overlapping = fix_overlap(cleaned_sections)
'''
print("All sections:")
for mapping in sections:
print(mapping)
print("Deduped sections:")
for mapping in deduped_sections:
print(mapping)
print("Cleaned sections:")
for mapping in cleaned_sections:
print(mapping)
print("Fixing overlap")
for mapping in fix_overlap(cleaned_sections):
print(mapping)
'''
cmd_txt = 'define info proc mappings\n'
cmd_lines = []
# This gets pid 1 when running against a QEMU user-mode instance.
# The PID is not meaningful for querying the
#cmd_lines.append(f'process {gdb.selected_inferior().pid}')
cmd_lines.append('Mapped address spaces:')
cmd_lines.append('')
cmd_lines.append(' Start Addr End Addr Size Offset objfile')
for mapping in non_overlapping:
cmd_lines.append(f'{mapping}')
cmd_txt += ''.join(f'echo {line}\\n\n' for line in cmd_lines)
cmd_txt += 'end\n'
print(cmd_txt)
with open('/tmp/test_mapping', 'w') as fd:
fd.write(cmd_txt)
run_cmd('source /tmp/test_mapping')
#run_cmd(cmd_txt)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment