3 ## This file is part of the sigrok-util project.
5 ## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
7 ## This program is free software; you can redistribute it and/or modify
8 ## it under the terms of the GNU General Public License as published by
9 ## the Free Software Foundation; either version 3 of the License, or
10 ## (at your option) any later version.
12 ## This program is distributed in the hope that it will be useful,
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ## GNU General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
23 from getopt
import getopt
28 f
= open(filename
, 'rb')
29 if f
.read(2) != b
'MZ':
30 raise Exception("MZ signature not found.")
35 pe_ptr
= struct
.unpack("<L", f
.read(4))[0]
37 if f
.read(4) != b
'\x50\x45\x00\x00':
38 raise Exception("PE signature not found.")
41 sections
.append(['header', 324, 0])
42 num_sections
= struct
.unpack("<H", f
.read(2))[0]
45 symboltable_address
= struct
.unpack("<L", f
.read(4))[0]
46 num_symbols
= struct
.unpack("<L", f
.read(4))[0]
47 optheader_size
= struct
.unpack("<H", f
.read(2))[0]
48 # skip past PE header and PE optional header
49 f
.seek(f
.tell() + 2 + optheader_size
)
51 for i
in range(num_sections
):
52 name
= f
.read(8).decode('ascii', errors
='ignore').strip('\x00')
53 # skip past Misc and VirtualAddress
56 size
= struct
.unpack("<L", f
.read(4))[0]
58 ptr
= struct
.unpack("<L", f
.read(4))[0]
59 # skip to next section header
61 sections
.append([name
, size
, ptr
])
64 addr
= symboltable_address
65 stringtable_address
= symboltable_address
+ num_symbols
* 18
66 for i
in range(num_symbols
):
69 symaddr
= struct
.unpack("<L", f
.read(4))[0]
70 # skip SectionNumber and Type
71 symtype
= struct
.unpack("B", f
.read(1))[0]
73 if tmp
[:4] == b
'\x00\x00\x00\x00':
74 # symbol name is in the string table
75 straddr
= stringtable_address
+ struct
.unpack("<l", tmp
[4:])[0]
78 name
= tmpname
[:tmpname
.find(b
'\x00')]
81 name
= name
.decode('ascii', errors
='ignore').strip('\x00')
82 # need IMAGE_SYM_CLASS_EXTERNAL
87 if i
!= 0 and symbols
[-1][2] is not None and symaddr
> symbols
[-1][1]:
88 symbols
[-1][2] = symaddr
- symbols
[-1][1]
89 symbols
.append([name
, symaddr
, size
])
94 return sections
, symbols
97 def list_all(filename
):
98 sections
, symbols
= parse(filename
)
100 print("Sections:\n Name Size\t Position")
102 for name
, size
, address
in sections
:
103 print("%-3d %-8s %5d\t 0x%.8x" % (cnt
, name
, size
, address
))
106 print("\nSymbol table:\n Address Size Symbol")
107 for symbol
, address
, size
in symbols
:
109 sizestr
= "%5d" % size
112 print("0x%.8x %s %-8s" % (address
, sizestr
, symbol
))
116 def extract_symbol(filename
, symbol
):
117 sections
, symbols
= parse(filename
)
121 for symbolname
, address
, size
in symbols
:
122 if symbolname
== symbol
:
124 raise Exception("symbol %s found, but has unknown size")
125 f
= open(filename
, 'rb')
129 if len(data
) != size
:
130 raise Exception("short file")
134 raise Exception("symbol %s not found" % symbol
)
141 print("usage: parsepe.py [-s <symbol>] <-l|-x> <filename>")
142 print(" -l list all sections and symbols in file")
143 print(" -x extract symbol from file (specify symbol name with -s)")
151 if __name__
== '__main__':
152 filename
= symbol
= mode
= None
153 opts
, args
= getopt(sys
.argv
[1:], 's:lx')
154 for opt
, arg
in opts
:
164 if mode
is None and symbol
is None:
171 elif mode
== 'extract':
173 raise Exception("specify a symbol to extract")
174 data
= extract_symbol(filename
, symbol
)
175 outfile
= os
.path
.splitext(filename
)[0] + symbol
176 open(outfile
, 'wb').write(data
)
177 print("saved %d bytes to %s" % (len(data
), outfile
))
179 raise Exception("specify -l or -x")
180 except Exception as e
:
181 print("Error: %s" % str(e
))