code refactor

This commit is contained in:
Nicolas Kruse 2025-02-27 16:55:03 +01:00
parent f06f68681b
commit f17cf0acfb
3 changed files with 511 additions and 115 deletions

View File

@ -22,12 +22,8 @@ class elf_symbol():
self.index = index self.index = index
st_info = fdat.st_info_values[fields['st_info'] & 0x0F] self.info, self.description = fdat.st_info_values[fields['st_info'] & 0x0F]
stb = fdat.stb_values[fields['st_info'] >> 4] self.stb, self.stb_description = fdat.stb_values[fields['st_info'] >> 4]
self.stb = stb['name']
self.description = st_info['description']
self.info = st_info['name']
def read_data(self) -> bytes: def read_data(self) -> bytes:
offset = self.file.sections[self['st_shndx']]['sh_offset'] + self['st_value'] offset = self.file.sections[self['st_shndx']]['sh_offset'] + self['st_value']
@ -47,15 +43,17 @@ class elf_symbol():
ret.append(reloc) ret.append(reloc)
return relocation_list(ret) return relocation_list(ret)
def __getitem__(self, key: str): def __getitem__(self, key: str | int):
if isinstance(key, str):
assert key in self.fields, f'Unknown field name: {key}' assert key in self.fields, f'Unknown field name: {key}'
return self.fields[key] return self.fields[key]
else:
return list(self.fields.values())[key]
def __repr__(self): def __repr__(self):
stb = fdat.stb_values[self.fields['st_info'] >> 4]
return f'index {self.index}\n' +\ return f'index {self.index}\n' +\
f'name {self.name}\n' +\ f'name {self.name}\n' +\
f'stb {self.stb} ({stb["description"]})\n' +\ f'stb {self.stb} ({self.stb_description})\n' +\
f'info {self.info} ({self.description})\n' +\ f'info {self.info} ({self.description})\n' +\
'\n'.join(f'{k:18} {v:4}' for k, v in self.fields.items()) + '\n' '\n'.join(f'{k:18} {v:4}' for k, v in self.fields.items()) + '\n'
@ -68,16 +66,24 @@ class elf_section():
self.name = name self.name = name
self.data = self.file.read_bytes(self['sh_offset'], self['sh_size']) self.data = self.file.read_bytes(self['sh_offset'], self['sh_size'])
assert fields['sh_type'] in fdat.section_header_types, f"Unknown section type: {hex(fields['sh_type'])}" if fields['sh_type'] > 0x60000000:
self.description = fdat.section_header_types[fields['sh_type']]['description'] self.description = [v for k, v in fdat.section_header_types_ex.items() if k >= fields['sh_type']][0]
self.type = fdat.section_header_types[fields['sh_type']]['name'] self.type = str(hex(fields['sh_type']))
elif fields['sh_type'] in fdat.section_header_types:
self.type, self.description = fdat.section_header_types[fields['sh_type']]
else:
self.description = ''
self.type = str(hex(fields['sh_type']))
def get_data_hex(self): def get_data_hex(self):
return ' '.join(f'{d:02X}' for d in self.data) return ' '.join(f'{d:02X}' for d in self.data)
def __getitem__(self, key: str): def __getitem__(self, key: str | int):
if isinstance(key, str):
assert key in self.fields, f'Unknown field name: {key}' assert key in self.fields, f'Unknown field name: {key}'
return self.fields[key] return self.fields[key]
else:
return list(self.fields.values())[key]
def __repr__(self): def __repr__(self):
return f'index {self.index}\n' +\ return f'index {self.index}\n' +\
@ -87,21 +93,31 @@ class elf_section():
class elf_relocation(): class elf_relocation():
def __init__(self, file: 'elf_file', fields: dict[str, int], symbol_index: int, relocation_type: int, sh_info: int): def __init__(self, file: 'elf_file', fields: dict[str, int], symbol_index: int, relocation_type: int, sh_info: int, index: int):
self.fields = fields self.fields = fields
self.file = file self.file = file
self.index = index
self.symbol = file.symbols[symbol_index] self.symbol = file.symbols[symbol_index]
self.description = fdat.relocation_table_types[relocation_type]['description'] reloc_types = fdat.relocation_table_types.get(file.architecture)
self.type = fdat.relocation_table_types[relocation_type]['name'] if reloc_types and relocation_type in reloc_types:
self.calculation = reloc_types[relocation_type][2]
self.type = reloc_types[relocation_type][0]
else:
self.calculation = ''
self.type = str(relocation_type)
self.target_section = file.sections[sh_info] self.target_section = file.sections[sh_info]
def __getitem__(self, key: str): def __getitem__(self, key: str | int):
if isinstance(key, str):
assert key in self.fields, f'Unknown field name: {key}' assert key in self.fields, f'Unknown field name: {key}'
return self.fields[key] return self.fields[key]
else:
return list(self.fields.values())[key]
def __repr__(self): def __repr__(self):
return f'symbol {self.symbol.name}\n' +\ return f'index {self.symbol.index}\n' +\
f'relocation type {self.type} ({self.description})\n' +\ f'symbol {self.symbol.name}\n' +\
f'relocation type {self.type} ({self.calculation})\n' +\
'\n'.join(f'{k:18} {v:4}' for k, v in self.fields.items()) + '\n' '\n'.join(f'{k:18} {v:4}' for k, v in self.fields.items()) + '\n'
@ -117,10 +133,13 @@ class elf_list(Generic[_T]):
else: else:
return self._data.__getitem__(key) return self._data.__getitem__(key)
def __len__(self):
return len(self._data)
def __iter__(self): def __iter__(self):
return iter(self._data) return iter(self._data)
def _repr_table(self, format: Literal['text', 'markdown', 'html']) -> str: def _repr_table(self, format: output_formatter.table_format) -> str:
return 'not implemented' return 'not implemented'
def to_html(self): def to_html(self):
@ -137,8 +156,7 @@ class elf_list(Generic[_T]):
class section_list(elf_list[elf_section]): class section_list(elf_list[elf_section]):
def _repr_table(self, format: output_formatter.table_format):
def _repr_table(self, format: Literal['text', 'markdown', 'html']):
columns = ['index', 'name', 'type', 'description'] columns = ['index', 'name', 'type', 'description']
data: list[list[str | int]] = [[item.index, item.name, item.type, data: list[list[str | int]] = [[item.index, item.name, item.type,
item.description] for item in self] item.description] for item in self]
@ -146,8 +164,7 @@ class section_list(elf_list[elf_section]):
class symbol_list(elf_list[elf_symbol]): class symbol_list(elf_list[elf_symbol]):
def _repr_table(self, format: output_formatter.table_format):
def _repr_table(self, format: Literal['text', 'markdown', 'html']):
columns = ['index', 'name', 'info', 'size', 'stb', 'description'] columns = ['index', 'name', 'info', 'size', 'stb', 'description']
data: list[list[str | int]] = [[item.index, item.name, item.info, item.fields['st_size'], data: list[list[str | int]] = [[item.index, item.name, item.info, item.fields['st_size'],
item.stb, item.description] for item in self] item.stb, item.description] for item in self]
@ -155,10 +172,9 @@ class symbol_list(elf_list[elf_symbol]):
class relocation_list(elf_list[elf_relocation]): class relocation_list(elf_list[elf_relocation]):
def _repr_table(self, format: output_formatter.table_format):
def _repr_table(self, format: Literal['text', 'markdown', 'html']): columns = ['index', 'symbol name', 'type', 'calculation']
columns = ['symbol name', 'type', 'description'] data: list[list[str | int]] = [[item.index, item.symbol.name, item.type, item.calculation] for item in self]
data: list[list[str | int]] = [[item.symbol.name, item.type, item.description] for item in self]
return output_formatter.generate_table(data, columns, format=format) return output_formatter.generate_table(data, columns, format=format)
@ -181,7 +197,7 @@ class elf_file:
self.fields = {fn: self._read_int_from_elf_field(fn) for fn in fdat.elf_header_field.keys()} self.fields = {fn: self._read_int_from_elf_field(fn) for fn in fdat.elf_header_field.keys()}
arch_entr = fdat.e_machine_dict.get(self.fields['e_machine']) arch_entr = fdat.e_machine_dict.get(self.fields['e_machine'])
self.architecture = arch_entr['name'] + ' - ' + arch_entr['description'] if arch_entr else 'Unknown' self.architecture = arch_entr[0] if arch_entr else str(self.fields['e_machine'])
section_data = list(self._list_sections()) section_data = list(self._list_sections())
name_addr: dict[str, int] = section_data[self.fields['e_shstrndx']] if section_data else dict() name_addr: dict[str, int] = section_data[self.fields['e_shstrndx']] if section_data else dict()
@ -201,7 +217,7 @@ class elf_file:
self.functions = symbol_list(s for s in self.symbols if s.info == 'STT_FUNC') self.functions = symbol_list(s for s in self.symbols if s.info == 'STT_FUNC')
self.objects = symbol_list(s for s in self.symbols if s.info == 'STT_OBJECT') self.objects = symbol_list(s for s in self.symbols if s.info == 'STT_OBJECT')
self.code_relocations = self.get_relocations('.rela.text') self.code_relocations = self.get_relocations(['.rela.text', '.rel.text'])
def _list_sections(self): def _list_sections(self):
for i in range(self.fields['e_shnum']): for i in range(self.fields['e_shnum']):
@ -230,38 +246,38 @@ class elf_file:
yield elf_symbol(self, ret, j) yield elf_symbol(self, ret, j)
def get_relocations(self, reloc_section: elf_section | str | None = None) -> relocation_list: def get_relocations(self, reloc_section: elf_section | str | list[str] | None = None) -> relocation_list:
if isinstance(reloc_section, elf_section): if isinstance(reloc_section, elf_section):
assert reloc_section.type == 'SHT_RELA', f'{reloc_section.name} is not a relocation section' assert reloc_section.type in ('SHT_REL', 'SHT_RELA'), f'{reloc_section.name} is not a relocation section'
return relocation_list(self._list_relocations(reloc_section)) return relocation_list(self._list_relocations(reloc_section))
else: else:
relocations: list[elf_relocation] = list() relocations: list[elf_relocation] = list()
for sh in self.sections: for sh in self.sections:
if sh.type == 'SHT_RELA': if sh.type in ('SHT_REL', 'SHT_RELA'):
if sh.name == reloc_section or not isinstance(reloc_section, str): if reloc_section is None or \
(isinstance(reloc_section, str) and sh.name == reloc_section) or \
(isinstance(reloc_section, list) and sh.name in reloc_section):
relocations += relocation_list(self._list_relocations(sh)) relocations += relocation_list(self._list_relocations(sh))
return relocation_list(relocations) return relocation_list(relocations)
def _list_relocations(self, sh: elf_section): def _list_relocations(self, sh: elf_section):
assert sh.type == 'SHT_RELA', 'Section must be a relocation section (currently only SHT_RELA is supported)'
offs = sh['sh_offset'] offs = sh['sh_offset']
for i in range(offs, sh['sh_size'] + offs, sh['sh_entsize']): for i, el_off in enumerate(range(offs, sh['sh_size'] + offs, sh['sh_entsize'])):
ret: dict[str, int] = dict() ret: dict[str, int] = dict()
if self.bit_width == 32: if self.bit_width == 32:
ret['r_offset'] = self.read_int(i, 4) ret['r_offset'] = self.read_int(el_off, 4)
r_info = self.read_int(i + 4, 4) r_info = self.read_int(el_off + 4, 4)
ret['r_info'] = r_info ret['r_info'] = r_info
ret['r_addend'] = self.read_int(i + 8, 4, True) ret['r_addend'] = self.read_int(el_off + 8, 4, True) if sh.type == 'SHT_RELA' else 0
yield elf_relocation(self, ret, r_info >> 8, r_info & 0xFF, sh['sh_info']) yield elf_relocation(self, ret, r_info >> 8, r_info & 0xFF, sh['sh_info'], i)
elif self.bit_width == 64: elif self.bit_width == 64:
ret['r_offset'] = self.read_int(i, 8) ret['r_offset'] = self.read_int(el_off, 8)
r_info = self.read_int(i + 8, 8) r_info = self.read_int(el_off + 8, 8)
ret['r_info'] = r_info ret['r_info'] = r_info
ret['r_addend'] = self.read_int(i + 16, 8, True) ret['r_addend'] = self.read_int(el_off + 16, 8, True) if sh.type == 'SHT_RELA' else 0
yield elf_relocation(self, ret, r_info >> 32, r_info & 0xFFFFFFFF, sh['sh_info']) yield elf_relocation(self, ret, r_info >> 32, r_info & 0xFFFFFFFF, sh['sh_info'], i)
def read_bytes(self, offset: int, num_bytes: int): def read_bytes(self, offset: int, num_bytes: int):
return self._data[offset:offset + num_bytes] return self._data[offset:offset + num_bytes]

View File

@ -81,6 +81,173 @@ elf_header_field = {
} }
} }
e_machine_dict = {
0: ("EM_NONE", "No machine"),
1: ("EM_M32", "AT&T WE 32100"),
2: ("EM_SPARC", "SUN SPARC"),
3: ("EM_386", "Intel 80386"),
4: ("EM_68K", "Motorola m68k family"),
5: ("EM_88K", "Motorola m88k family"),
6: ("EM_IAMCU", "Intel MCU"),
7: ("EM_860", "Intel 80860"),
8: ("EM_MIPS", "MIPS R3000 big-endian"),
9: ("EM_S370", "IBM System/370"),
10: ("EM_MIPS_RS3_LE", "MIPS R3000 little-endian"),
15: ("EM_PARISC", "HPPA"),
17: ("EM_VPP500", "Fujitsu VPP500"),
18: ("EM_SPARC32PLUS", "Sun's v8plus"),
19: ("EM_960", "Intel 80960"),
20: ("EM_PPC", "PowerPC"),
21: ("EM_PPC64", "PowerPC 64-bit"),
22: ("EM_S390", "IBM S390"),
23: ("EM_SPU", "IBM SPU/SPC"),
36: ("EM_V800", "NEC V800 series"),
37: ("EM_FR20", "Fujitsu FR20"),
38: ("EM_RH32", "TRW RH-32"),
39: ("EM_RCE", "Motorola RCE"),
40: ("EM_ARM", "ARM"),
41: ("EM_FAKE_ALPHA", "Digital Alpha"),
42: ("EM_SH", "Hitachi SH"),
43: ("EM_SPARCV9", "SPARC v9 64-bit"),
44: ("EM_TRICORE", "Siemens Tricore"),
45: ("EM_ARC", "Argonaut RISC Core"),
46: ("EM_H8_300", "Hitachi H8/300"),
47: ("EM_H8_300H", "Hitachi H8/300H"),
48: ("EM_H8S", "Hitachi H8S"),
49: ("EM_H8_500", "Hitachi H8/500"),
50: ("EM_IA_64", "Intel Merced"),
51: ("EM_MIPS_X", "Stanford MIPS-X"),
52: ("EM_COLDFIRE", "Motorola Coldfire"),
53: ("EM_68HC12", "Motorola M68HC12"),
54: ("EM_MMA", "Fujitsu MMA Multimedia Accelerator"),
55: ("EM_PCP", "Siemens PCP"),
56: ("EM_NCPU", "Sony nCPU embedded RISC"),
57: ("EM_NDR1", "Denso NDR1 microprocessor"),
58: ("EM_STARCORE", "Motorola Start*Core processor"),
59: ("EM_ME16", "Toyota ME16 processor"),
60: ("EM_ST100", "STMicroelectronic ST100 processor"),
61: ("EM_TINYJ", "Advanced Logic Corp. Tinyj emb.fam"),
62: ("EM_X86_64", "AMD x86-64 architecture"),
63: ("EM_PDSP", "Sony DSP Processor"),
64: ("EM_PDP10", "Digital PDP-10"),
65: ("EM_PDP11", "Digital PDP-11"),
66: ("EM_FX66", "Siemens FX66 microcontroller"),
67: ("EM_ST9PLUS", "STMicroelectronics ST9+ 8/16 mc"),
68: ("EM_ST7", "STMicroelectronics ST7 8-bit mc"),
75: ("EM_VAX", "Digital VAX"),
76: ("EM_CRIS", "Axis Communications 32-bit emb.proc"),
80: ("EM_MMIX", "Donald Knuth's educational 64-bit proc"),
83: ("EM_AVR", "Atmel AVR 8-bit microcontroller"),
87: ("EM_V850", "NEC v850"),
88: ("EM_M32R", "Mitsubishi M32R"),
89: ("EM_MN10300", "Matsushita MN10300"),
90: ("EM_MN10200", "Matsushita MN10200"),
91: ("EM_PJ", "picoJava"),
92: ("EM_OPENRISC", "OpenRISC 32-bit embedded processor"),
94: ("EM_XTENSA", "Tensilica Xtensa Architecture"),
95: ("EM_VIDEOCORE", "Alphamosaic VideoCore"),
96: ("EM_TMM_GPP", "Thompson Multimedia General Purpose Proc"),
97: ("EM_NS32K", "National Semi. 32000"),
98: ("EM_TPC", "Tenor Network TPC"),
99: ("EM_SNP1K", "Trebia SNP 1000"),
100: ("EM_ST200", "STMicroelectronics ST200"),
101: ("EM_IP2K", "Ubicom IP2xxx"),
102: ("EM_MAX", "MAX processor"),
103: ("EM_CR", "National Semi. CompactRISC"),
104: ("EM_F2MC16", "Fujitsu F2MC16"),
105: ("EM_MSP430", "Texas Instruments msp430"),
106: ("EM_BLACKFIN", "Analog Devices Blackfin DSP"),
107: ("EM_SE_C33", "Seiko Epson S1C33 family"),
108: ("EM_SEP", "Sharp embedded microprocessor"),
109: ("EM_ARCA", "Arca RISC"),
110: ("EM_UNICORE", "PKU-Unity & MPRC Peking Uni. mc series"),
111: ("EM_EXCESS", "eXcess configurable cpu"),
112: ("EM_DXP", "Icera Semi. Deep Execution Processor"),
113: ("EM_ALTERA_NIOS2", "Altera Nios II"),
114: ("EM_CRX", "National Semi. CompactRISC CRX"),
115: ("EM_XGATE", "Motorola XGATE"),
116: ("EM_C166", "Infineon C16x/XC16x"),
117: ("EM_M16C", "Renesas M16C"),
118: ("EM_DSPIC30F", "Microchip Technology dsPIC30F"),
119: ("EM_CE", "Freescale Communication Engine RISC"),
120: ("EM_M32C", "Renesas M32C"),
131: ("EM_TSK3000", "Altium TSK3000"),
132: ("EM_RS08", "Freescale RS08"),
133: ("EM_SHARC", "Analog Devices SHARC family"),
134: ("EM_ECOG2", "Cyan Technology eCOG2"),
135: ("EM_SCORE7", "Sunplus S+core7 RISC"),
136: ("EM_DSP24", "New Japan Radio (NJR) 24-bit DSP"),
137: ("EM_VIDEOCORE3", "Broadcom VideoCore III"),
138: ("EM_LATTICEMICO32", "RISC for Lattice FPGA"),
139: ("EM_SE_C17", "Seiko Epson C17"),
140: ("EM_TI_C6000", "Texas Instruments TMS320C6000 DSP"),
141: ("EM_TI_C2000", "Texas Instruments TMS320C2000 DSP"),
142: ("EM_TI_C5500", "Texas Instruments TMS320C55x DSP"),
143: ("EM_TI_ARP32", "Texas Instruments App. Specific RISC"),
144: ("EM_TI_PRU", "Texas Instruments Prog. Realtime Unit"),
160: ("EM_MMDSP_PLUS", "STMicroelectronics 64bit VLIW DSP"),
161: ("EM_CYPRESS_M8C", "Cypress M8C"),
162: ("EM_R32C", "Renesas R32C"),
163: ("EM_TRIMEDIA", "NXP Semi. TriMedia"),
164: ("EM_QDSP6", "QUALCOMM DSP6"),
165: ("EM_8051", "Intel 8051 and variants"),
166: ("EM_STXP7X", "STMicroelectronics STxP7x"),
167: ("EM_NDS32", "Andes Tech. compact code emb. RISC"),
168: ("EM_ECOG1X", "Cyan Technology eCOG1X"),
169: ("EM_MAXQ30", "Dallas Semi. MAXQ30 mc"),
170: ("EM_XIMO16", "New Japan Radio (NJR) 16-bit DSP"),
171: ("EM_MANIK", "M2000 Reconfigurable RISC"),
172: ("EM_CRAYNV2", "Cray NV2 vector architecture"),
173: ("EM_RX", "Renesas RX"),
174: ("EM_METAG", "Imagination Tech. META"),
175: ("EM_MCST_ELBRUS", "MCST Elbrus"),
176: ("EM_ECOG16", "Cyan Technology eCOG16"),
177: ("EM_CR16", "National Semi. CompactRISC CR16"),
178: ("EM_ETPU", "Freescale Extended Time Processing Unit"),
179: ("EM_SLE9X", "Infineon Tech. SLE9X"),
180: ("EM_L10M", "Intel L10M"),
181: ("EM_K10M", "Intel K10M"),
183: ("EM_AARCH64", "ARM AARCH64"),
185: ("EM_AVR32", "Amtel 32-bit microprocessor"),
186: ("EM_STM8", "STMicroelectronics STM8"),
187: ("EM_TILE64", "Tileta TILE64"),
188: ("EM_TILEPRO", "Tilera TILEPro"),
189: ("EM_MICROBLAZE", "Xilinx MicroBlaze"),
190: ("EM_CUDA", "NVIDIA CUDA"),
191: ("EM_TILEGX", "Tilera TILE-Gx"),
192: ("EM_CLOUDSHIELD", "CloudShield"),
193: ("EM_COREA_1ST", "KIPO-KAIST Core-A 1st gen."),
194: ("EM_COREA_2ND", "KIPO-KAIST Core-A 2nd gen."),
195: ("EM_ARC_COMPACT2", "Synopsys ARCompact V2"),
196: ("EM_OPEN8", "Open8 RISC"),
197: ("EM_RL78", "Renesas RL78"),
198: ("EM_VIDEOCORE5", "Broadcom VideoCore V"),
199: ("EM_78KOR", "Renesas 78KOR"),
200: ("EM_56800EX", "Freescale 56800EX DSC"),
201: ("EM_BA1", "Beyond BA1"),
202: ("EM_BA2", "Beyond BA2"),
203: ("EM_XCORE", "XMOS xCORE"),
204: ("EM_MCHP_PIC", "Microchip 8-bit PIC(r)"),
210: ("EM_KM32", "KM211 KM32"),
211: ("EM_KMX32", "KM211 KMX32"),
212: ("EM_EMX16", "KM211 KMX16"),
213: ("EM_EMX8", "KM211 KMX8"),
214: ("EM_KVARC", "KM211 KVARC"),
215: ("EM_CDP", "Paneve CDP"),
216: ("EM_COGE", "Cognitive Smart Memory Processor"),
217: ("EM_COOL", "Bluechip CoolEngine"),
218: ("EM_NORC", "Nanoradio Optimized RISC"),
219: ("EM_CSR_KALIMBA", "CSR Kalimba"),
220: ("EM_Z80", "Zilog Z80"),
221: ("EM_VISIUM", "Controls and Data Services VISIUMcore"),
222: ("EM_FT32", "FTDI Chip FT32"),
223: ("EM_MOXIE", "Moxie processor"),
224: ("EM_AMDGPU", "AMD GPU"),
243: ("EM_RISCV", "RISC-V"),
247: ("EM_BPF", "Linux BPF -- in-kernel virtual machine"),
252: ("EM_CSKY", "C-SKY")
}
section_header = { section_header = {
"sh_name": { "sh_name": {
"32": "0x00", "64": "0x00", "size32": "4", "size64": "4", "field_name": "sh_name", "32": "0x00", "64": "0x00", "size32": "4", "size64": "4", "field_name": "sh_name",
@ -125,75 +292,286 @@ section_header = {
} }
section_header_types = { section_header_types = {
0: {"value": "0x0", "name": "SHT_NULL", "description": "Section header table entry unused"}, 0: ("SHT_NULL", "Section header table entry unused"),
1: {"value": "0x1", "name": "SHT_PROGBITS", "description": "Program data"}, 1: ("SHT_PROGBITS", "Program data"),
2: {"value": "0x2", "name": "SHT_SYMTAB", "description": "Symbol table"}, 2: ("SHT_SYMTAB", "Symbol table"),
3: {"value": "0x3", "name": "SHT_STRTAB", "description": "String table"}, 3: ("SHT_STRTAB", "String table"),
4: {"value": "0x4", "name": "SHT_RELA", "description": "Relocation entries with addends"}, 4: ("SHT_RELA", "Relocation entries with addends"),
5: {"value": "0x5", "name": "SHT_HASH", "description": "Symbol hash table"}, 5: ("SHT_HASH", "Symbol hash table"),
6: {"value": "0x6", "name": "SHT_DYNAMIC", "description": "Dynamic linking information"}, 6: ("SHT_DYNAMIC", "Dynamic linking information"),
7: {"value": "0x7", "name": "SHT_NOTE", "description": "Notes"}, 7: ("SHT_NOTE", "Notes"),
8: {"value": "0x8", "name": "SHT_NOBITS", "description": "Program space with no data (bss)"}, 8: ("SHT_NOBITS", "Program space with no data (bss)"),
9: {"value": "0x9", "name": "SHT_REL", "description": "Relocation entries, no addends"}, 9: ("SHT_REL", "Relocation entries, no addends"),
10: {"value": "0x0A", "name": "SHT_SHLIB", "description": "Reserved"}, 10: ("SHT_SHLIB", "Reserved"),
11: {"value": "0x0B", "name": "SHT_DYNSYM", "description": "Dynamic linker symbol table"}, 11: ("SHT_DYNSYM", "Dynamic linker symbol table"),
14: {"value": "0x0E", "name": "SHT_INIT_ARRAY", "description": "Array of constructors"}, 14: ("SHT_INIT_ARRAY", "Array of constructors"),
15: {"value": "0x0F", "name": "SHT_FINI_ARRAY", "description": "Array of destructors"}, 15: ("SHT_FINI_ARRAY", "Array of destructors"),
16: {"value": "0x10", "name": "SHT_PREINIT_ARRAY", "description": "Array of pre-constructors"}, 16: ("SHT_PREINIT_ARRAY", "Array of pre-constructors"),
17: {"value": "0x11", "name": "SHT_GROUP", "description": "Section group"}, 17: ("SHT_GROUP", "Section group"),
18: {"value": "0x12", "name": "SHT_SYMTAB_SHNDX", "description": "Extended section indices"}, 18: ("SHT_SYMTAB_SHNDX", "Extended section indices"),
19: {"value": "0x13", "name": "SHT_NUM", "description": "Number of defined types."}, 19: ("SHT_NUM", "Number of defined types.")
1610612736: {"value": "0x60000000", "name": "SHT_LOOS", "description": "Start OS-specific."},
1879048182: {"value": "0x6ffffff6", "name": "SHT_GNU_HASH", "description": "GNU-style hash table."}
} }
section_header_types_ex = {0x60000000: 'OS-specific',
0x70000000: 'Processor-specific',
0x80000000: 'Application-specific'}
st_info_values = { st_info_values = {
0: {"name": "STT_NOTYPE", "description": "Type is unspecified"}, 0: ("STT_NOTYPE", "Symbol type is unspecified"),
1: {"name": "STT_OBJECT", "description": "Data object (variable, array, etc.)"}, 1: ("STT_OBJECT", "Symbol is a data object"),
2: {"name": "STT_FUNC", "description": "Function or executable code"}, 2: ("STT_FUNC", "Symbol is a code object"),
3: {"name": "STT_SECTION", "description": "Associated with a section"}, 3: ("STT_SECTION", "Symbol associated with a section"),
4: {"name": "STT_FILE", "description": "Represents a file name"}, 4: ("STT_FILE", "Symbol's name is file name"),
5: {"name": "STT_COMMON", "description": "Common data object (uninit. storage)"}, 5: ("STT_COMMON", "Symbol is a common data object"),
6: {"name": "STT_TLS", "description": "Thread-local storage (TLS)"}, 6: ("STT_TLS", "Symbol is thread-local data object"),
7: {"name": "STT_NUM", "description": "Number of defined types"}, 7: ("STT_NUM", "Number of defined types"),
10: {"name": "STT_GNU_IFUNC", "description": "Indirect function (GNU extension)"}, 10: ("STT_GNU_IFUNC", "Symbol is indirect code object")
12: {"name": "STT_HIPROC", "description": "Processor-specific symbol type"},
} }
stb_values = { stb_values = {
0: {"name": "STB_LOCAL", "description": "Local, not visible outside the object file"}, 0: ("STB_LOCAL", "Local, not visible outside the object file"),
1: {"name": "STB_GLOBAL", "description": "Global, visible to all object files"}, 1: ("STB_GLOBAL", "Global, visible to all object files"),
2: {"name": "STB_WEAK", "description": "Weak, like global but with lower precedence"}, 2: ("STB_WEAK", "Weak, like global but with lower precedence"),
10: {"name": "STB_GNU_UNIQUE", "description": "Unique in the entire process (GNU extension)"}, 10: ("STB_GNU_UNIQUE", "Unique in the entire process (GNU extension)"),
12: {"name": "STB_HIPROC", "description": "Processor-specific binding type"}, 12: ("STB_HIPROC", "Processor-specific binding type")
} }
relocation_table_types = { relocation_table_types = {
0: {"name": "R_X86_64_NONE", "description": "No relocation"}, "EM_386": {
1: {"name": "R_X86_64_64", "description": "Direct 64-bit relocation"}, 0: ("R_386_NONE", 0, ""),
2: {"name": "R_X86_64_PC32", "description": "32-bit PC-relative relocation"}, 1: ("R_386_32", 32, "S + A"),
3: {"name": "R_X86_64_GOT32", "description": "32-bit Global Offset Table (GOT) entry"}, 2: ("R_386_PC32", 32, "S + A - P"),
4: {"name": "R_X86_64_PLT32", "description": "32-bit Procedure Linkage Table (PLT) entry"}, 3: ("R_386_GOT32", 32, "G + A"),
5: {"name": "R_X86_64_COPY", "description": "Copy data from shared object"}, 4: ("R_386_PLT32", 32, "L + A - P"),
6: {"name": "R_X86_64_GLOB_DAT", "description": "Set GOT entry to the address of a symbol"}, 5: ("R_386_COPY", 0, ""),
7: {"name": "R_X86_64_JUMP_SLOT", "description": "Set GOT entry to the address of a function (dynamic linking)"}, 6: ("R_386_GLOB_DAT", 32, "S"),
8: {"name": "R_X86_64_RELATIVE", "description": "Adjust relative to the load address"}, 7: ("R_386_JMP_SLOT", 32, "S"),
9: {"name": "R_X86_64_GOTPCREL", "description": "PC-relative address for GOT entry"}, 8: ("R_386_RELATIVE", 32, "B + A"),
10: {"name": "R_X86_64_32", "description": "32-bit absolute relocation"}, 9: ("R_386_GOTOFF", 32, "S + A - GOT"),
11: {"name": "R_X86_64_32S", "description": "32-bit signed absolute relocation"}, 10: ("R_386_GOTPC", 32, "GOT + A - P"),
12: {"name": "R_X86_64_16", "description": "16-bit absolute relocation"}, 11: ("R_386_32PLT", 32, "L + A"),
13: {"name": "R_X86_64_8", "description": "8-bit absolute relocation"} 20: ("R_386_16", 16, "S + A"),
21: ("R_386_PC16", 16, "S + A - P"),
22: ("R_386_8", 8, "S + A"),
23: ("R_386_PC8", 8, "S + A - P"),
38: ("R_386_SIZE32", 32, "Z + A")
},
"EM_X86_64": {
0: ("R_AMD64_NONE", 0, ""),
1: ("R_AMD64_64", 64, "S + A"),
2: ("R_AMD64_PC32", 32, "S + A - P"),
3: ("R_AMD64_GOT32", 32, "G + A"),
4: ("R_AMD64_PLT32", 32, "L + A - P"),
5: ("R_AMD64_COPY", 0, ""),
6: ("R_AMD64_GLOB_DAT", 64, "S"),
7: ("R_AMD64_JUMP_SLOT", 64, "S"),
8: ("R_AMD64_RELATIVE", 64, "B + A"),
9: ("R_AMD64_GOTPCREL", 32, "G + GOT + A - P"),
10: ("R_AMD64_32", 32, "S + A"),
11: ("R_AMD64_32S", 32, "S + A"),
12: ("R_AMD64_16", 16, "S + A"),
13: ("R_AMD64_PC16", 16, "S + A - P"),
14: ("R_AMD64_8", 8, "S + A"),
15: ("R_AMD64_PC8", 8, "S + A - P"),
24: ("R_AMD64_PC64", 64, "S + A - P"),
25: ("R_AMD64_GOTOFF64", 64, "S + A - GOT"),
26: ("R_AMD64_GOTPC32", 32, "GOT + A + P"),
32: ("R_AMD64_SIZE32", 32, "Z + A"),
33: ("R_AMD64_SIZE64", 64, "Z + A"),
},
"EM_ARM": {
0: ("R_ARM_NONE", 0, ""),
1: ("R_ARM_PC24", 24, "S - P + A"),
2: ("R_ARM_ABS32", 32, "S + A"),
3: ("R_ARM_REL32", 32, "S - P + A"),
4: ("R_ARM_PC13", 13, "S - P + A"),
5: ("R_ARM_ABS16", 16, "S + A"),
6: ("R_ARM_ABS12", 12, "S + A"),
7: ("R_ARM_THM_ABS5", 5, "S + A"),
8: ("R_ARM_ABS8", 8, "S + A"),
9: ("R_ARM_SBREL32", 32, "S - B + A"),
10: ("R_ARM_THM_PC22", 22, "S - P + A"),
11: ("R_ARM_THM_PC8", 8, "S - P + A"),
12: ("Reserved", 0, ""),
13: ("R_ARM_SWI24", 24, "S + A"),
14: ("R_ARM_THM_SWI8", 8, "S + A"),
15: ("R_ARM_XPC25", 25, ""),
16: ("R_ARM_THM_XPC22", 22, ""),
30: ("R_ARM_TLS_DESC", 0, ""),
32: ("R_ARM_ALU_PCREL_7_0", 7, "(S - P + A) & 0x000000FF"),
33: ("R_ARM_ALU_PCREL_15_8", 15, "(S - P + A) & 0x0000FF00"),
34: ("R_ARM_ALU_PCREL_23_15", 23, "(S - P + A) & 0x00FF0000"),
35: ("R_ARM_LDR_SBREL_11_0", 11, "(S - B + A) & 0x00000FFF"),
36: ("R_ARM_ALU_SBREL_19_12", 19, "(S - B + A) & 0x000FF000"),
37: ("R_ARM_ALU_SBREL_27_20", 27, "(S - B + A) & 0x0FF00000"),
38: ("R_ARM_RELABS32", 32, "S + A or S - P + A"),
39: ("R_ARM_ROSEGREL32", 32, "S - E + A"),
40: ("R_ARM_V4BX", 0, ""),
41: ("R_ARM_STKCHK", 0, ""),
42: ("R_ARM_THM_STKCHK", 0, ""),
},
"EM_AARCH64": {
0: ("R_AARCH64_NONE", 0, ""),
257: ("R_AARCH64_ABS64", 64, "S + A"),
258: ("R_AARCH64_ABS32", 32, "S + A"),
259: ("R_AARCH64_ABS16", 16, "S + A"),
260: ("R_AARCH64_PREL64", 64, "S + A - P"),
261: ("R_AARCH64_PREL32", 32, "S + A - P"),
262: ("R_AARCH64_PREL16", 16, "S + A - P"),
263: ("R_AARCH64_MOVW_UABS_G0", 16, "S + A"),
264: ("R_AARCH64_MOVW_UABS_G0_NC", 16, "S + A"),
265: ("R_AARCH64_MOVW_UABS_G1", 32, "S + A"),
266: ("R_AARCH64_MOVW_UABS_G1_NC", 32, "S + A"),
267: ("R_AARCH64_MOVW_UABS_G2", 48, "S + A"),
268: ("R_AARCH64_MOVW_UABS_G2_NC", 48, "S + A"),
269: ("R_AARCH64_MOVW_UABS_G3", 64, "S + A"),
270: ("R_AARCH64_MOVW_SABS_G0", 16, "S + A"),
271: ("R_AARCH64_MOVW_SABS_G1", 32, "S + A"),
272: ("R_AARCH64_MOVW_SABS_G2", 48, "S + A"),
273: ("R_AARCH64_LD_PREL_LO19", 19, "S + A - P"),
274: ("R_AARCH64_ADR_PREL_LO21", 21, "S + A - P"),
275: ("R_AARCH64_ADR_PREL_PG_HI21", 21, "Page(S+A) - Page(P)"),
276: ("R_AARCH64_ADR_PREL_PG_HI21_NC", 21, "Page(S+A) - Page(P)"),
277: ("R_AARCH64_ADD_ABS_LO12_NC", 12, "S + A"),
278: ("R_AARCH64_LDST8_ABS_LO12_NC", 12, "S + A"),
279: ("R_AARCH64_TSTBR14", 14, "S + A - P"),
280: ("R_AARCH64_CONDBR19", 19, "S + A - P"),
282: ("R_AARCH64_JUMP26", 26, "S + A - P"),
283: ("R_AARCH64_CALL26", 26, "S + A - P"),
284: ("R_AARCH64_LDST16_ABS_LO12_NC", 16, "S + A"),
285: ("R_AARCH64_LDST32_ABS_LO12_NC", 32, "S + A"),
286: ("R_AARCH64_LDST64_ABS_LO12_NC", 64, "S + A"),
287: ("R_AARCH64_MOVW_PREL_G0", 16, "S + A - P"),
288: ("R_AARCH64_MOVW_PREL_G0_NC", 16, "S + A - P"),
289: ("R_AARCH64_MOVW_PREL_G1", 32, "S + A - P"),
290: ("R_AARCH64_MOVW_PREL_G1_NC", 32, "S + A - P"),
291: ("R_AARCH64_MOVW_PREL_G2", 48, "S + A - P"),
292: ("R_AARCH64_MOVW_PREL_G2_NC", 48, "S + A - P"),
293: ("R_AARCH64_MOVW_PREL_G3", 64, "S + A - P"),
299: ("R_AARCH64_LDST128_ABS_LO12_NC", 128, "S + A"),
300: ("R_AARCH64_MOVW_GOTOFF_G0", 16, "G(GDAT(S+A)) - GOT"),
301: ("R_AARCH64_MOVW_GOTOFF_G0_NC", 16, "G(GDAT(S+A)) - GOT"),
302: ("R_AARCH64_MOVW_GOTOFF_G1", 32, "G(GDAT(S+A)) - GOT"),
303: ("R_AARCH64_MOVW_GOTOFF_G1_NC", 32, "G(GDAT(S+A)) - GOT"),
304: ("R_AARCH64_MOVW_GOTOFF_G2", 48, "G(GDAT(S+A)) - GOT"),
305: ("R_AARCH64_MOVW_GOTOFF_G2_NC", 48, "G(GDAT(S+A)) - GOT"),
306: ("R_AARCH64_MOVW_GOTOFF_G3", 64, "G(GDAT(S+A)) - GOT"),
307: ("R_AARCH64_GOTREL64", 64, "S + A - GOT"),
308: ("R_AARCH64_GOTREL32", 32, "S + A - GOT"),
309: ("R_AARCH64_GOT_LD_PREL19", 19, "G(GDAT(S+A)) - P"),
310: ("R_AARCH64_LD64_GOTOFF_LO15", 15, "G(GDAT(S+A)) - GOT"),
311: ("R_AARCH64_ADR_GOT_PAGE", 21, "Page(G(GDAT(S+A))) - Page(P)"),
312: ("R_AARCH64_LD64_GOT_LO12_NC", 12, "G(GDAT(S+A))"),
313: ("R_AARCH64_LD64_GOTPAGE_LO15", 15, "G(GDAT(S+A)) - Page(GOT)"),
},
"EM_MIPS": {
0: ("R_MIPS_NONE", 0, ""),
1: ("R_MIPS_16", 16, "S + A"),
2: ("R_MIPS_32", 32, "S + A"),
3: ("R_MIPS_REL32", 32, "A + S - P"),
4: ("R_MIPS_26", 26, "((A << 2) | (P & 0xF0000000)) + S"),
5: ("R_MIPS_HI16", 16, "((A + S) >> 16) & 0xFFFF"),
6: ("R_MIPS_LO16", 16, "(A + S) & 0xFFFF"),
7: ("R_MIPS_GPREL16", 16, "S + A - GP"),
8: ("R_MIPS_LITERAL", 16, ""),
9: ("R_MIPS_GOT16", 16, "G + A"),
10: ("R_MIPS_PC16", 16, "S + A - P"),
11: ("R_MIPS_CALL16", 16, "G + A"),
12: ("R_MIPS_GPREL32", 32, "S + A - GP"),
16: ("R_MIPS_SHIFT5", 5, ""),
17: ("R_MIPS_SHIFT6", 6, ""),
18: ("R_MIPS_64", 64, "S + A"),
19: ("R_MIPS_GOT_DISP", 16, "G + A - GP"),
20: ("R_MIPS_GOT_PAGE", 16, "(G + A - GP) >> 16"),
21: ("R_MIPS_GOT_OFST", 16, "(G + A - GP) & 0xFFFF"),
22: ("R_MIPS_GOT_HI16", 16, "((G + A) >> 16) & 0xFFFF"),
23: ("R_MIPS_GOT_LO16", 16, "(G + A) & 0xFFFF"),
24: ("R_MIPS_SUB", 64, "S - A"),
25: ("R_MIPS_INSERT_A", 0, ""),
26: ("R_MIPS_INSERT_B", 0, ""),
27: ("R_MIPS_DELETE", 0, ""),
28: ("R_MIPS_HIGHER", 16, "(A + S) >> 32"),
29: ("R_MIPS_HIGHEST", 16, "(A + S) >> 48"),
30: ("R_MIPS_SCN_DISP", 16, ""),
31: ("R_MIPS_REL16", 16, ""),
32: ("R_MIPS_ADD_IMMEDIATE", 16, ""),
33: ("R_MIPS_PJUMP", 26, ""),
34: ("R_MIPS_RELGOT", 32, ""),
35: ("R_MIPS_JALR", 0, ""),
36: ("R_MIPS_TLS_DTPMOD32", 32, "TLSMODULE"),
37: ("R_MIPS_TLS_DTPREL32", 32, "S + A - TLS_DTV_OFFSET"),
38: ("R_MIPS_TLS_DTPMOD64", 64, "TLSMODULE"),
39: ("R_MIPS_TLS_DTPREL64", 64, "S + A - TLS_DTV_OFFSET"),
40: ("R_MIPS_TLS_GD", 16, "G"),
41: ("R_MIPS_TLS_LDM", 16, "G"),
42: ("R_MIPS_TLS_DTPREL_HI16", 16, "((S + A - TLS_DTV_OFFSET) >> 16) & 0xFFFF"),
43: ("R_MIPS_TLS_DTPREL_LO16", 16, "(S + A - TLS_DTV_OFFSET) & 0xFFFF"),
44: ("R_MIPS_TLS_GOTTPREL", 16, "G"),
45: ("R_MIPS_TLS_TPREL32", 32, "S + A + TLSOFFSET"),
46: ("R_MIPS_TLS_TPREL64", 64, "S + A + TLSOFFSET"),
47: ("R_MIPS_TLS_TPREL_HI16", 16, "((S + A + TLSOFFSET) >> 16) & 0xFFFF"),
48: ("R_MIPS_TLS_TPREL_LO16", 16, "(S + A + TLSOFFSET) & 0xFFFF")
},
"EM_RISCV": {
0: ("R_RISCV_NONE", 0, ""),
1: ("R_RISCV_32", 32, "S + A"),
2: ("R_RISCV_64", 64, "S + A"),
3: ("R_RISCV_RELATIVE", 255, "B + A"),
4: ("R_RISCV_COPY", 0, ""),
5: ("R_RISCV_JUMP_SLOT", 255, "S"),
6: ("R_RISCV_TLS_DTPMOD32", 32, "TLSMODULE"),
7: ("R_RISCV_TLS_DTPMOD64", 64, "TLSMODULE"),
8: ("R_RISCV_TLS_DTPREL32", 32, "S + A - TLS_DTV_OFFSET"),
9: ("R_RISCV_TLS_DTPREL64", 64, "S + A - TLS_DTV_OFFSET"),
10: ("R_RISCV_TLS_TPREL32", 32, "S + A + TLSOFFSET"),
11: ("R_RISCV_TLS_TPREL64", 64, "S + A + TLSOFFSET"),
12: ("R_RISCV_TLSDESC", 0, "TLSDESC(S+A)"),
16: ("R_RISCV_BRANCH", 254, "S + A - P"),
17: ("R_RISCV_JAL", 248, "S + A - P"),
18: ("R_RISCV_CALL",246, "S + A - P"),
19: ("R_RISCV_CALL_PLT",246, "S + A - P"),
20: ("R_RISCV_GOT_HI20", 249, "G + GOT + A - P"),
21: ("R_RISCV_TLS_GOT_HI20", 249, ""),
22: ("R_RISCV_TLS_GD_HI20", 249, ""),
23: ("R_RISCV_PCREL_HI20", 249, "S + A - P"),
24: ("R_RISCV_PCREL_LO12_I", 251, "S - P"),
25: ("R_RISCV_PCREL_LO12_S", 250, "S - P"),
26: ("R_RISCV_HI20", 249, "S + A"),
27: ("R_RISCV_LO12_I", 251, "S + A"),
28: ("R_RISCV_LO12_S", 250, "S + A"),
29: ("R_RISCV_TPREL_HI20", 249, ""),
30: ("R_RISCV_TPREL_LO12_I", 251, ""),
31: ("R_RISCV_TPREL_LO12_S", 250, ""),
32: ("R_RISCV_TPREL_ADD", 0, ""),
33: ("R_RISCV_ADD8", 8, "V + S + A"),
34: ("R_RISCV_ADD16", 16, "V + S + A"),
35: ("R_RISCV_ADD32", 32, "V + S + A"),
36: ("R_RISCV_ADD64", 64, "V + S + A"),
37: ("R_RISCV_SUB8", 8, "V - S - A"),
38: ("R_RISCV_SUB16", 16, "V - S - A"),
39: ("R_RISCV_SUB32", 32, "V - S - A"),
40: ("R_RISCV_SUB64", 64, "V - S - A"),
41: ("R_RISCV_GOT32_PCREL", 32, "G + GOT + A - P"),
42: ("R_RISCV_Reserved", 0, ""),
43: ("R_RISCV_ALIGN", 0, ""),
44: ("R_RISCV_RVC_BRANCH", 253, "S + A - P"),
45: ("R_RISCV_RVC_JUMP", 252, "S + A - P"),
46: ("R_RISCV_Reserved", 0, ""),
51: ("R_RISCV_RELAX", 0, ""),
52: ("R_RISCV_SUB6", 6, "V - S - A"),
53: ("R_RISCV_SET6", 6, "S + A"),
54: ("R_RISCV_SET8", 8, "S + A"),
55: ("R_RISCV_SET16", 16, "S + A"),
56: ("R_RISCV_SET32", 32, "S + A"),
57: ("R_RISCV_32_PCREL", 32, "S + A - P"),
58: ("R_RISCV_IRELATIVE", 255, "ifunc_resolver(B + A)"),
59: ("R_RISCV_PLT32", 32, "S + A - P"),
60: ("R_RISCV_SET_ULEB128",247, "S + A"),
61: ("R_RISCV_SUB_ULEB128",247, "V - S - A"),
62: ("R_RISCV_TLSDESC_HI20", 249, "S + A - P"),
63: ("R_RISCV_TLSDESC_LOAD_LO12", 251, "S - P"),
64: ("R_RISCV_TLSDESC_ADD_LO12", 251, "S - P"),
65: ("R_RISCV_TLSDESC_CALL", 0, ""),
191: ("R_RISCV_VENDOR", 0, "")
} }
e_machine_dict = {
0x0001: {"name": "EM_386", "description": "Intel 80386 (x86)"},
0x0002: {"name": "EM_MIPS", "description": "MIPS (32-bit)"},
0x0003: {"name": "EM_SPARC", "description": "SPARC (32-bit)"},
0x0008: {"name": "EM_MIPS_RS3_LE", "description": "MIPS (Big Endian)"},
0x0014: {"name": "EM_ARM", "description": "ARM (32-bit)"},
0x0028: {"name": "EM_PPC", "description": "PowerPC (32-bit)"},
0x0032: {"name": "EM_S390", "description": "IBM S/390"},
0x003E: {"name": "EM_X86_64", "description": "x86-64 (64-bit)"},
0x00F3: {"name": "EM_AARCH64", "description": "ARM64 (64-bit)"},
0x0103: {"name": "EM_RISCV", "description": "RISC-V (32/64-bit)"}
} }

View File

@ -1,9 +1,11 @@
from typing import Any, Literal from typing import Any, Literal
table_format = Literal['text', 'markdown', 'html']
def generate_table(data: list[list[Any]], columns: list[str], def generate_table(data: list[list[Any]], columns: list[str],
right_adj_col: list[str] = [], right_adj_col: list[str] = [],
format: Literal['text', 'markdown', 'html'] = 'markdown'): format: table_format = 'markdown'):
if format == 'html': if format == 'html':
return generate_html_table(data, columns, right_adj_col) return generate_html_table(data, columns, right_adj_col)
elif format == 'markdown': elif format == 'markdown':