Created
December 26, 2022 22:38
-
-
Save olofk/c1741593970df7ea2104d42bd64d7c8d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from elftools.dwarf.descriptions import describe_form_class | |
from elftools.elf.elffile import ELFFile | |
def decode_funcname(dwarfinfo, address): | |
# Go over all DIEs in the DWARF information, looking for a subprogram | |
# entry with an address range that includes the given address. Note that | |
# this simplifies things by disregarding subprograms that may have | |
# split address ranges. | |
for CU in dwarfinfo.iter_CUs(): | |
for DIE in CU.iter_DIEs(): | |
try: | |
if DIE.tag == 'DW_TAG_subprogram': | |
lowpc = DIE.attributes['DW_AT_low_pc'].value | |
# DWARF v4 in section 2.17 describes how to interpret the | |
# DW_AT_high_pc attribute based on the class of its form. | |
# For class 'address' it's taken as an absolute address | |
# (similarly to DW_AT_low_pc); for class 'constant', it's | |
# an offset from DW_AT_low_pc. | |
highpc_attr = DIE.attributes['DW_AT_high_pc'] | |
highpc_attr_class = describe_form_class(highpc_attr.form) | |
if highpc_attr_class == 'address': | |
highpc = highpc_attr.value | |
elif highpc_attr_class == 'constant': | |
highpc = lowpc + highpc_attr.value | |
else: | |
print('Error: invalid DW_AT_high_pc class:', | |
highpc_attr_class) | |
continue | |
if lowpc <= address < highpc: | |
return (DIE.attributes['DW_AT_name'].value, lowpc, highpc) | |
except KeyError: | |
continue | |
return None | |
if __name__ == '__main__': | |
with open(sys.argv[1], 'rb') as elf, open(sys.argv[2], 'rb') as trace: | |
elffile = ELFFile(elf) | |
dwarfinfo = elffile.get_dwarf_info() | |
visited = {} | |
adr_table = {-1 : ''} | |
adr = trace.read(4) | |
last_adr = -1 | |
while adr: | |
address = int.from_bytes(adr, byteorder='little') | |
if not address in adr_table: | |
rv = decode_funcname(dwarfinfo, address) | |
if rv: | |
(name, lo, hi) = rv | |
for i in range(lo, hi, 4): | |
adr_table[i] = name.decode('utf-8') | |
else: | |
adr_table[address] = "" | |
func_name = adr_table[address] | |
if func_name != adr_table[last_adr]: | |
print(adr_table[address]) | |
if not func_name in visited: | |
visited[func_name] = 0 | |
visited[func_name] += 1 | |
adr = trace.read(4) | |
last_adr = address | |
print(visited) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am not familiar with dwarf, but I wrote myself a simplistic RISCV profiler based on execution over rv8 simulator https://github.com/bat52/rv8_prof