Source Server und Symbol Server Setup mit Subversion
Mit diesem Blogpost will ich mal mein privates Source- und Symbolserver Setup beschreiben. Einerseits soll mir das helfen, die Umgebung schnell wieder ans Laufen zu bringen, wenn mal was abraucht, andererseits kann es vielleicht anderen helfen, sich eine ähnliche Umgebung aufzubauen.
DISCLAIMER: Das nachfolgend beschriebene Setup ist sicherlich nicht unbedingt der Weisheit letzter Schluss, vielleicht kann man da noch einiges optimieren. Über Verbesserungsvorschläge bin ich da natürlich stets dankbar. Andererseits kann ich mir durchaus vorstellen, dass die beschriebene Vorgehensweise zumindest in kleineren Softwareshops exakt so wie hier beschrieben sehr gut funktionieren kann. Darüberhinaus denke ich, dass das eigentliche Interface zum Source Server so gut abstrahiert ist, dass sich die Informationen aus diesem Blogpost auch sehr leicht auf andere Versionskontrollsysteme übertragen lassen und daher nicht allzu Subversion-spezifisch sind.
Wozu ist das Ganze gut?
Mit einem gut funktionierenden Source Server und Symbol Server Setup zusammen mit einem Versionskontrollsystem kann man folgende Ziele sehr einfach erreichen:
- Automatisiertes Runterladen der Symbole von Microsofts Symbol Server, was einem das Debugging extrem erleichtern kann und zumindest ansonsten die nur als Hexadezimalzahlen sichtbaren Adressen durch Funktionsnamen ersetzt.
- Automatisiertes Laden eigener Symbole in den Debugger mit zugehörigem automatisierten Auschecken des dazu passenden Sourcecodes. Damit ist man in der Lage, Minidumps von Kunden, beispielsweise durch Dr.Watson erzeugt, oder von der Winqual-Website (so man einen Account hierfür hat), in den Debugger zu laden und der Debugger sorgt dann selbständig dafür, dass der zugehörige Sourcecode-Stand ausgecheckt wird. Man landet damit dann direkt in der Sourcecodezeile, wo der Crash stattfand, auch wenn die zugehörigen Quellcodedateien zwischenzeitlich Veränderungen erfahren haben.
Doch zunächst mal einige Begriffsklärungen.
Was ist ein Symbol Server?
Ein Symbol Server ist eine DLL, die es gestattet, Symbole von woanders her in den Debugger zu laden. Mit Visual Studio 2005 und 2008 oder den Debugging Tools for Windows shippt als Symbol Server die Datei symsrv.dll mit - man kann sich aber in der Theorie auch einen anderen Symbol Server selber bauen indem man eine DLL schreibt, die statt symsrv.dll vom Debugger als Symbol Server verwendet wird und beispielsweise Symbole aus einer Datenbank o.ä. extrahiert, wo vorher die Symbole abgelegt wurden. Aber mit der Installation der drei vorgenannten Produkte hat man praktisch schon den Standard Symbol Server von Microsoft und dieser operiert mit sogenannten Symbol Stores. Ein Symbol Store ist nichts anderes als ein Share, auf dem Symbole (also PDB files) und optional Binaries (also .exe oder .dll files, PE files eben) liegen. Diese Dateien werden dort abgelegt, damit man sie sich dann beim Debuggen in den Debugger laden kann und damit Funktionsnamen, lokale Variablen etc. anzeigen lassen kann. Eben all das, was man im Debugger so üblicherweise braucht. Abgelegt werden die Symbole auf dem Symbol Store durch Automatismen, die der Debugger nach entsprechender Konfiguration selber mitbringt, oder durch Ausführen von Tools, beispielsweise im eigenen Buildprozess. Wird beispielsweise der Debugger entsprechend konfiguriert, etwa mit entsprechenden Umgebungsvariablen, so sorgt er beim Debuggen selbständig dafür, dass für die Binaries, die das Betriebssystem mitbringt, die entsprechenden Symbole vom Symbol Store von Microsoft heruntergeladen werden. Wie das geht zeige ich weiter unten. Andererseits kann man sich in einem Symbol Store auch Symbole für die eigenen Binaries ablegen, beispielsweise automatisiert aus dem daily build. Dazu verwendet man das Tool symstore.exe, und wie man das anwendet, zeige ich auch weiter unten.
Was ist ein Source Server?
Ein Source Server ist auch wieder nur eine DLL, in diesem Fall die Datei srcsrv.dll. Sie shippt auch mit den drei vorgenannten Produkten mit. Diese DLL verwendet man unter der Haube, wenn man die Perl-Skripte verwendet, die mit dem Source Server Support der Debugging Tools for Windows mitkommen. Diese Perl-Skripte (man braucht nur jeweils eines, je nachdem, welches Versionskontrollsystem man verwendet) dienen dazu, die beim Build entstandenen PDB files zu indizieren. "Indizieren" bezeichnet hier einen Vorgang, bei dem die PDB files um Informationen bereichert werden, die ein automatisiertes Auschecken des Source Codes aus dem Versionskontrollsystem gestatten. Wenn man sich also ein indiziertes PDB File mal in einem Hexeditor betrachtet, wird man erkennen, dass dort für jede Datei, die zum Builden des zugehörigen Binaries verwendet wurde, die Revisionsinformationen aus dem verwendeten Versionskontrollsystem abgelegt werden, samt Kommandozeile, wie diese Revision aus dem Versionskontrollsystem auszuchecken ist. Die folgende Abbildung zeigt, wie beispielsweise ein von mir indiziertes PDB im Hexeditor auszugsweise ausschaut:
(Ein Klick auf die Abbildung startet sie in Normalgröße in einem separaten Browserfenster)
Deutlich erkennbar ist, dass offenbar eine Environmentvariable SVN_EXTRACT_CMD verwendet wird, die als Wert svn.exe hat (das ist das Kommandozeilentool für Subversion). Dann folgen aufgelistet die Checkout-Kommandos wobei alle hier referenzierten Sourcefiles im Verzeichnis
http://ripley/svn/cvs/trunk/symbtest
auf meinem Subversion-Server ripley liegen. So sieht man beispielsweise an der Zeile
c:\applic\symbtest\symbtest\symbtestview.cpp* http://ripley/*svn/cvs/trunk/symbtest/symbtest/symbtestView.cpp*3863
, dass die lokal beim Builden verwendete Datei c:\applic\symbtest\symbtest\symbtestview.cpp der Datei
http://ripley/svn/cvs/trunk/symbtest/symbtest/symbtestView.cpp
in Revision 3863 entpricht. Nun ist auch klar, dass das Indizieren abhängig ist vom verwendeten Versionskontrollsystem, weil natürlich durch den Indizierungsvorgang je nach Versionskontrollsystem unterschiedliche Auscheckkommandos in das PDB File geschrieben werden müssen. So heisst beispielsweise bei Perforce das Kommandozeilentool zum Auschecken p4.exe, Bei Subversion svn.exe und bei CVS cvs.exe. Mal ganz davon abgesehen, dass natürlich Revisionsinformationen und die Kommandozeile auch jeweils unterschiedlich sind. Von Hause aus unterstützen die Windows Debugging Tools dabei folgende Versionskontrollsysteme (die Namen in Klammern bezeichnen die für das Indizieren verwendeten Batchfiles, die mit den Windows Debugging Tools ausgeliefert werden):
- Visual Source Safe (vssindex.cmd)
- Team Foundation Server (tfsindex.cmd)
- Subversion (svnindex.cmd)
- Perforce (p4index.cmd)
- CVS (cvsindex.cmd)
Doch wie man das Indizieren vornimmt, dazu lasse ich mich weiter unten aus, zunächst beschreibe ich, welche Software man braucht, und wie man seine Environmentvariablen und Symbol Stores clever anlegt.
Erforderliche Software
Zunächst braucht man mal eine aktuelle Version des Microsoft Debugging Toolkits für Windows, wovon man einfach eine Standardinstallation vornimmt, bei mir landet die in "c:\Program Files\Debugging Tools for Windows (x86)". Als nächstes benötigt man zum Indizieren eine Perl-Installation. Ich verwende hier ActivePerl von ActiveState. Auch hiervon macht man eine Standardinstallation, die landet bei mir im Verzeichnis c:\perl. Als drittes braucht man im Fall von Subversion noch einen SVN-Kommandozeilenclient. Ich verwende hier den CollabNet Subversion Client. Auch von dem macht man eine Standardinstallation, die landet bei mir in "c:\Program Files\CollabNet Subversion". Der Einfachheit halber ergänze ich auch noch folgendes zur Umgebunbgsvariable PATH:
C:\Perl\site\bin;C:\Perl\bin; C:\Program Files\CollabNet Subversion; c:\srcsrv; c:\Program Files\Debugging Tools for Windows (x86)
Was soll der Pfad c:\srcsrv? Dieses Verzeichnis lege ich mir an und kopiere da den kompletten Inhalt von "c:\Program Files\Debugging Tools for Windows (x86)\srcsrv" rein. Das mache ich, weil ich an den Dateien srcsrv.ini und svn.pm (dem Perl-Modul für Subversion) einige Änderungen machen muss und ich beim nächsten Update der Debugging Tools diese Änderungen nicht verlieren will. So ändere ich in c:\srcsrv.ini die Zeile
MYSERVER=mymachine.sys-mygroup.corp.microsoft.com:1666
ab in
MYSERVER=http://ripley/svn/cvs
und ergänze in der Section [trusted commands] eine Zeile mit dem Inhalt
svn.exe
Erstere Änderung spezifiziert natürlich den Pfad zu meinem SVN-Repository, die zweitere Änderung verhindert, dass der Debugger beim Auschecken ständig mit der Warnung nervt, dass er jetzt ein potentiell gefährliches externes Programm ausführt. Die solchermassen abgeänderte Datei c:\srcsrv.ini kopiere ich nun auch noch in meine Installation von VS2005 und VS2008. Diese liegen bei mir unter c:\msvc8 und c:\msvc9 und dieses ini-Datei landet dann in den Verzeichnissen c:\msvc8\Common7\IDE und c:\msvc9\Common7\IDE. Zusätzlich sollte man sich bei der Gelegenheit auch noch - wenn man VS2005 einsetzt - die Datei srcsrv.dll in c:\msvc8\Common7\IDE durch die aus "c:\Program Files\Debugging Tools for Windows (x86)\srcsrv" ersetzen, weil die mit VS2005 ausgelieferte Variante nicht so richtig gut funktioniert.
Die zweite Änderung erfolgt in c:\srcsrv\svn.pm wo ich die Zeile 283
"SVN_EXTRACT_CMD=cmd /c svn.exe cat ".
einfach ersetze durch
"SVN_EXTRACT_CMD=svn.exe cat ".
Das ist aber nur eine Schönheitskorrektur, die dafür sorgt, dass nicht noch für jeden Aufruf von svn.exe eine cmd.exe-Hülle gestartet wird.
Aufsetzen der Symbol Stores
Um einen Symbol Store aufzusetzen, braucht man eigentlich nur eine Maschine mit einer halbwegs grossen Festplatte, in meinem Fall heisst diese Maschine LaForge. Mein Ziel war es, zwei Symbol Stores auf LaForge zu haben, wobei einer die Symbole von Microsoft speichert (websymbols) und der zweite die Symbole, die ich selber generiere als Teil meines Builds (privatesymbols). Dieser zweite Store ist auch das, was man regelmässig backuppen sollte, damit man im Fall eines Plattencrashes die eigenen Symbole wiederherstellen kann. Also lege ich zwei Shares an auf LaForge und zwar:
\\laforge\websymbols
und
\\laforge\privatesymbols
Als Berechtigungen vergebe ich NTFS-seitig Vollzugriff für Everyone und Share-seitig Leseberechtigung für Everyone und Vollzugriff für "Authenticated Users". Natürlich kann man das beliebig paranoid gestalten, der Fantasie sind da keine Grenzen gesetzt. Dass Authenticated Users hier Schreibrechte haben sollen, garantiert mir, dass auch unprivilegierte User automatisch hier die von Microsoft geladenen Symbole speichern dürfen, sodass sie alle Rechner in meinem LAN auch von dort laden können und nicht jedesmal auf den Microsoftschen Symbol-Store gehen müssen. Und meine User sind alles LUA Users, also hat das schon seinen Sinn.
Damit die Symbole auch lokal erstmal gecached werden und vom Debugger geladen werden können fehlen jetzt noch drei Dinge:
- Ich lege auf jeder Entwicklungsmaschine die Verzeichnisse c:\websymbols und c:\privatesymbols an.
Ich lege auf jeder Entwicklungsmaschine die Umgebungsvariable _NT_SYMBOL_PATH mit folgendem Wert an:
srv*c:\websymbols*\\laforge\websymbols* http://msdl.microsoft.com/download/symbols; srv*c:\privatesymbols*\\laforge\privatesymbols*
Eintragen von
c:\websymbols*\\laforge\websymbols* http://msdl.microsoft.com/download/symbols
undc:\privatesymbols*\\laforge\privatesymbols*
als "Symbol file (.pdb) locations in VS2005/2008 in den "Debugging" - "Symbols" Options, die man über die Menüpunkte "Tools"-"Options" erreicht (siehe nächste Abbildung).
(Ein Klick auf die Abbildung startet sie in Normalgröße in einem separaten Browserfenster)
Damit werden dann neue Symbole von Microsoft von http://msdl.microsoft.com/download/symbols geladen und erstmal auf \\laforge\websymbols und dann im lokalen Cache c:\websymbols abgelegt. Die Suchreihenfolge für den Debugger ist dann c:\websymbols - \\laforge\websymbols - http://msdl.microsoft.com/download/symbols, er nimmt also den schnellsten Zugriff, den er bekommen kann. Gleichzeitig werden private Symbole versucht, von c:\privatesymbols geladen, und wenn sie dort nicht gefunden werden, von \\laforge\privatesymbols und dann in c:\privatesymbols gecached.
Indizieren privater Symbole und Ablegen im privaten Symbol Store
Nachdem nun die Infrastruktur steht, können wir jetzt mal unser Lieblingsprodukt builden, indizieren und auf dem eigenen Symbolstore ablegen. Dazu mache ich im Buildverzeichnis des Produkts (also da wo die EXE- und DLL-Files sowie die zugehoerigen PDB files stehen) eine Konsole (cmd.exe) auf und gebe in etwa folgendes ein:
svnindex.cmd /debug /source=<Pfad1>;<Pfad2>
Dabei stellen <Pfad1> und <Pfad2> Verzeichnisse daher, unterhalb von denen nach Sourcefiles gesucht wird, die zum Builden der Binaries verwendet wurden. Wenn man lieber das Verzeichnis angibt, unter dem nach zu indizierenden PDB files gesucht werden soll, dann tut man das mit dem /symbols=<Pfad> Parameter. Der Parameter /debug sorgt lediglich für verbose output.
Hat man so nun seine PDB files indiziert, liegen sie natürlich immer noch auf der Maschine, auf der gerade gebuildet und indiziert wurde, aber noch nicht auf dem symbol store. Auf diesen bringt man nun die pdb und exe/dll Files mit folgendem Kommando:
symstore add /r /f <Pfad>\*.* /s \\laforge\privatesymbols /t <Projektname> /v <versionsnummer> /compress
Dabei ist <Pfad> das Verzeichnis unter dem rekursiv (/r) nach PDB Files gesucht werden soll, die dann in den Symbolstore \\laforge\privatesymbols kopiert werden. Mit /t kann man nun noch so etwas wie einen Produktnamen und mit /v eine Versionsnummer angeben. Wozu letzte beideren gut sind, weiss ich selber nicht, jedenfalls tauchen sie aber in den Logfiles auf dem Symbol Store wieder auf. Mit /compress werden die Dateien im Symbol Store noch LZ-komprimiert abgelegt und der \*.* hinter /f <Pfad> sorgt dafür, dass nicht nur die PDB files, sondern auch die EXE und DLL files auf dem Symbol Store landen. Will man letzteres nicht, so gibt man eben /f <Pfad>\*.pdb an. Was fuer einen Vorteil es hat, die PE files auch noch mit auf dem Symbol Store abzulegen, hat sich mir noch nicht so ganz erschlossen, aber da LaForge eine mördergroße Festplatte hat, mache ich mir da keinen Kopf drum und speichere einfach alles ab.
Konfigurieren von VS2005/VS2008
Nun muss eigentlich nur noch VS2005/2008 so konfiguriert werden, dass es mit einem Source Server arbeitet. Dazu wählt man aus dem Menü "Tools"-"Options" an und wählt dann in dem nun erscheinenden Dialog im Baum links den Punkt "Debugging" an und setzt das Häkchen bei "Enable source server support" und optional "Print source server diagnostic messages to the output window", wie in der nächsten Abbildung:
(Ein Klick auf die Abbildung startet sie in Normalgröße in einem separaten Browserfenster)
Bonustrack 1: JIT Debugging mit Windbg und Symbol Server Anbindung
Will man aus irgendeinem Grund lieber Windbg zum Debuggen nehmen, beispielsweise auf Maschinen von Testern, die ansonsten keine full-blown Installation von Visual Studio haben oder wenn man dafür keine Lizenz verschwenden möchte, dann kann man sich auch Windbg so konfigurieren, dass man damit die Annehmlichkeiten des automatisierten Auscheckens bekommt. Dazu konfiguriert man sich die Umgebungsvariable _NT_SOURCE_PATH und weist ihr den Wert SRV*;SRV*\\laforge\privatesymbols zu. Nun kann auch Windbg automatisch die privaten PDB files ermitteln und die zugehörigen Auscheckkommandos durchführen. Allerdings checkt es dann in ein Unterverzeichnis src im Windbg Installationsverzeichnis aus, was natürlich keine gute Sache für LUA User ist. Daher reserviert man sich am Besten ein Verzeichnis auf der Entwickler- oder Testermaschine, in die Windbg auschecken darf. Bei mir ist das das Verzeichnis c:\srccache, dem ich einen entsprechend relaxten Security-Descriptor verbrate, so dass unprivilegierte User auch da hinein auschecken duerfen, wenn sie Windbg verwenden. Was dann noch fehlt ist das Definieren einer weiteren Umgebungsvariablen namens DBGHELP_HOMEDIR, der ich dann den Wert c:\srccache zuweise. Um nun Windbg als JIT Debugger einzurichten, muss man nun nur einmal als privilegierter Benutzer windbg mit dem Kommandozeilenparameter -I aufrufen. Sollte man aber bereits VS2005 oder VS2008 auf seiner Maschine installiert haben und will später wieder zurück zum Debuggerselektor als JIT Debugger, tut man gut daran, vorher den Value "Debugger" unter HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug umzubenennen, sonst wird der durch windbg -I geplättet.
Bonustrack 2: Geht das ganze auch mit PDB Files, die mit älteren Versionen von VS erstellt wurden?
Mit PDB Files, die von VS6 (aka VC98) erzeugt wurden, ging die Sache bei mir in einem kleineren Test schon, also denke ich mal, dass das schon generell gehen sollte.
Das wär's also zum Thema Source Server und Symbol Server. Keep debugging, you know, I am.
Trackback address for this post
2 comments
Hab es bei mir praktisch genau so laufen, nur die Einbindung in Windbg kannte ich bisher noch nicht. Verwende ich zwar nicht immer, aber grad für dumps doch mal gerne.
Was bei mir aus irgendeinem Grund nicht geht, ist das definieren des MYSERVER= Eintrags in der srcsrv.ini. Dieser wird bei mir einfach ignoriert. kann mir nur vorstellen, dass dies damit zu tun hat, das ich keinen apache, sondern nur das svn protokoll verwende.
Da ich Externals verwende, und diese von svnindex.cmd ignoriert werden, hab ich mir dafür noch ein script geschrieben, welches als post build läuft, und meine pdbs automatisch inkl. externals indiziert.
Kann ich bei Bedarf gerne zur Verfügung stellen!
Die Suche nach dem Mist hat mich zwei Stunden Perl-Debugging gekostet. :-\
Comments are closed for this post.