Skip to content

Instantly share code, notes, and snippets.

@olofk
Created December 26, 2022 22:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olofk/c1741593970df7ea2104d42bd64d7c8d to your computer and use it in GitHub Desktop.
Save olofk/c1741593970df7ea2104d42bd64d7c8d to your computer and use it in GitHub Desktop.
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)
@bat52
Copy link

bat52 commented Jan 10, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment