summaryrefslogtreecommitdiffstats
path: root/tools/symsrc/source_index.py
diff options
context:
space:
mode:
authordeanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-07 13:42:24 +0000
committerdeanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-07 13:42:24 +0000
commitcff1841ada280b9d7be8883851e1acca259da7de (patch)
tree215152b9121c6ae61d2aadbb81c3ee885f42535b /tools/symsrc/source_index.py
parent0614b501e4df1c1ce02dcd20d3a26d08243e3dfb (diff)
downloadchromium_src-cff1841ada280b9d7be8883851e1acca259da7de.zip
chromium_src-cff1841ada280b9d7be8883851e1acca259da7de.tar.gz
chromium_src-cff1841ada280b9d7be8883851e1acca259da7de.tar.bz2
Add the symbol and source server scripts.
Review URL: http://codereview.chromium.org/155136 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20022 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/symsrc/source_index.py')
-rw-r--r--tools/symsrc/source_index.py193
1 files changed, 193 insertions, 0 deletions
diff --git a/tools/symsrc/source_index.py b/tools/symsrc/source_index.py
new file mode 100644
index 0000000..152fe22
--- /dev/null
+++ b/tools/symsrc/source_index.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Usage: <win-path-to-pdb.pdb>
+This tool will take a PDB on the command line, extract the source files that
+were used in building the PDB, query SVN for which repository and revision
+these files are at, and then finally write this information back into the PDB
+in a format that the debugging tools understand. This allows for automatic
+source debugging, as all of the information is contained in the PDB, and the
+debugger can go out and fetch the source files via SVN.
+
+You most likely want to run these immediately after a build, since the source
+input files need to match the generated PDB, and we want the correct SVN
+revision information for the exact files that were used for the build.
+
+The following files from a windbg + source server installation are expected
+to reside in the same directory as this python script:
+ dbghelp.dll
+ pdbstr.exe
+ srctool.exe
+
+NOTE: Expected to run under a native win32 python, NOT cygwin. All paths are
+dealt with as win32 paths, since we have to interact with the Microsoft tools.
+"""
+
+import sys
+import os
+import time
+import subprocess
+import tempfile
+
+# This serves two purposes. First, it acts as a whitelist, and only files
+# from repositories listed here will be source indexed. Second, it allows us
+# to map from one SVN URL to another, so we can map to external SVN servers.
+REPO_MAP = {
+ "svn://chrome-svn/chrome": "http://src.chromium.org/svn",
+ "svn://chrome-svn.corp.google.com/chrome": "http://src.chromium.org/svn",
+ "http://v8.googlecode.com/svn": None,
+ "http://google-breakpad.googlecode.com/svn": None,
+ "http://googletest.googlecode.com/svn": None,
+ "http://open-vcdiff.googlecode.com/svn": None,
+ "http://google-url.googlecode.com/svn": None,
+}
+
+def FindFile(filename):
+ """Return the full windows path to a file in the same dir as this code."""
+ thisdir = os.path.dirname(os.path.join(os.path.curdir, __file__))
+ return os.path.abspath(os.path.join(thisdir, filename))
+
+
+def ExtractSourceFiles(pdb_filename):
+ """Extract a list of local paths of the source files from a PDB."""
+ srctool = subprocess.Popen([FindFile('srctool.exe'), '-r', pdb_filename],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ filelist = srctool.stdout.read()
+ res = srctool.wait()
+ if res != 0 or filelist.startswith("srctool: "):
+ raise "srctool failed: " + filelist
+ return [x for x in filelist.split('\r\n') if len(x) != 0]
+
+def ReadSourceStream(pdb_filename):
+ """Read the contents of the source information stream from a PDB."""
+ srctool = subprocess.Popen([FindFile('pdbstr.exe'),
+ '-r', '-s:srcsrv',
+ '-p:%s' % pdb_filename],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ data = srctool.stdout.read()
+ res = srctool.wait()
+
+ if (res != 0 and res != -1) or data.startswith("pdbstr: "):
+ raise "pdbstr failed: " + data
+ return data
+
+def WriteSourceStream(pdb_filename, data):
+ """Write the contents of the source information stream to a PDB."""
+ # Write out the data to a temporary filename that we can pass to pdbstr.
+ (f, fname) = tempfile.mkstemp()
+ f = os.fdopen(f, "wb")
+ f.write(data)
+ f.close()
+
+ srctool = subprocess.Popen([FindFile('pdbstr.exe'),
+ '-w', '-s:srcsrv',
+ '-i:%s' % fname,
+ '-p:%s' % pdb_filename],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ data = srctool.stdout.read()
+ res = srctool.wait()
+
+ if (res != 0 and res != -1) or data.startswith("pdbstr: "):
+ raise "pdbstr failed: " + data
+
+ os.unlink(fname)
+
+# TODO for performance, we should probably work in directories instead of
+# files. I'm scared of DEPS and generated files, so for now we query each
+# individual file, and don't make assumptions that all files in the same
+# directory are part of the same repository or at the same revision number.
+def ExtractSvnInfo(local_filename):
+ """Calls svn info to extract the repository, path, and revision."""
+ # We call svn.bat to make sure and get the depot tools SVN and not cygwin.
+ srctool = subprocess.Popen(['svn.bat', 'info', local_filename],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ info = srctool.stdout.read()
+ res = srctool.wait()
+ if res != 0:
+ return None
+ # Hack up into a dictionary of the fields printed by svn info.
+ vals = dict((y.split(': ', 2) for y in info.split('\r\n') if y))
+
+ root = vals['Repository Root']
+ if not vals['URL'].startswith(root):
+ raise "URL is not inside of the repository root?!?"
+ path = vals['URL'][len(root):]
+ rev = int(vals['Revision'])
+
+ return [root, path, rev]
+
+def UpdatePDB(pdb_filename):
+ """Update a pdb file with source information."""
+ dir_blacklist = { }
+ # TODO(deanm) look into "compressing" our output, by making use of vars
+ # and other things, so we don't need to duplicate the repo path and revs.
+ lines = [
+ 'SRCSRV: ini ------------------------------------------------',
+ 'VERSION=1',
+ 'INDEXVERSION=2',
+ 'VERCTRL=Subversion',
+ 'DATETIME=%s' % time.asctime(),
+ 'SRCSRV: variables ------------------------------------------',
+ 'SVN_EXTRACT_TARGET=%targ%\%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%)',
+ 'SVN_EXTRACT_CMD=cmd /c svn cat "%var2%%var3%@%var4%" --non-interactive > "%svn_extract_target%"',
+ 'SRCSRVTRG=%SVN_extract_target%',
+ 'SRCSRVCMD=%SVN_extract_cmd%',
+ 'SRCSRV: source files ---------------------------------------',
+ ]
+
+ if ReadSourceStream(pdb_filename):
+ raise "PDB already has source indexing information!"
+
+ filelist = ExtractSourceFiles(pdb_filename)
+ for filename in filelist:
+ filedir = os.path.dirname(filename)
+
+ print "Processing: %s" % filename
+ # This directory is blacklisted, either because it's not part of the SVN
+ # repository, or from one we're not interested in indexing.
+ if dir_blacklist.get(filedir, False):
+ print " skipping, directory is blacklisted."
+ continue
+
+ info = ExtractSvnInfo(filename)
+
+ # Skip the file if it's not under an svn repository. To avoid constantly
+ # querying SVN for files outside of SVN control (for example, the CRT
+ # sources), check if the directory is outside of SVN and blacklist it.
+ if not info:
+ if not ExtractSvnInfo(filedir):
+ dir_blacklist[filedir] = True
+ print " skipping, file is not in an SVN repository"
+ continue
+
+ root = info[0]
+ path = info[1]
+ rev = info[2]
+
+ # Check if file was from a svn repository we don't know about, or don't
+ # want to index. Blacklist the entire directory.
+ if not REPO_MAP.has_key(info[0]):
+ print " skipping, file is from an unknown SVN repository %s" % root
+ dir_blacklist[filedir] = True
+ continue
+
+ # We might want to map an internal repository URL to an external repository.
+ if REPO_MAP[root]:
+ root = REPO_MAP[root]
+
+ lines.append('%s*%s*%s*%s' % (filename, root, path, rev))
+ print " indexed file."
+
+ lines.append('SRCSRV: end ------------------------------------------------')
+
+ WriteSourceStream(pdb_filename, '\r\n'.join(lines))
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print "usage: file.pdb"
+ sys.exit(1)
+
+ UpdatePDB(sys.argv[1])