From 1a516a3eb2e159fba1f9ef05686f36de80c899cf Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Thu, 22 Dec 2011 15:22:00 +0200 Subject: [PATCH] documentation fixes + new examples --- elftools/elf/relocation.py | 2 + examples/dwarf_die_tree.py | 73 +++++++++++++++++++++++++++++ examples/elf_low_high_api.py | 74 ++++++++++++++++++++++++++++++ examples/elf_relocations.py | 46 +++++++++++++++++++ examples/elfclass_address_size.py | 11 +++-- examples/examine_dwarf_info.py | 57 +++++++++++++++++++++++ examples/sample_exe64.elf | Bin 0 -> 12333 bytes scripts/readelf.py | 6 ++- 8 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 examples/dwarf_die_tree.py create mode 100644 examples/elf_low_high_api.py create mode 100644 examples/elf_relocations.py create mode 100644 examples/examine_dwarf_info.py create mode 100644 examples/sample_exe64.elf diff --git a/elftools/elf/relocation.py b/elftools/elf/relocation.py index cc90032..acb2da2 100644 --- a/elftools/elf/relocation.py +++ b/elftools/elf/relocation.py @@ -44,6 +44,8 @@ class Relocation(object): class RelocationSection(Section): + """ ELF relocation section. Serves as a collection of Relocation entries. + """ def __init__(self, header, name, stream, elffile): super(RelocationSection, self).__init__(header, name, stream) self.elffile = elffile diff --git a/examples/dwarf_die_tree.py b/examples/dwarf_die_tree.py new file mode 100644 index 0000000..5633d59 --- /dev/null +++ b/examples/dwarf_die_tree.py @@ -0,0 +1,73 @@ +#------------------------------------------------------------------------------- +# elftools example: dwarf_die_tree.py +# +# In the .debug_info section, Dwarf Information Entries (DIEs) form a tree. +# pyelftools provides easy access to this tree, as demonstrated here. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from __future__ import print_function +import sys +from elftools.elf.elffile import ELFFile + + +def process_file(filename): + print('Processing file:', filename) + with open(filename) as f: + elffile = ELFFile(f) + + if not elffile.has_dwarf_info(): + print(' file has no DWARF info') + return + + # get_dwarf_info returns a DWARFInfo context object, which is the + # starting point for all DWARF-based processing in pyelftools. + dwarfinfo = elffile.get_dwarf_info() + + for CU in dwarfinfo.iter_CUs(): + # DWARFInfo allows to iterate over the compile units contained in + # the .debug_info section. CU is a CompileUnit object, with some + # computed attributes (such as its offset in the section) and + # a header which conforms to the DWARF standard. The access to + # header elements is, as usual, via item-lookup. + print(' Found a compile unit at offset %s, length %s' % ( + CU.cu_offset, CU['unit_length'])) + + # Start with the top DIE, the root for this CU's DIE tree + top_DIE = CU.get_top_DIE() + print(' Top DIE with tag=%s' % top_DIE.tag) + + # Each DIE holds an OrderedDict of attributes, mapping names to + # values. Values are represented by AttributeValue objects in + # elftools/dwarf/die.py + # We're interested in the DW_AT_name attribute. Note that its value + # is usually a string taken from the .debug_string section. This + # is done transparently by the library, and such a value will be + # simply given as a string. + name_attr = top_DIE.attributes['DW_AT_name'] + print(' name=%s' % name_attr.value) + + # Display DIEs recursively starting with top_DIE + die_info_rec(top_DIE) + + +def die_info_rec(die, indent_level=' '): + """ A recursive function for showing information about a DIE and its + children. + """ + print(indent_level + 'DIE tag=%s' % die.tag) + child_indent = indent_level + ' ' + for child in die.iter_children(): + die_info_rec(child, child_indent) + + +if __name__ == '__main__': + for filename in sys.argv[1:]: + process_file(filename) + + + + + + diff --git a/examples/elf_low_high_api.py b/examples/elf_low_high_api.py new file mode 100644 index 0000000..43f9880 --- /dev/null +++ b/examples/elf_low_high_api.py @@ -0,0 +1,74 @@ +#------------------------------------------------------------------------------- +# elftools example: elf_low_high_api.py +# +# A simple example that shows some usage of the low-level API pyelftools +# provides versus the high-level API. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from __future__ import print_function +import sys +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection + + +def process_file(filename): + print('Processing file:', filename) + with open(filename) as f: + section_info_lowlevel(f) + f.seek(0) + section_info_highlevel(f) + + +def section_info_lowlevel(stream): + print('Low level API...') + # We'll still be using the ELFFile context object. It's just too + # convenient to give up, even in the low-level API demonstation :-) + elffile = ELFFile(stream) + + # The e_shnum ELF header field says how many sections there are in a file + print(' %s sections' % elffile['e_shnum']) + + # We need section #40 + section_offset = elffile['e_shoff'] + 40 * elffile['e_shentsize'] + + # Parse the section header using structs.Elf_Shdr + stream.seek(section_offset) + section_header = elffile.structs.Elf_Shdr.parse_stream(stream) + + # Some details about the section. Note that the section name is a pointer + # to the object's string table, so it's only a number here. To get to the + # actual name one would need to parse the string table section and extract + # the name from there (or use the high-level API!) + print(' Section name: %s, type: %s' % ( + section_header['sh_name'], section_header['sh_type'])) + + +def section_info_highlevel(stream): + print('High level API...') + elffile = ELFFile(stream) + + # Just use the public methods of ELFFile to get what we need + print(' %s sections' % elffile.num_sections()) + section = elffile.get_section(40) + + # A section type is in its header, but the name was decoded and placed in + # a public attribute. + print(' Section name: %s, type: %s' %( + section.name, section['sh_type'])) + + # But there's more... If this section is a symbol table section (which is + # the case in the sample ELF file that comes with the examples), we can + # get some more information about it. + if isinstance(section, SymbolTableSection): + print(" It's a symbol section with %s symbols" % section.num_symbols()) + print(" The name of symbol #60 is: %s" % ( + section.get_symbol(60).name)) + + +if __name__ == '__main__': + for filename in sys.argv[1:]: + process_file(filename) + + diff --git a/examples/elf_relocations.py b/examples/elf_relocations.py new file mode 100644 index 0000000..a09f014 --- /dev/null +++ b/examples/elf_relocations.py @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------------- +# elftools example: elf_relocations.py +# +# An example of obtaining a relocation section from an ELF file and examining +# the relocation entries it contains. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from __future__ import print_function +import sys +from elftools.elf.elffile import ELFFile +from elftools.elf.relocation import RelocationSection + + +def process_file(filename): + print('Processing file:', filename) + with open(filename) as f: + elffile = ELFFile(f) + + # Read the .rela.dyn section from the file, by explicitly asking + # ELFFile for this section + reladyn_name = '.rela.dyn' + reladyn = elffile.get_section_by_name(reladyn_name) + + if not isinstance(reladyn, RelocationSection): + print(' The file has no %s section' % reladyn_name) + + print(' %s section with %s relocations' % ( + reladyn_name, reladyn.num_relocations())) + + for reloc in reladyn.iter_relocations(): + # Use the Relocation's object ability to pretty-print itself to a + # string to examine it + print(' ', reloc) + + # Relocation entry attributes are available through item lookup + print(' offset = %s' % reloc['r_offset']) + + +if __name__ == '__main__': + for filename in sys.argv[1:]: + process_file(filename) + + + diff --git a/examples/elfclass_address_size.py b/examples/elfclass_address_size.py index e131496..21c839c 100644 --- a/examples/elfclass_address_size.py +++ b/examples/elfclass_address_size.py @@ -7,6 +7,7 @@ # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- +from __future__ import print_function import sys from elftools.elf.elffile import ELFFile @@ -14,13 +15,17 @@ from elftools.elf.elffile import ELFFile def process_file(filename): with open(filename) as f: elffile = ELFFile(f) - print '%s: elfclass is %s' % (filename, elffile.elfclass) + # elfclass is a public attribute of ELFFile, read from its header + print('%s: elfclass is %s' % (filename, elffile.elfclass)) if elffile.has_dwarf_info(): dwarfinfo = elffile.get_dwarf_info() for CU in dwarfinfo.iter_CUs(): - print ' CU at offset 0x%x. address_size is %s' % ( - CU.cu_offset, CU['address_size']) + # cu_offset is a public attribute of CU + # address_size is part of the CU header + print(' CU at offset 0x%x. address_size is %s' % ( + CU.cu_offset, CU['address_size'])) + if __name__ == '__main__': for filename in sys.argv[1:]: diff --git a/examples/examine_dwarf_info.py b/examples/examine_dwarf_info.py new file mode 100644 index 0000000..ba712dd --- /dev/null +++ b/examples/examine_dwarf_info.py @@ -0,0 +1,57 @@ +#------------------------------------------------------------------------------- +# elftools example: examine_dwarf_info.py +# +# An example of examining information in the .debug_info section of an ELF file. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from __future__ import print_function +import sys +from elftools.elf.elffile import ELFFile + + +def process_file(filename): + print('Processing file:', filename) + with open(filename) as f: + elffile = ELFFile(f) + + if not elffile.has_dwarf_info(): + print(' file has no DWARF info') + return + + # get_dwarf_info returns a DWARFInfo context object, which is the + # starting point for all DWARF-based processing in pyelftools. + dwarfinfo = elffile.get_dwarf_info() + + for CU in dwarfinfo.iter_CUs(): + # DWARFInfo allows to iterate over the compile units contained in + # the .debug_info section. CU is a CompileUnit object, with some + # computed attributes (such as its offset in the section) and + # a header which conforms to the DWARF standard. The access to + # header elements is, as usual, via item-lookup. + print(' Found a compile unit at offset %s, length %s' % ( + CU.cu_offset, CU['unit_length'])) + + # The first DIE in each compile unit describes it. + top_DIE = CU.get_top_DIE() + print(' Top DIE with tag=%s' % top_DIE.tag) + + # Each DIE holds an OrderedDict of attributes, mapping names to + # values. Values are represented by AttributeValue objects in + # elftools/dwarf/die.py + # We're interested in the DW_AT_name attribute. Note that its value + # is usually a string taken from the .debug_string section. This + # is done transparently by the library, and such a value will be + # simply given as a string. + name_attr = top_DIE.attributes['DW_AT_name'] + print(' name=%s' % name_attr.value) + +if __name__ == '__main__': + for filename in sys.argv[1:]: + process_file(filename) + + + + + diff --git a/examples/sample_exe64.elf b/examples/sample_exe64.elf new file mode 100644 index 0000000000000000000000000000000000000000..ccfa6ae0f448b64e14d34cf719c37828534e1095 GIT binary patch literal 12333 zcmeHNeQ;Y>mA~&j%a&usmScyeNg!&g(6o)8?KBMzP1EN%PNYGnmIWLqFh z9(|-qDbT@fLAarA`P>}_I?L=#VTYOQ@DD80#o2UeyIp2j=yXe$flQ!a=*OgmLKtYx z@7#Bf^z**t-v3M=+#YGQpJ1F=Y>llD%rMRMMf3lS2qh zg$PNWaFn&KQ?j5(WrAso@?)K%j3btCmcm&I$Mg~97*nnv)s3EURo=L6fg|1`B5s#) zm69%nLoXDQln$tR1X?W;gLi0HazZd|QT%&=QxGNj^Mw68tn4*wmt|EyrivB)ne^n2 z?fsc#UnZR`9q&6nw4-mwcC(N(x5;`3VV-pN-!dT`;dUf{ssD(MmBvQtAq7pW(n;2f zhsFlsK6&W7kDj~jQ_+8V{HuK@fA#vw_UJPoqB1GJ(oIN{%>96U%YksA2HNW(Thl-; zYJ|B`<>0pap%6uk^gWd3pgnU(9-1VUnEb1&kq zO%_tb&rlh^JiD^8LJ10kFGtJ&dq<>vE;9eK^M}TxPb`IemWVuYdO(sVUTU$#^0xu_ z&Eg{2iY)lP(h(Ao`<9CO%J-zHMR%BplwTMl#d~g8f}SYd^o;?$GLeO~|4y*JEySF@ zU_?&dx)Ry>d|`9frhCYb$jLogr0n|)lvaBGOKL5w{TM-ZKA%7L9bW-Sjm#Z+>de&C zl-afEUV@2<$ovht_7DmvzffHN4HA)W!EX=2P_%sJso|BMQvIJgv$#mUl|S^yNV#-A zvM_qS{GSWHwJ7#vi(d8xkXZ1wA~r_;R}(IeLwJrMC{}Z z|3jpl44;i5b2(NnhR;XJw};U>FAc@6dSkf!X0-fzeHOMDBaJxN-3R z$*)-XT&(=c-tzB;S9*UEnLndNcD|VZRb=7zFq%3O4#pOe;dL>jLa~KncuQ>I?(hJb zVTe7fv^P2?0zV@27gmawev78Hu1$N<81pas(N7BoWt3i3E$H;+@(P?({W^=RT}bz$>x-aa&<@$xL^Ju2^K11e+5uw-hr;xAx3NrCqG6i(?D5%Kz)D>K2j8*=|7LdH=AiTa+zU$r$HGMLQH-r|4Qmnb28*!m`>|^B#lsd0#^NY6_P)L_DhO zvwTtUewEMob`Ov3imcC^(nq^VUQ>GK6+ff$mH6*Y_`K>h^hy&ydZ3sq%-y+P>>n9< zcWBGl#Mo#kMn}D?Lfg%2&F!Hh(}_gicKh1C$$UJUm8xEUq>>N_5yGPja^exB`tZo}9PLA=Gr36+A$H)=1sNW|b2B(~08A80 z_Eb8X7U^0UL`6u1DBw{|0we-AiK3?2UpP@nrsfL$I91y?Wv4Pz{qn$Rj*0$KA>Uuf zC;I2&i4Vl5Q-%IL6Vce-{%JaW_H8o<2hG8L_&_J<(C}CY$Ik(CKxp@TOq!+f?$@LcYw@=s zdk!hzt%$Ts@1wZg@V8n>;40<46n_DaE^NfgmAlM@I0cq_`x4cQA16iaNyM72QD=D- zAd;PE;0Oa9QqdpE82>7{W0E^6S{xUB{<|UY`9F%d)p4@zKS)uQ3@6vAGq%`@e$mC# z$W#9P5=m+*9$nv5{+)(Q)!g_lrJub~N@P2+S?%p8PPG=oDQVrGsQHNJeA?Amw)d29b9CD->(p0Wx)i!w9Wg1Y5hc zHJahy;NR@;p~0ecYnwZJI*iT@os<)7h0(C+=-3SrMvY41C2w((=$Y-p=zMp_^&Qck z8v{Bf`qp=fD9uA$l;2g9sofZGw66?Ad&q*-szKTCRSKaZRN)5f__|=7%4@B<(dIQ- zvDL)ww^d57E!z}Tcce4qzT3yDhj^8^nmQWAUv&Z9)}c*6whA)8(-Nf8!JY@423f6X z(H^R7=VfS}uC>~g0pfx_*<9V#0&fiL3P6LVVqKo5HSG_btI>V(!k2om;ar0$if*?s z*+2zO={!RjOF}b(=I+aO$HGQusC4Z35loVrc7-(XcEoiC1WkK*yD88um@epMtzM00 z02$hKe#d*h=D+D79oG`t!xH$uMnE|oI(Ly+kJNV7bB3$QFQ_rEY3q$UUNgGCXyl$Xy8T5Xx6A0BGI9ru&Rs{o_Qb>b74S;B z+l!d?MrelPL3O7=8FZ&Xfh%*3!&a_En&C)3gok}`77FLSm*hNAlvR1&YmrPYI~^)z z3+d@>DjA}gxiFK<7i&dtc@1%}RElSntXN3Q#PdQLB`sQWM&9cFAfBH-Ci;uBbN#8w zR5qE)7o61<@`SVC7Sea6?4n3zkIlJPSGkh9y3)2uV#o9O_zCC!RS*&ommC({Wylp; zwV~7hV6ZXpJKc)6TV+BPN}}=)HtI)Q9-FaSQT53dJm&$d7+?HK2110;@ef~gNkZmtdge^^iosU;t;{5 z(h^J|>JYh4qNJtx5k>2WSvWCUj86))P|Q1YhEo`5sr;NUv$m2a%c2CF8}oFjF)3R6ahNvS*UOGAGPLF^8dTCLQwr1Ts-(d^Vkc!5oS~WXiIg zawZGVPUL21Q(4Tx*ms);4~FlB-5uJiR%zJ!1b) z=@vLT4@)B0KG~pvjf)Ii&Ova$#TkY*blqM89V>8d^ z>^X%GIdJK>+kYjNyJ%`l#xEL{%vw}1B^VW{nJN{13c*ZgRFCIMK>s+8gjX-sF z2e!{Ld4K`K-&Xlx=vNKm)n}gR*MX(_bN}&o@qogI*^r`)WASMu-1vc3OJ)ryJhiVo zaR0OHX(R}*n%nh10!PE!US9n7J$U-kNnwj>xW9z|A#~mL=`$yVA%*wa^YTB2E>)HN z=X)Xkf5RhGI0ECCvR}VIp4&cuuRhx)VHKRi)tB><2haC%%L*T2prUM_>FXZ6KX_DX z`jvyd3de+T%>Mxil5zb*3cpd|xt^@=#Z%>}{sXL_DC5;Is^qHXlo%5BG{Il44DYNU zorD*^QQh--#Z&+c zc>o?(OfT(UN7UK=&hA1|aw+P5##`CVD`-nNKWS6m{Qr1_wcya#d}<87;F zype~E^l7@#@NXpgqmw((`Aie_MomEqqIYYoQvV~|U`K1=Fx)U2I<0EI^F`F~C1 z=OEYg`uE}j8Pa=2ugCv(YN!Tsxo^?y-^b0+58+PO`+f~Tz6R|XQuX3B$5L|dyhQto zZj{5{aCqMzgFHmOdcu(=@*L!AaGB?w-%3*MDFp1NA@9bI=RLOjWypgK>UE0r_4OjC z#t)bHn3S&-^k+$T_;1Lm9lZCx&&%>(UD@a<=jTd3;E})BME^BazW1K`cT(P9y`cLq z+|?7I>n|h|@l3|`r&y857YoG_{xg}th3m-p!NYbeIyR2~%G&nc8t%Y|D=V3^>Dy{N zW6O&&J6<|2a0xb-NflE`bI0IyI|XIf>Ev;6I|hYw*On~J&Yoa9qqpppX7(K(zIoJU zj?8enYDM14Nh|c}!F`*&KX!1>aLhiqZ{OJHxII3+CpJpHQ;pRfvvZg163Fi*!rpt^ zEyFiQM+DvDsf%duM`0zFpOHO(CAJS7vk#}H(*;~_j%4D60xt8MFUfU(Ew(K8e~UeL v^R``MKUv7xGx2OPLl@$*1Gq8d|CQ-;HPr-}xOil*WerpEK2m=Ac2xcZDyqhn literal 0 HcmV?d00001 diff --git a/scripts/readelf.py b/scripts/readelf.py index 051a21a..c133d53 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -756,8 +756,10 @@ def main(stream=None): action='store', dest='show_string_dump', metavar='', help='Dump the contents of section as strings') optparser.add_option('--debug-dump', - action='store', dest='debug_dump_what', metavar='
', - help='Display the contents of DWARF debug sections') + action='store', dest='debug_dump_what', metavar='', + help=( + 'Display the contents of DWARF debug sections. can ' + + 'one of {info,decodedline,frames,frames-interp}')) options, args = optparser.parse_args() -- 2.30.2