2 # Copyright 2008, Google Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 """discmp.py - compare disassembler output
34 This script compares output from the Native Client decoder to output
35 from GNU objdump to make sure they agree on instruction lengths. It
36 returns a zero status on success and non-zero on failure.
39 discmp.py PLATFORM_BASE=<platform_base> <fileordir> <fileordir>
41 discmp.py PLATFORM_BASE=/home/who/proj/nacl/googleclient/native_client/scons-out/dbg-linux ncv/testdata/hanoi
52 %s PLATFORM_BASE=<platform_base> <fileordir> <fileordir>
55 %s PLATFORM_BASE=/home/who/proj/nacl/googleclient/native_client/scons-out/dbg-linux ncv/testdata/hanoi
57 Commonly this installer will be invoked from hammer as:
59 In this case hammer will take care of the command line args.
60 """ % (sys
.argv
[0], sys
.argv
[0]))
63 def FindBinaries(PlatformBase
):
64 ncdis
= os
.path
.join(PlatformBase
, "staging", "ncdis")
65 # Someday if nacl-objdump gets more permissive we can use it
66 # objdump = os.path.join(nacl.SDK_BASE, "bin", "nacl-objdump")
67 objdump
= "/usr/bin/objdump"
68 if not os
.path
.isfile(ncdis
):
69 print "Error: could not find", ncdis
71 if not os
.path
.isfile(objdump
):
72 print "Error: could not find", objdump
76 class DisFile(object):
77 """Processes variants of disassembler output from various sources,
78 providing a list of instruction lengths, based on addresses."""
80 def __init__(self
, stream
):
86 # note we ignore lines that have only continuation bytes;
88 self
.dislinefmt
= re
.compile("\s*([0-9a-f]+):\t(.*\t+.*)")
89 self
.data16fmt
= re
.compile("\s*([0-9a-f]+):\s+66\s+data16")
90 self
.waitfmt
= re
.compile("\s*([0-9a-f]+):\s+9b\s+[f]?wait")
92 def NextDisInst(self
):
94 line
= self
.fd
.readline()
95 if line
== "": return 0, None
96 match
= self
.data16fmt
.match(line
)
99 line
= self
.fd
.readline()
100 match
= self
.dislinefmt
.match(line
)
101 return (int(addr
, 16),
102 " " + addr
+ ":\t60 " + match
.group(2) + "\n")
103 match
= self
.waitfmt
.match(line
)
105 addr
= match
.group(1)
106 line
= self
.fd
.readline()
107 match
= self
.dislinefmt
.match(line
)
108 return (int(addr
, 16),
109 " " + addr
+ ":\t9b " + match
.group(2) + "\n")
110 match
= self
.dislinefmt
.match(line
)
112 return int(match
.group(1), 16), line
115 if self
.lastaddr
is None:
116 self
.lastaddr
, self
.lastline
= self
.NextDisInst()
118 self
.lastaddr
= self
.thisaddr
119 self
.lastline
= self
.thisline
120 self
.thisaddr
, self
.thisline
= self
.NextDisInst()
121 if self
.thisline
is None:
122 # don't know how long the last line was, so just return 1
123 return (1, self
.lastline
)
124 if self
.lastline
is None:
127 return (self
.thisaddr
- self
.lastaddr
, self
.lastline
)
129 def IsElfBinary(fname
):
131 iselfbinary
= fd
.readline().startswith("\x7fELF")
135 def DoOneFile(fname
, ncdis
, objdump
):
136 if not IsElfBinary(fname
):
137 print("Error:", fname
, "is not an ELF binary\nContinuing...")
139 df1
= DisFile(os
.popen(objdump
+ " -dz " + fname
))
140 df2
= DisFile(os
.popen(ncdis
+ " " + fname
))
144 len1
, line1
= df1
.NextInst()
145 len2
, line2
= df2
.NextInst()
146 if line1
is None: break
147 if line2
is None: break
149 sys
.stdout
.write("ERROR: inst length mistmatch %d != %d\n" %
151 sys
.stdout
.write(line1
)
152 sys
.stdout
.write(line2
)
155 sys
.stdout
.write("ERROR: disasm output is different lengths\n")
157 sys
.stdout
.write("%s: %d instructions; 0 errors!\n"
158 % (fname
, instcount
))
160 def DoOneFileOrDir(name
, ncdis
, objdump
):
161 if os
.path
.isfile(name
): DoOneFile(name
, ncdis
, objdump
)
162 elif os
.path
.isdir(name
):
163 for dirpath
, dirlist
, filelist
in os
.walk(name
):
164 for fname
in filelist
:
165 DoOneFile(os
.path
.join(dirpath
, fname
), ncdis
, objdump
)
166 else: print "invalid argument", name
172 for arg
in sys
.argv
[1:]:
174 if arg
.find("=") > 0:
175 name
, value
= arg
.split("=")
176 print("%s=%s" % (name
, value
))
180 # require MODE and PLATFORM_BASE to be set
181 if "PLATFORM_BASE" not in args
: Usage()
185 args
, files
= ParseArgv()
186 ncdis
, objdump
= FindBinaries(args
["PLATFORM_BASE"])
188 DoOneFileOrDir(name
, ncdis
, objdump
)
191 if '__main__' == __name__
: