Set Up a Source Server


Setting up a Symbol Server will help get call stacks out of native code back into your managed code, but if you don't know the source version, you're still debugging at the assembly language level. No matter how vigilant your team is with the version-control system, there are those times where you're debugging a build and just don't know what version you need. Although you might get close, the one change you need to see isn't in the particular version you guessed it was, and you don't solve the problem.

Wouldn't it be great if there were a way for the debugger to already have the knowledge about the source code version and automatically have the right version in the Source window? Even better would be if the debugger would get the source code without any prompting or input on your part? I don't know about you, but that just about sounds like debugging perfection to me! That's exactly what the Source Server tools are all about.

Before we jump into setting up and using the Source Server, I have to warn you that it can be an adventure to get it working. The Source Server has a few foibles and lacks documentation. However, I think I've teased out all the oddities and issues you'll run into, which took me a solid week of experimentation, so I'll help you skip the parts where you'll be wondering what its doing.

The Zen of Source Server

As you've seen, the Symbol Server is really a database using the file system. When you go to load Foo.pdb, the debugger builds up a directory path starting with your cache directory, appends to the file to open, and finishes with the GUID uniquely identifying that particular version of the file. In that directory path is the actual PDB file the debugger needs.

Although it has Server in the name, the Source Server doesn't actually store your source code as the Symbol Server does with PDBs. A PDB file created with any of the recent compilers has in it the full path for each of the source files used to create the binary. When you run the Source Server programs on your binaries, they add a section to the PDB file where it embeds the exact version control systemreported version of the file. Moreover, it also embeds the actual version control commands to get that file out of the version control system. The process of running the Source Server tools and embedding this information in the PDB files is called indexing the source code. Once you've indexed the version and commands to extract from the version control system into the PDB, no matter where you are in the company, as long as you have access to the version control system, the debuggers will ask the version control system for the correct version of the file as necessary. I'll show you how you can see this information in the PDB files later in the chapter.

Because the Source Server is using your version control system, it has to support the particular version control you are using. When you install the latest Source Server binaries, it has support for Perforce, http://subversion.tigris.org/Subversion, and, of course, the ubiquitous Visual SourceSafe. Support for additional version control systems, including Microsoft Team Foundation System, will be available shortly. If you're using an unsupported version control system, the good news is that the Source Server tools are extensible, and as long as your system supports a command-line tool to get version information and retrieve source files, you can write your own module to coordinate and use your system. See the Srcsrv.doc file in the Source Server installation directory on what you will need to do to create that module and integrate it into the tools.

From the highest level, the Source Server workflow is straightforward. The first step is obviously to build both the debug and release builds of your application. After you've run your automated smoke tests to ensure that you have a build worth keeping, you'll use the Source Server programs to index the PDB files with the version control information. The final step will be to store those indexed PDB files into your Symbol Server so that everyone can benefit.

For this chapter, I used Visual SourceSafe because it's the most common version control system used by developers on Windows. However, the way Source Server is written, there are few differences between the various products, so the concepts are almost identical. No matter what version control system you are using, I strongly recommend that you set up a little practice spot so you can practice and become proficient with Source Server.

When I refer to the Source Server binaries, I refer to those programs do the actual source indexing. The debuggers already have the Srcsrv.dll that knows how to execute the version control system embedded into your PDB files. The Source Server binaries are part of the Debugging Tools for Windows package, which you can download free from Microsoft at http://microsoft.com/whdc/devtools/debugging/default.mspx. If you are going to be running your code on a 64-bit system, you can use the appropriate 64-bit debugger package tools, but the 32-bit versions will work on x64 also.

The only problem is that a default Debugging Tools for Windows installation does not install the necessary Source Server binaries by default. You'll need to do a custom installation of the Debugging Tools for Windows and select the SDK portion to install. That will add an SDK directory under the Debugging Tools for Windows directory. Inside the SDK directory is a SRCSRV directory that contains all the appropriate programs. You can leave that directory there and point your path to it, or you can copy it somewhere else. In any event, the directory that contains the tools has to be in your path.

After installing the custom Debugging Tools for Windows, you'll need to install Perl 5.6 or greater if you don't already have it on your machine. I've been using Perl 5.8.7, which you can download from http://www.cpan.org/.

When you look at the files in the Source Server directory, you'll see that most of the work in Source Server tools is in Perl code. The Ssindex.cmd file, which is the core batch file, just calls Perl.exe and passes the Perl code in through standard input. The .pm files are the Perl modules that know how to talk to the individual version control systems, and Ssindex.cmd loads them and calls through a standard interface to isolate the system differences. The other .cmd files, such as VSsindex.cmd, are wrappers that make it easier to use a specific version control system because Ssindex.cmd needs the version control system on the command line. The Pdbstr.exe and Srctool.exe files in the SRCSRV directory read and write to PDB files. The Vssdump.exe program is a helper for the Visual SourceSafe integration; it's installed only with the x86 version of the Debugging Tools for Windows package.

When you run Ssindex.cmd, after validating parameters, it asks the version control system for the list of all source files and associated version numbers in the target version control project and all child projects. The next step is to start looking for PDB files recursively. For each PDB file found, the Perl code calls Srctool.exe to extract the list of source file names out of the PDB. The code looks through the source file names in the PDB and sees if they match any of those stored earlier from the version control search, and if so, saves that file information into a temporary file. Once the code has looked at all the source files, it's time to call Pdbstr.exe to write the index stream, appropriately called SRCSRV, to the PDB file. (Note that the stream is not an NTFS file system stream, but a section in the PDB file). When debugging, the debugger looks for that stream, and if it finds it, it knows that there's a Source Server involved and calls into Srcsrv.dll to execute the version control system to get the right file.

I just wanted to provide you a general overview of what happens when you index source code. If you're more interested in what's going on in Ssindex.cmd, you can look at the code or Srcsrv.doc. As I mentioned earlier, if the Source Server does not support your version control system out of the box; you'll just need to write the Perl module that conforms to the interface specified in Srcsrv.doc.

Basic Indexing

To walk you through the steps of manually using the Source Server, I'll use a very simple source tree that comprises two console applications, CppApp and NetApp, which reside in appropriately named directories: D:\Dev\CppApp and D:\Dev\NetApp. CppApp is a native C++ application, and NetApp was written in C#. I want to show native code also because many of you are still supporting C++ applications. Both tools build their Debug builds to D:\Dev\Debug. The Visual SourceSafe version control is on the share, \\Timon\Source, with CppApp and NetApp as projects of $/ (which is the root project in Visual SourceSafe). Note that to index source files with Visual SourceSafe, you are required to set the working directories on the project. I've also applied the version control label "First Version" to the project. Finally, I built both projects. Now they're ready for indexing.

The first step is to ensure that the Visual SourceSafe command line-program (Ss.exe), Perl, and the Source Server programs are all in the path for the command shell you are using. If they are not, nothing will work. Where it gets confusing is when you start debugging. If the version control program is not in the path, the source file fetch silently fails, and you have no idea why you are looking at the Disassembly window.

Another note of caution regarding the Source Server Visual SourceSafe code: although the Source Server Help says that you can specify the server to use on the command line, for Visual SourceSafe, that doesn't work. You'll need to set the SSDIR environment variable to the Visual SourceSafe database. In the case of my example, I'll issue the following command in the command prompt before continuing:

set SSDIR=\\Timon\Source\


Another problem with Visual SourceSafe is the concept of current project, which is the project selected when you end the SourceSafe Explorer GUI. The source indexing for Visual SourceSafe "respects" the current project, which means that it assumes that the current project is the one you want to work on. If you have a single project in your version control system, that's fine, but no one actually does. In order to get the Visual SourceSafe indexing to work, you'll need to set the Visual SourceSafe current project to the project you are about to index. For indexing at the command line, you can set it with the Ss.exe cp option. In my example, I'd run the following command because I'm working with the root project:

 ss cp $/


The second step is to set up Srcsrv.ini for use when indexing, which consists of defining a logical name for the server and the server path itself. The example Srcsrv.ini that is in the C:\Program Files\Debugging Tools for Windows\SDK\SRCSRV directory has more documentation that you'll want to read. In the case of my Visual SourceSafe database, my Srcsrv.ini will look like the following (in the case of Visual SourceSafe, the value to the right of the equal sign must exactly match the value in the SSDIR environment variable, including the trailing backslash):

[variables] BOOKSRC=\\Timon\Source\


In almost all instances, you'll need only the Srcsrv.ini file during the indexing phase. It will store the BOOKSRC logical name and the actual location for the server in the PDB files processed. However, if the machine TIMON dies and you need to move the version control to a different machine, you can put an Srcsrv.ini file in the same directory as the debugger's Srcsrv.dll, and the settings in that file will override what source file indexing embedded in the PDB file. Thus, you wouldn't need to reindex the PDB files.

Another use for the Srcsrv.ini file during debugging is to have the debugger use a mirrored version control system that provides only read-only access. This allows you to share source indexed PDB files across teams and departments in a large company without requiring each team to have direct access to the real version control systems for other teams. Also note that it's perfectly acceptable to include all your company's version control systems in the Srcsrv.ini under the [variables] section and share that file across the company. When I get to the "Debugging with Source Servers" section later in the chapter, I'll discuss the [trusted commands] section of Srcsrv.ini.

When indexing, there are several places where the Srcsrv.ini file can reside. If you've copied the Source Server code directory to its own location on the machine, you can put your version there, and the source indexing tools will pick it up automatically. Alternatively, you can put it in the current directory where you execute the indexing commands. Finally, you can also tell the tools where to find it by using a command-line option or set the SRCSRV_INI environment variable to point to it. In my case, I'll put it in the root directory for my source code (D:\Dev) and run all my indexing commands from there.

To start the indexing, most of you will set command-line options to tell the tools where to find sources, symbols, and the like, so it's important to discuss those command-line options. Since I'm using Visual SourceSafe, I'll run Vssindex.cmd to do my indexing. I could also run the identical Ssindex.cmd /System=VSS. There are two help command-line options, -? and -??; two question marks show you more help than one. If you look at the Help, you'll see there are all sorts of switches and environment variable combinations that you can set to tell the tools what to do.

There are four command-line options of real importance and a fifth necessary for Visual SourceSafe. The first is /Ini, which specifies the Srcsrv.ini file to use. As I mentioned, the file can be placed in numerous spots and automatically be found, but if you want to be specific, you can use /Ini to set it. The /Source switch tells the indexing tools where the source code root starts. The default is the current directory. The indexing script will attempt to correlate any source file found in and below the specified directory with files in the version control system. The /Symbols switch indicates the root directory that will be recursed looking for PDB files; like the source, this directory defaults to the current directory. If the PDB file contains one or more source code files from the version control system, the PDB file will be indexed with the srcsrv stream, which I'll show you later.

For Visual SourceSafe only, the /Label command is required. Because of limitations in Visual SourceSafe, the source indexing cannot figure out the version of a source file in a given directory. Thus, you need to first set a label on the root of the project with Visual SourceSafe and pass that same name to the source indexing tools. Because you should always be labeling your builds for good version control hygiene, that should not be too onerous.

The last command-line option, /Debug, is the most important of all. One major problem with the source indexing tools is if there are any problems and no PDB files are indexed, they give you no notification at all, so you think life is grand until you start debugging and nothing works. You must always run the indexing commands with /Debug so you can see what worked and what didn't.

Given the brief tour of command-line switches, it's time to do some indexing. I have a command prompt open, and my current directory is D:\Dev. Since that's the root of both my source code and symbols, I don't have to set those command-line options. My Srcsrv.ini file is in that directory also, so there is no need to set that command-line value either. I've applied the label "First Version" in SourceSafe already. Lastly, I've set the SSDIR environment variable to set the server to use. Executing the command VSSINDEX /Label="First Version"/Debug produces the output shown in Listing 2-2.

Listing 2-2. Initial Source Indexing Output

[View full width]

[D:\Dev]vssindex /Label="First Version" /debug ------------------------------------------------ -------------------------------- SSIndex.cmd [STATUS] : Server ini file: D:\Dev \srcsrv.ini SSIndex.cmd [STATUS] : Source root : D:\Dev SSIndex.cmd [STATUS] : Symbols root : D:\Dev SSIndex.cmd [STATUS] : Control system : VSS SSIndex.cmd [STATUS] : VSS Server : \\Timon \Source\ SSIndex.cmd [STATUS] : VSS Client Root: D:\Dev SSIndex.cmd [STATUS] : VSS Project : $/ SSIndex.cmd [STATUS] : VSS Label : First Version ------------------------------------------------ -------------------------------- SSIndex.cmd [STATUS] : Running... this will take some time... SSIndex.cmd [STATUS] : Processing ss.exe properties output ... SSIndex.cmd [INFO ] : ... indexing D:\Dev \CppApp\Debug\vc80.pdb SSIndex.cmd [INFO ] : ... zero source files found ... SSIndex.cmd [INFO ] : ... indexing D:\Dev\debug \CppApp.pdb SSIndex.cmd [INFO ] : ... wrote C:\DOCUME~1 \john\LOCALS~1\Temp\indexD9F8.stream to D:\Dev\debug\CppApp.pdb ... SSIndex.cmd [INFO ] : ... indexing D:\Dev\debug \NetApp.pdb SSIndex.cmd [INFO ] : ... wrote C:\DOCUME~1 \john\LOCALS~1\Temp\index18A3B.stream to D:\Dev\debug\NetApp.pdb ... SSIndex.cmd [INFO ] : ... indexing D:\Dev \NetApp\obj\Debug\NetApp.pdb SSIndex.cmd [INFO ] : ... wrote C:\DOCUME~1 \john\LOCALS~1\Temp\index19DD.stream to D:\Dev\NetApp\obj\Debug\NetApp.pdb ...



As you can see in the output, Vssindex.cmd found some PDB files and wrote streams to them, which is how you'll know the tools have indexed a PDB file. Technically, this all worked, but I want to point out some issues in the output. First, scan down until you find the line containing VC80.PDB, which is a PDB file produced by the native C++ build. The line after it says "zero source files found". In the case of any Vc?0.pdb files, that's normal because those are the throwaway type information files, and you don't need them. However, if you see that one of your PDB files reports zero source files, that's a very serious problem, but the indexing tools do not stop on indexing errors. That means that you must very carefully read the output and double-check that your PDB files are all properly indexed. If you did not specify the /debug option, you would not see those lines with [INFO], and you'd have no idea that indexing actually failed.

If you look carefully at the output in Listing 2-2, you might see another problem. Though not very serious, it can slow down your overall indexing performance. I left the /Symbols switch to the default, which treats the current directory as the root for all PDB files. The last PDB file indexed was the file D:\Dev\NetApp\obj\Debug\NetApp.pdb, which for .NET applications is the spot where MSBuild actually builds your application. MSBuild copies them to the output directory you specified as the last step of the build. If you index those files in the Obj directory, you'll be doubling the time it takes to index your sources.

Best practices in general dictate that you build your applications to a central directory or directory tree for easier maintenance. In the case of my example here, everything builds to the D:\Dev\Debug directory. Therefore, if I use the command line:

vssindex /Label= "First Version" /debug /symbols=.\Debug


Vssindex will index only the PDB files I'm going to put in my Symbol Server next.

I've purposely put my source code in the D:\Dev directory to work around a major problem in the indexing code. If all your source directories are directly off the drive root directory, source indexing will not work at all. When I first tried Source Indexing, I had my directories set to D:\CppApp, D:\NetApp, and D:\Debug, and I went absolutely nuts trying to work around this bug. If your build is set up so that all source directories are off the root directory, to work around the bug, you'll need to switch to each source code directory and run the indexing commands. For example, you'd switch to the D:\CppApp directory and run the command:

vssindex /debug /symbols=..\Debug /Ini=..\srcsrv.ini /Project=CppApp


Note that the /Project option is Visual SourceSafespecific. Other version controls systems use a different value to specify the version control project.

If you have more than source code directories at the root, running multiple indexing commands will quickly become painful. You'll be much better off changing your build to be in a directory down from root. That way, you'll have to run the command just once, and the command will automatically pick up all new directories you add without your having to do it manually.

The next surprise with indexing will be if the version control project you want to index is a subproject in your version control system, for example, if my Visual SourceSafe contained one root project, $/Happy, which had two subprojects, $/Happy/Foo and $Happy/Bar. Under the two subprojects to $/Happy were all the subprojects necessary for those pieces of code. If I were responsible only for source indexing $/Happy/Foo, and if the working directory was D:\Dev\Happy\Foo, if I ran the indexing command:

vssindex /debug /Symbols=.\Debug


The indexing would report that zero source code files were indexed.

It took an hour or so for the idea to pop up in my head as to why source indexing wasn't working, but it finally did. The issue is that the default project for source indexing is the root of the version control system. My bad assumption was that the source indexing commands considered the current directory and matched the version control projects appropriately, but they don't. Keep in mind that all my testing is with Visual SourceSafe. If you are using a different version control system, you will need to practice all the scenarios I've discussed to see if there are any foibles in your particular system.

What you need to do to get everything working is to tell the source indexing code which Visual SourceSafe version control project you want to work with using the /Project command-line option. In the example I'm discussing, the command line that will get everything properly indexed is:

vssindex /debug /Symbols=.\Debug /Project=Happy/Foo


The Visual SourceSafe source indexing code will put in the leading "$/" necessary for Ss.exe. It's a very good idea to get in the habit of always specifying the /Project command-line option, even if it is the root, which would be /Project=/. I can't stress enough that you need to manually test various scenarios to see what works and doesn't work in your environment.

In the output of the indexing command, seeing the output that a .stream file was written to the PDB file is enough to rest assured that life is good. If you want to verify the stream, the Pdbstr.exe program allows you to look at what's in that stream. Pdbstr.exe is a little persnickety, so you'll have to get the command-line options just right; otherwise, the output looks like no stream is in the PDB. The first parameter must be -r to indicate you want to read the PDB. The second parameter is -p:file_name.pdb for the PDB you want to look at. The last parameter is the stream you want to see, which is always -s:srcsrv. Listing 2-3 shows the output of running Pdbstr.exe on Netapp.pdb.

Listing 2-3. Pdbstr.exe Output

[View full width]

[D:\Dev\debug]pdbstr -r -p:NetApp.pdb -s:srcsrv SRCSRV: ini ------------------------------------------------ VERSION=1 INDEXVERSION=2 VERCTRL=Visual Source Safe DATETIME=Thu Aug 31 15:35:43 2006 SRCSRV: variables ------------------------------------------ SSDIR=\\Timon\Source\ SRCSRVENV=SSDIR=%BOOKSRC% VSSTRGDIR=%targ%\%var2%\%fnbksl%(%var3%)\%var4% VSS_EXTRACT_CMD=ss.exe get -GL"%vsstrgdir%" -GF- -I-Y -W "$/%var3%" -V"%var4%" VSS_EXTRACT_TARGET=%targ%\%var2%\%fnbksl%(%var3 %)\%var4%\%fnfile%(%var1%) BOOKSRC=\\Timon\Source\ SRCSRVTRG=%VSS_extract_target% SRCSRVCMD=%VSS_extract_cmd% SRCSRV: source files --------------------------------------- d:\Dev\NetApp\Program.cs*BOOKSRC*NetApp/Program .cs*First Version SRCSRV: end ------------------------------------------------



The ini section of the stream tells the tale of the source-indexing version, version control system used, and the time you did the indexing. The variables section shows variables that are used by the debuggers to do the work. The debuggers look for the SRCSRVCMD value and treat values surrounded by percent signs as variables to build up. In Listing 2-3, the VSS_EXTRACT_CMD contains the actual command line that Srcsrv.dll builds up to call the version control system with the appropriate file and extraction directory. The last section, the source files, shows the values that will be filled in as part of the variables. Each line contains the data for a single source file, delineated by asterisks. The first value is the path to the source file as it came from the PDB. The second value, in this case BOOKSRC, indicates the version control database to use. The third field is the version control project, and the last field is the file version in version control. If you want to see a great example of exactly how the data is built up, see the Srcsvr.doc file.

Because of all the niggling surprises I kept running into when I started playing with Source Server, I put together a quick checklist that lists all the issues you need to ensure are set up to achieve Source Server nirvana. That checklist is in Table 2-5. Let's now turn to using the Source Server in the debuggers, the moment you've been waiting for!

Table 2-5. The Source Server Indexing Checklist

Source Server Indexing Checklist

Is your source tree in a directory below the root?

Have you built both debug and release builds?

Have you built all binaries and PDBs to inhabit a logical directory structure?

Did you add your version control logical name(s) to Srcsrv.ini?

Is Srcsrv.ini in the tools directory, the SRCSRV_INI environment variable, or the current directory, or specified with the /Ini switch?

Is your version control system command-line tool in the path?

For Visual SourceSafe, have you set the SSDIR environment variable?

For Visual SourceSafe, is the working directory set for each project?

For Visual SourceSafe, have you applied a label to the project?

Is Perl 5.0 or greater installed and in the path?

Are the Source Server tools and scripts in the path?


Debugging with Source Servers

Turning on Source Server support in WinDBG or its console-based siblings, Ntsd.exe or Cdb.exe, is similar to turning on the Symbol Server support. To turn it on globally for all WinDBG sessions, you have two options: The first is to start WinDBG with no debuggee open and select Source File Path from the File menu to get to the Source Search Path dialog box. The second way is to set the _NT_SOURCE_PATH environment variable. In both cases, you'll want the value to be SRV*c:\symbols;.

The SRV, much like its counterpart in Symbol Servers, tells the debugger that you're expecting to use a Source Server. After the asterisks comes the directory that you want to use as the local cache for all the files. If you don't specify a download cache, which I don't recommend, the sources will be pulled to the Debugging Tools for Windows\Src directory. As the default directory is in Program Files, the pull will abort if you're correctly running in a Least User Access (LUA) environment. In addition to setting source paths globally, you can always set it during a debugging session by running the .srcpath command.

In my development, I like to set the Source Server cache directory to my Symbol Server cache directory. That way, all my caches are in the same place, and if I need to reclaim disk space, I can wipe everything out and immediately start again.

Once you start debugging in WinDBG and perform any operation in which you need source code, the dialog box shown in Figure 2-8 will pop up. This is your sign that everything's starting out great for your Source Server adventure. The upper part of the dialog box shows you the command to run. The set of option buttons allow you to determine how you want Source Server to proceed in the future. If you select Perform This Action Each Time From Now On, that will assign "off" to the Default value in HKEY_CURRENT_USER\Software\Microsoft\Source Server\Warning so you never see the Microsoft Source Server Security Alert dialog box again.

Figure 2-8. WinDBG Source Server Security dialog box


In many cases, you'll want to turn off the security warning and always have WinDBG jump directly to executing the version control command to get the source. However, if you use the Source Server, that's the first place the debugger will look for the source. Even if you have the source on the machine and it's in the exact same directories as embedded in the PDB file, the Source Server execution will be first. If you have a very fast version control system, that might not be any problem, but not everyone does.

An alternative way of disabling the security dialog box is to put a copy of Srcsrv.ini in the Debugging Tools for Windows program directory. That's where Srcsrv.dll resides, and it knows to look for the file there. If Srcsrv.ini has the version control system in the [trusted commands] section, it will not display the security dialog box. For each trusted command, you'll specify on the left side the base name of your version control system command-line program. On the right side, you'll specify the full path to the version control system command-line program. On my machines, my [trusted commands] section looks like the following:

[trusted commands] ss.exe=C:\VSNET8\Microsoft Visual SourceSafe\ss.exe


In the example I'm showing in Figure 2-8, I used a source path of SRV*c:\symbols for demonstration purposes. If you look carefully enough at Figure 2-8, you'll see the whole path where the version control will extract the file, C:\symbols\BOOKSRC\CppApp\CppApp.cpp\First Version. The C:\symbols is obvious, but the rest of the string is how it uniquely identifies the particular source file. The BOOKSRC lines up with the version control identifier specified in Srcsrv.ini when indexing the PDBs. The CppApp directory identifies the version control project, and the CppApp.cpp directory identifies the source file. In the example I'm showing, the file label version is "First Version," which explains why that is the last directory. If I used a version control system that understood file versions, the last directory would be the version number. Like the symbol server, the Source Server uses the file system as a database to uniquely identify the exact version of the file you need. The beauty of this system is that if the Source Server code in Srcsrv.dll sees that the file already exists in the extract directory, it will load the source file from there without querying the version control system for the file.

Once you click Yes in the Microsoft Source Server Security Alert dialog box, if everything has been done correctly, WinDBG displays the source code, and you'll cheer. If you're having trouble with your Source Server in WinDBG, use the .srcnoisy WinDBG command to see the verbose output from Srcsrv.dll. In nearly all cases, that will show you what the problem is.

Setting up Source Server debugging in Visual Studio 2005 is nearly as simple as it is in WinDBG. Instead of using an environment variable, the magic is in the Options dialog box. Once you get to the Options dialog box, navigate to the General node under the Debugging node. In there, as shown in Figure 2-9, you'll see the Enable Source Server Support check box. Select that check box and the indented one below it, Print Source Server Diagnostic Messages To The Output Window. When you click OK, you'll be notified that using the Source Server is a potential security problem, because you're asking the debugger to execute a program in the path. Click Yes, and you're on your way to Source Server heaven.

Figure 2-9. Turning on Source Server in Visual Studio


When you start debugging with Visual Studio, you'll see a slightly different security dialog box, as shown in Figure 2-10. Like WinDBG, it's warning you that you're about to execute a program, and it's giving you a chance to say no. Unfortunately, there's no option that says, "I trust the Symbol Server; I don't want to see this dialog box ever again." That means that for every source file, you'll be prompted with this dialog box, which can get tedious to say the least. As I discussed with WinDBG, you can put a Srcsrv.ini file that defines your [trusted commands] section with your version control system into the Visual_Studio_Install Directory\Common7\IDE and never see the security dialog box again.

Figure 2-10. Visual Studio Source Server Security dialog box


Although it's great that Visual Studio doesn't require a weird SRV* thing in an environment variable to get the source server running, the quiz question is where does Visual Studio put the Source Server download cache? The default location is C:\Documents and Settings\user_name \Local Settings\Application Data\SourceServer. That's great from a security standpoint because with proper security in place, only the logged-in user can see that directory. However, I do want to share the Source Server cache directory so I can share the source between the debuggers. Although you can change the WinDBG source path to SRV*C:\Documents and Settings \user_name\Local Settings\Application Data\SourceServer, I like keeping the source files under my Symbol Server directory as I mentioned earlier.

That began my quest to figure out where Visual Studio sets the cache directory. Poking through each property page accessible from the Options dialog box does not show anything that can set the Source Server cache directory. Looking at the registry, you'll eventually find the SourceServerExtractToDirectory under HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\Debugger, which is where the cache directory setting resides.

Since I don't relish manually changing registry keys because of the great potential for error, I wrote an add-in, HiddenSettings, in Chapter 7, which exposes this key in an Options property page along with a few other undocumented and hidden settings in Visual Studio. The great news here is that the Import and Export Settings Wizard in Visual Studio will properly export and import the settings between machines. One word of caution is that if you import the settings to a new machine where the cache directory does not exist, the Source Server file pull will silently fail, and you'll be left wondering what happened. Always make sure the cache directory exists.

If you are having troubles with the Source Server with Visual Studio, make sure to look at the Output window. There you'll see the reports of any problems with the Source Server. That's the first place you'll go whenever there's anything odd going on with it. In addition, you can verify where the source file is located by moving the mouse cursor over the source file tab in Visual Studio. The tooltip will show you the full path to the open files. Finally, like WinDBG, Visual Studio will grab the source code through the Source Server before it will search the raw paths in the PDB file.

The last tip I want to mention about debugging with Visual Studio 2005 is about Srcsrv.dll file versions. WinDBG generally has two public releases a year, while Visual Studio has less than that. The WinDBG team is working hard making bug fixes and performance improvements to Srcsrv.dll, thus the version with the latest version of WinDBG is always an improvement over the version that shipped with Visual Studio 2005. It's up to you, but I always copy the latest x86 version of Srcsrv.dll to the Visual_Studio_Install_Directory\Common7\IDE directory to ensure that Visual Studio 2005 is always using the latest and greatest version. Even if you're using only 64-bit versions of Windows, Visual Studio 2005 is a 32-bit x86 program, so that's why you need the 32-bit version. Given your newfound Source Server debugging prowess, I want to turn to a much-improved source-indexing tool.

Better and Easier Source Server Indexing

Up to this point, I've covered all the painful manual steps you need to apply Source Server in your development shop. However, if you're like me, you quickly realized that manually executing a batch file to do your source indexing and manually reading its output to see if everything worked is a complete waste of time. As soon as you have more than five binaries in your project, your eyes will glaze over, and you'll miss that one binary you need source indexed, to the detriment of everyone on your team.

As I mentioned back in the "Wonderful MSBuild" section, I set up a couple of tasks to make indexing your source code easier. Because Source Server is so vital to better debugging, I want to spend some time going over the requirements and the task specifics so you can better apply these tasks to your development shop.

My requirements for a good source indexing task are pretty simple: if there's any problem indexing source files, generate an error to stop MSBuild. Those problems can occur if

  • There's any kind of [ERROR] output from Ssindex.cmd.

  • There's any PDB file indexing that reports zero source files found.

  • There are no source files indexed at all.

The last error is particularly insidious with source indexing because it reports no errors at all, so you think that life is great.

Given those requirements, my plan was to build a reusable base task, SourceIndexTask, that all version control product-specific tasks could inherit from. Additionally, I wanted to do the VssSourceIndexTask because so many of you are using Visual SourceSafe, and it has the additional required items I discussed earlier. If you do write a task for a Source Serversupported version control system, please send it to me, and I'll include it in Wintellect.Build.Tasks.DLL and post the code for everyone's use.

To keep life slightly simpler, I did make a couple of assumptions about the Source Server tools and your directory setup. My tasks assume that you have the Source Indexing tools in the path. The base SourceIndexTask will hunt the tools down in the path because MSBuild will not run unless the full path to the tools is present. The second assumption is that your directory setup matches your version control project names. While the various product-specific indexing scripts allow you to set project and client parameters, it's much better if directory names align with project names. That way, you can run the indexing script at the top directory, and everything just works. If there are mismatches, you'll have to run the source indexing separately on each directory, which is a major pain.

The SourceIndexTask has three required properties that you must set in your .proj files. The first is Symbols, which defines the directory where your PDB files are located and can be a relative path from your .proj file. The second is Sources. I had to make Sources required, because the source indexing commands work best if I have the task switch to the sources directory before executing the commands.

The last required parameter is VersionControlSystem, which defines the version control system. This parameter is not marked with RequiredAttribute because I didn't want derived classes, such as VssSourceIndexTask, to require redundantly specifying the version control system all over again. However, if VersionControlSystem is not defined, the task will report an error as though it were required.

The first of the optional properties to SourceIndexTask is IniFile, and you can use that property in case you want to explicitly specify the location of your Srcsrv.ini file. The AdditionalCommandLineOptions property lets you add any additional commands not covered by derived types. It's also very useful if you are using a version control system that does not have its own task class and you want to get started with indexing immediately. You can add the version controlspecific files to the AdditionalCommandLineOptions and be up and running. Obviously, there's no error checking on the values inside AdditionalCommandLineOptions.

The last of the optional properties is IgnorePdbFiles. This ITaskItem array is where you can put PDB files on which you don't care if source indexing reports an error while processing. This can happen on automatically generated binaries and items, such as the Vc?0.pdb type files I described earlier. The SourceIndexTask already knows to ignore Vc60.pdb, Vc70.pdb, and Vc80.pdb, but this property gives you the place to add any additional PDBs on which you don't want error checking performed.

The VssSourceIndexTask, which is the task that handles Visual SourceSafe, defines two required parameters. The first, Server, holds the version control system server name. The second required parameter is Label because Visual SourceSafe cannot be indexed without a version label. The task does the right thing and sets the SSDIR environment variable before executing the indexing commands to work around the bug in the Visual SourceSafe processing.

The Project optional parameter deserves some explanation. As I described earlier, if you are indexing source code from a project that's below the top level in Visual SourceSafe, the indexing will not work. If you do not set the Project property, the VssSourceIndexTask will take the Source property, expand it to the full path, and convert that path to the Visual SourceSafe project. If your Visual SourceSafe projects map to your file directories, this will automatically set the /Project option with no effort on your part. If you do set the Project property, that value is sacred and not changed by the task, so VssSourceIndexTask passes it directly to the source indexing tools.

The one small issue here with the Project property occurs if you are working with projects directly off $/ (the Visual SourceSafe root). In that case, you need to manually set the Project property to / in your MSBuild project to keep everything straight. I've wracked my brain on how to best handle subproject indexing, and this is the best I've come up with. If you have a better idea, please don't hesitate to contact me!

To see all the magic in action, look at the MSBuild project, SourceServerIndex.proj, in the .\Build directory. This project indexes the source code for everything in the book. Yes, there's nothing like dogfooding yourself.

From an implementation standpoint, there's not much hacking and excitement in the code. The most interesting challenge was figuring out how I was going to handle looking for errors in the source indexing output. I originally thought I'd redirect the output to a file and use my super regular expression skills to parse up all the problems. However, I found the power of the ToolTask.LogEventsFromTextOutput method to process each of the lines as they came in. I set up a simple state machine so I could report any possible problems when it comes to indexing.




Debugging Microsoft  .NET 2.0 Applications
Debugging Microsoft .NET 2.0 Applications
ISBN: 0735622027
EAN: 2147483647
Year: 2006
Pages: 99
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net