Home | History | Annotate | Download | only in symsrc
      1 #!/usr/bin/env python
      2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 """This will retrieve a PDBs "fingerprint" from it's corresponding executable
      7 image (.dll or .exe).  This is used when retrieving the PDB from the symbol
      8 server.  The .pdb (or cab compressed .pd_) is expected at a path like:
      9  foo.pdb/FINGERPRINT/foo.pdb
     10 
     11 We can retrieve the same information from the .PDB file itself, but this file
     12 format is much more difficult and undocumented.  Instead, we can look at the
     13 DLL's reference to the PDB, and use that to retrieve the information."""
     14 
     15 import sys
     16 import pefile
     17 
     18 
     19 __CV_INFO_PDB70_format__ = ('CV_INFO_PDB70',
     20   ('4s,CvSignature', '16s,Signature', 'L,Age'))
     21 
     22 __GUID_format__ = ('GUID',
     23   ('L,Data1', 'H,Data2', 'H,Data3', '8s,Data4'))
     24 
     25 
     26 def GetPDBInfoFromImg(filename):
     27   """Returns the PDB fingerprint and the pdb filename given an image file"""
     28 
     29   pe = pefile.PE(filename)
     30 
     31   for dbg in pe.DIRECTORY_ENTRY_DEBUG:
     32     if dbg.struct.Type == 2:  # IMAGE_DEBUG_TYPE_CODEVIEW
     33       off = dbg.struct.AddressOfRawData
     34       size = dbg.struct.SizeOfData
     35       data = pe.get_memory_mapped_image()[off:off+size]
     36 
     37       cv = pefile.Structure(__CV_INFO_PDB70_format__)
     38       cv.__unpack__(data)
     39       cv.PdbFileName = data[cv.sizeof():]
     40       guid = pefile.Structure(__GUID_format__)
     41       guid.__unpack__(cv.Signature)
     42       guid.Data4_0 = ''.join("%02X" % ord(x) for x in guid.Data4[0:2])
     43       guid.Data4_1 = ''.join("%02X" % ord(x) for x in guid.Data4[2:])
     44 
     45       return ("%08X%04X%04X%s%s%d" % (
     46           guid.Data1, guid.Data2, guid.Data3,
     47           guid.Data4_0, guid.Data4_1, cv.Age),
     48           cv.PdbFileName.split('\x00', 1)[0])
     49 
     50     break
     51 
     52 
     53 def main():
     54   if len(sys.argv) != 2:
     55     print "usage: file.dll"
     56     return 1
     57 
     58   (fingerprint, filename) = GetPDBInfoFromImg(sys.argv[1])
     59   print "%s %s" % (fingerprint, filename)
     60   return 0
     61 
     62 
     63 if __name__ == '__main__':
     64   sys.exit(main())
     65