OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Copyright (c) 2008 The Chromium Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 4 # found in the LICENSE file. |
6 | 5 |
7 """Usage: <win-path-to-pdb.pdb> | 6 """Usage: <win-path-to-pdb.pdb> |
8 This tool will take a PDB on the command line, extract the source files that | 7 This tool will take a PDB on the command line, extract the source files that |
9 were used in building the PDB, query SVN for which repository and revision | 8 were used in building the PDB, query SVN for which repository and revision |
10 these files are at, and then finally write this information back into the PDB | 9 these files are at, and then finally write this information back into the PDB |
11 in a format that the debugging tools understand. This allows for automatic | 10 in a format that the debugging tools understand. This allows for automatic |
12 source debugging, as all of the information is contained in the PDB, and the | 11 source debugging, as all of the information is contained in the PDB, and the |
13 debugger can go out and fetch the source files via SVN. | 12 debugger can go out and fetch the source files via SVN. |
(...skipping 24 matching lines...) Expand all Loading... |
38 REPO_MAP = { | 37 REPO_MAP = { |
39 "svn://chrome-svn/chrome": "http://src.chromium.org/svn", | 38 "svn://chrome-svn/chrome": "http://src.chromium.org/svn", |
40 "svn://chrome-svn.corp.google.com/chrome": "http://src.chromium.org/svn", | 39 "svn://chrome-svn.corp.google.com/chrome": "http://src.chromium.org/svn", |
41 "http://v8.googlecode.com/svn": None, | 40 "http://v8.googlecode.com/svn": None, |
42 "http://google-breakpad.googlecode.com/svn": None, | 41 "http://google-breakpad.googlecode.com/svn": None, |
43 "http://googletest.googlecode.com/svn": None, | 42 "http://googletest.googlecode.com/svn": None, |
44 "http://open-vcdiff.googlecode.com/svn": None, | 43 "http://open-vcdiff.googlecode.com/svn": None, |
45 "http://google-url.googlecode.com/svn": None, | 44 "http://google-url.googlecode.com/svn": None, |
46 } | 45 } |
47 | 46 |
| 47 |
48 def FindFile(filename): | 48 def FindFile(filename): |
49 """Return the full windows path to a file in the same dir as this code.""" | 49 """Return the full windows path to a file in the same dir as this code.""" |
50 thisdir = os.path.dirname(os.path.join(os.path.curdir, __file__)) | 50 thisdir = os.path.dirname(os.path.join(os.path.curdir, __file__)) |
51 return os.path.abspath(os.path.join(thisdir, filename)) | 51 return os.path.abspath(os.path.join(thisdir, filename)) |
52 | 52 |
53 | 53 |
54 def ExtractSourceFiles(pdb_filename): | 54 def ExtractSourceFiles(pdb_filename): |
55 """Extract a list of local paths of the source files from a PDB.""" | 55 """Extract a list of local paths of the source files from a PDB.""" |
56 srctool = subprocess.Popen([FindFile('srctool.exe'), '-r', pdb_filename], | 56 srctool = subprocess.Popen([FindFile('srctool.exe'), '-r', pdb_filename], |
57 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 57 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
58 filelist = srctool.stdout.read() | 58 filelist = srctool.stdout.read() |
59 res = srctool.wait() | 59 res = srctool.wait() |
60 if res != 0 or filelist.startswith("srctool: "): | 60 if res != 0 or filelist.startswith("srctool: "): |
61 raise "srctool failed: " + filelist | 61 raise "srctool failed: " + filelist |
62 return [x for x in filelist.split('\r\n') if len(x) != 0] | 62 return [x for x in filelist.split('\r\n') if len(x) != 0] |
63 | 63 |
| 64 |
64 def ReadSourceStream(pdb_filename): | 65 def ReadSourceStream(pdb_filename): |
65 """Read the contents of the source information stream from a PDB.""" | 66 """Read the contents of the source information stream from a PDB.""" |
66 srctool = subprocess.Popen([FindFile('pdbstr.exe'), | 67 srctool = subprocess.Popen([FindFile('pdbstr.exe'), |
67 '-r', '-s:srcsrv', | 68 '-r', '-s:srcsrv', |
68 '-p:%s' % pdb_filename], | 69 '-p:%s' % pdb_filename], |
69 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 70 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
70 data = srctool.stdout.read() | 71 data = srctool.stdout.read() |
71 res = srctool.wait() | 72 res = srctool.wait() |
72 | 73 |
73 if (res != 0 and res != -1) or data.startswith("pdbstr: "): | 74 if (res != 0 and res != -1) or data.startswith("pdbstr: "): |
74 raise "pdbstr failed: " + data | 75 raise "pdbstr failed: " + data |
75 return data | 76 return data |
76 | 77 |
| 78 |
77 def WriteSourceStream(pdb_filename, data): | 79 def WriteSourceStream(pdb_filename, data): |
78 """Write the contents of the source information stream to a PDB.""" | 80 """Write the contents of the source information stream to a PDB.""" |
79 # Write out the data to a temporary filename that we can pass to pdbstr. | 81 # Write out the data to a temporary filename that we can pass to pdbstr. |
80 (f, fname) = tempfile.mkstemp() | 82 (f, fname) = tempfile.mkstemp() |
81 f = os.fdopen(f, "wb") | 83 f = os.fdopen(f, "wb") |
82 f.write(data) | 84 f.write(data) |
83 f.close() | 85 f.close() |
84 | 86 |
85 srctool = subprocess.Popen([FindFile('pdbstr.exe'), | 87 srctool = subprocess.Popen([FindFile('pdbstr.exe'), |
86 '-w', '-s:srcsrv', | 88 '-w', '-s:srcsrv', |
87 '-i:%s' % fname, | 89 '-i:%s' % fname, |
88 '-p:%s' % pdb_filename], | 90 '-p:%s' % pdb_filename], |
89 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 91 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
90 data = srctool.stdout.read() | 92 data = srctool.stdout.read() |
91 res = srctool.wait() | 93 res = srctool.wait() |
92 | 94 |
93 if (res != 0 and res != -1) or data.startswith("pdbstr: "): | 95 if (res != 0 and res != -1) or data.startswith("pdbstr: "): |
94 raise "pdbstr failed: " + data | 96 raise "pdbstr failed: " + data |
95 | 97 |
96 os.unlink(fname) | 98 os.unlink(fname) |
97 | 99 |
| 100 |
98 # TODO for performance, we should probably work in directories instead of | 101 # TODO for performance, we should probably work in directories instead of |
99 # files. I'm scared of DEPS and generated files, so for now we query each | 102 # files. I'm scared of DEPS and generated files, so for now we query each |
100 # individual file, and don't make assumptions that all files in the same | 103 # individual file, and don't make assumptions that all files in the same |
101 # directory are part of the same repository or at the same revision number. | 104 # directory are part of the same repository or at the same revision number. |
102 def ExtractSvnInfo(local_filename): | 105 def ExtractSvnInfo(local_filename): |
103 """Calls svn info to extract the repository, path, and revision.""" | 106 """Calls svn info to extract the repository, path, and revision.""" |
104 # We call svn.bat to make sure and get the depot tools SVN and not cygwin. | 107 # We call svn.bat to make sure and get the depot tools SVN and not cygwin. |
105 srctool = subprocess.Popen(['svn.bat', 'info', local_filename], | 108 srctool = subprocess.Popen(['svn.bat', 'info', local_filename], |
106 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 109 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
107 info = srctool.stdout.read() | 110 info = srctool.stdout.read() |
108 res = srctool.wait() | 111 res = srctool.wait() |
109 if res != 0: | 112 if res != 0: |
110 return None | 113 return None |
111 # Hack up into a dictionary of the fields printed by svn info. | 114 # Hack up into a dictionary of the fields printed by svn info. |
112 vals = dict((y.split(': ', 2) for y in info.split('\r\n') if y)) | 115 vals = dict((y.split(': ', 2) for y in info.split('\r\n') if y)) |
113 | 116 |
114 root = vals['Repository Root'] | 117 root = vals['Repository Root'] |
115 if not vals['URL'].startswith(root): | 118 if not vals['URL'].startswith(root): |
116 raise "URL is not inside of the repository root?!?" | 119 raise "URL is not inside of the repository root?!?" |
117 path = vals['URL'][len(root):] | 120 path = vals['URL'][len(root):] |
118 rev = int(vals['Revision']) | 121 rev = int(vals['Revision']) |
119 | 122 |
120 return [root, path, rev] | 123 return [root, path, rev] |
121 | 124 |
| 125 |
122 def UpdatePDB(pdb_filename, verbose=False): | 126 def UpdatePDB(pdb_filename, verbose=False): |
123 """Update a pdb file with source information.""" | 127 """Update a pdb file with source information.""" |
124 dir_blacklist = { } | 128 dir_blacklist = { } |
125 # TODO(deanm) look into "compressing" our output, by making use of vars | 129 # TODO(deanm) look into "compressing" our output, by making use of vars |
126 # and other things, so we don't need to duplicate the repo path and revs. | 130 # and other things, so we don't need to duplicate the repo path and revs. |
127 lines = [ | 131 lines = [ |
128 'SRCSRV: ini ------------------------------------------------', | 132 'SRCSRV: ini ------------------------------------------------', |
129 'VERSION=1', | 133 'VERSION=1', |
130 'INDEXVERSION=2', | 134 'INDEXVERSION=2', |
131 'VERCTRL=Subversion', | 135 'VERCTRL=Subversion', |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 root = REPO_MAP[root] | 187 root = REPO_MAP[root] |
184 | 188 |
185 lines.append('%s*%s*%s*%s' % (filename, root, path, rev)) | 189 lines.append('%s*%s*%s*%s' % (filename, root, path, rev)) |
186 if verbose: | 190 if verbose: |
187 print " indexed file." | 191 print " indexed file." |
188 | 192 |
189 lines.append('SRCSRV: end ------------------------------------------------') | 193 lines.append('SRCSRV: end ------------------------------------------------') |
190 | 194 |
191 WriteSourceStream(pdb_filename, '\r\n'.join(lines)) | 195 WriteSourceStream(pdb_filename, '\r\n'.join(lines)) |
192 | 196 |
193 if __name__ == '__main__': | 197 |
| 198 def main(): |
194 if len(sys.argv) < 2 or len(sys.argv) > 3: | 199 if len(sys.argv) < 2 or len(sys.argv) > 3: |
195 print "usage: file.pdb [-v]" | 200 print "usage: file.pdb [-v]" |
196 sys.exit(1) | 201 return 1 |
197 | 202 |
198 verbose = False | 203 verbose = False |
199 if len(sys.argv) == 3: | 204 if len(sys.argv) == 3: |
200 verbose = (sys.argv[2] == '-v') | 205 verbose = (sys.argv[2] == '-v') |
201 | 206 |
202 UpdatePDB(sys.argv[1], verbose=verbose) | 207 UpdatePDB(sys.argv[1], verbose=verbose) |
| 208 return 0 |
| 209 |
| 210 |
| 211 if __name__ == '__main__': |
| 212 sys.exit(main()) |
OLD | NEW |