public static int DoMain(String[] args) { String dacFile = null; String pdbFile = null; String mapFile = null; String binFile = null; String dllFile = null; for (int i = 0; i < args.Length; i++) { if (MatchArg(args[i], dacSwitch)) { dacFile = args[i].Substring(dacSwitch.Length); } else if (MatchArg(args[i], pdbSwitch)) { pdbFile = args[i].Substring(pdbSwitch.Length); } else if (MatchArg(args[i], mapSwitch)) { mapFile = args[i].Substring(mapSwitch.Length); } else if (MatchArg(args[i], binSwitch)) { binFile = args[i].Substring(binSwitch.Length); } else if (MatchArg(args[i], dllSwitch)) { dllFile = args[i].Substring(dllSwitch.Length); } else if (MatchArg(args[i], ignoreErrorsSwitch)) { s_ignoreErrors = true; } else { Help(); return(1); } } if (dacFile == null || (pdbFile == null && mapFile == null) || (dllFile == null && pdbFile != null) || binFile == null) { HelpHdr(); Console.WriteLine(); Console.WriteLine("Required option missing."); // Provide some extra help if just the new dllFile option is missing if ((dllFile == null) && (dacFile != null) && (binFile != null) && (pdbFile != null)) { Console.WriteLine("NOTE that /dll is a new required argument which must point to mscorwks.dll."); Console.WriteLine("Ideally all uses of DacTableGen.exe should use the build logic in ndp/clr/src/DacUpdateDll."); } Console.WriteLine(); HelpBody(); return(1); } // Validate the specified files exist string[] inputFiles = new string[] { dacFile, pdbFile, mapFile, dllFile }; foreach (string file in inputFiles) { if (file != null && !File.Exists(file)) { Console.WriteLine("ERROR, file does not exist: " + file); return(1); } } HelpHdr(); Console.WriteLine(); List <UInt32> rvaArray = new List <UInt32>(); UInt32 numGlobals; UInt32 debugTimestamp = 0; if (pdbFile != null) { #if FEATURE_PAL throw new InvalidOperationException("Not supported in Rotor."); #else PdbSymbolProvider pdbSymProvider = new PdbSymbolProvider(pdbFile, dllFile); // Read the mscorwks debug directory timestamp debugTimestamp = pdbSymProvider.DebugTimestamp; if (debugTimestamp == 0) { throw new System.ApplicationException("Didn't get debug directory timestamp from DIA"); } DateTime dt = new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc); dt = dt.AddSeconds(debugTimestamp).ToLocalTime(); // Output information about the PDB loaded Console.WriteLine("Processing DLL with PDB timestamp: {0}", dt.ToString("F")); Console.WriteLine("Loaded PDB file: " + pdbSymProvider.LoadedPdbPath); if (Path.GetFullPath(pdbSymProvider.LoadedPdbPath).ToLowerInvariant() != Path.GetFullPath(pdbFile).ToLowerInvariant()) { // DIA loaded a PDB oter than the one the user asked for. This could possibly happen if the PDB // also exists in a sub-directory that DIA automatically probes for ("retail" etc.). There doesn't // appear to be any mechanism for turning this sub-directory probing off, but all other searching mechanisms // should be turned off by the DiaLoadCallback. This could also happen if the user specified an incorrect // (but still existing) filename in a path containing the real PDB. Since DIA loaded it, it must match the DLL, // and so should only be an exact copy of the requested PDB (if the requested PDB actuall matches the DLL). So // go ahead and use it anyway with a warning. To be less confusing, we could update the command-line syntax // to take a PDB search path instead of a filename, but that inconsistent with the map path, and probably not // worth changing semantics for. In practice this warning will probably never be hit. Shell.Error("Loaded PDB path differs from requested path: " + pdbFile); } Console.WriteLine(); ScanDacFile(dacFile, pdbSymProvider, rvaArray, out numGlobals); if (mapFile != null) { List <UInt32> mapRvaArray = new List <UInt32>(); UInt32 mapNumGlobals; // check that both map file and pdb file produce same output to avoid breakages on Rotor ScanDacFile(dacFile, new MapSymbolProvider(mapFile), mapRvaArray, out mapNumGlobals); // Produce a nice message to include with any errors. For some reason, binplace will silently fail // when a PDB can't be updated due to file locking. This means that problems of this nature usually // occur when mscorwks.pdb was locked when mscorwks.dll was last rebuilt. string diagMsg = String.Format(". This is usually caused by mscorwks.pdb and mscorwks.map being out of sync. " + "Was {0} (last modified {1}) in-use and locked when {2} was built (last modified {3})? " + "Both should have been created when {4} was last rebuilt (last modified {5}).", pdbFile, File.GetLastWriteTime(pdbFile), mapFile, File.GetLastWriteTime(mapFile), dllFile, File.GetLastWriteTime(dllFile)); if (rvaArray.Count != mapRvaArray.Count) { throw new InvalidOperationException("Number of RVAs differes between pdb file and map file: " + numGlobals + " " + mapNumGlobals + diagMsg); } for (int i = 0; i < rvaArray.Count; i++) { if (rvaArray[i] != mapRvaArray[i] // it is ok if we find more stuff in the MAP file && rvaArray[i] != UInt32.MaxValue) { throw new InvalidOperationException("RVAs differ between pdb file and map file: " + ToHexNB(rvaArray[i]) + " " + ToHexNB(mapRvaArray[i]) + diagMsg); } } if (numGlobals != mapNumGlobals) { throw new InvalidOperationException("Number of globals differes between pdb file and map file: " + numGlobals + " " + mapNumGlobals + diagMsg); } } #endif } else { ScanDacFile(dacFile, new MapSymbolProvider(mapFile), rvaArray, out numGlobals); } if (s_errors && !s_ignoreErrors) { Console.Error.WriteLine( "DacTableGen : fatal error : Failing due to above validation errors. " + "Do you have an #ifdef (or name) mismatch between the symbol definition and the entry specified? " + "Or perhaps the symbol referenced was optimized away as unused? " + "If you're stuck, send e-mail to 'ClrDac'. Worst case, these errors can be temporarily ignored by passing the /ignoreerrors switch - but you may cause runtime failures instead."); return(1); } UInt32 numVptrs; numVptrs = (UInt32)rvaArray.Count - numGlobals; FileStream outFile = new FileStream(binFile, FileMode.Create, FileAccess.Write); BinaryWriter binWrite = new BinaryWriter(outFile); // Write header information binWrite.Write(numGlobals); binWrite.Write(numVptrs); binWrite.Write(debugTimestamp); binWrite.Write(0); // On Windows we only need a 4-byte timestamp, but on Mac we use binWrite.Write(0); // a 16-byte UUID. We need to be consistent here. binWrite.Write(0); // Write out the table of RVAs for (int i = 0; i < numGlobals + numVptrs; i++) { binWrite.Write(rvaArray[i]); } binWrite.Close(); return(0); }
public static int DoMain(String[] args) { String dacFile = null; String pdbFile = null; String mapFile = null; String binFile = null; String dllFile = null; for (int i = 0; i < args.Length; i++) { if (MatchArg(args[i], dacSwitch)) { dacFile = args[i].Substring(dacSwitch.Length); } else if (MatchArg(args[i], pdbSwitch)) { pdbFile = args[i].Substring(pdbSwitch.Length); } else if (MatchArg(args[i], mapSwitch)) { mapFile = args[i].Substring(mapSwitch.Length); } else if (MatchArg(args[i], binSwitch)) { binFile = args[i].Substring(binSwitch.Length); } else if (MatchArg(args[i], dllSwitch)) { dllFile = args[i].Substring(dllSwitch.Length); } else if (MatchArg(args[i], ignoreErrorsSwitch)) { s_ignoreErrors = true; } else { Help(); return 1; } } if (dacFile == null || (pdbFile == null && mapFile == null) || (dllFile == null && pdbFile != null) || binFile == null) { HelpHdr(); Console.WriteLine(); Console.WriteLine("Required option missing."); // Provide some extra help if just the new dllFile option is missing if ((dllFile == null) && (dacFile != null) && (binFile != null) && (pdbFile != null)) { Console.WriteLine("NOTE that /dll is a new required argument which must point to mscorwks.dll."); Console.WriteLine("Ideally all uses of DacTableGen.exe should use the build logic in ndp/clr/src/DacUpdateDll."); } Console.WriteLine(); HelpBody(); return 1; } // Validate the specified files exist string[] inputFiles = new string[] { dacFile, pdbFile, mapFile, dllFile }; foreach (string file in inputFiles) { if (file != null && !File.Exists(file)) { Console.WriteLine("ERROR, file does not exist: " + file); return 1; } } HelpHdr(); Console.WriteLine(); List<UInt32> rvaArray = new List<UInt32>(); UInt32 numGlobals; UInt32 debugTimestamp = 0; if (pdbFile != null) { #if FEATURE_PAL throw new InvalidOperationException("Not supported in Rotor."); #else PdbSymbolProvider pdbSymProvider = new PdbSymbolProvider(pdbFile, dllFile); // Read the mscorwks debug directory timestamp debugTimestamp = pdbSymProvider.DebugTimestamp; if (debugTimestamp == 0) { throw new System.ApplicationException("Didn't get debug directory timestamp from DIA"); } DateTime dt = new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc); dt = dt.AddSeconds(debugTimestamp).ToLocalTime(); // Output information about the PDB loaded Console.WriteLine("Processing DLL with PDB timestamp: {0}", dt.ToString("F")); Console.WriteLine("Loaded PDB file: " + pdbSymProvider.LoadedPdbPath); if (Path.GetFullPath(pdbSymProvider.LoadedPdbPath).ToLowerInvariant() != Path.GetFullPath(pdbFile).ToLowerInvariant()) { // DIA loaded a PDB oter than the one the user asked for. This could possibly happen if the PDB // also exists in a sub-directory that DIA automatically probes for ("retail" etc.). There doesn't // appear to be any mechanism for turning this sub-directory probing off, but all other searching mechanisms // should be turned off by the DiaLoadCallback. This could also happen if the user specified an incorrect // (but still existing) filename in a path containing the real PDB. Since DIA loaded it, it must match the DLL, // and so should only be an exact copy of the requested PDB (if the requested PDB actuall matches the DLL). So // go ahead and use it anyway with a warning. To be less confusing, we could update the command-line syntax // to take a PDB search path instead of a filename, but that inconsistent with the map path, and probably not // worth changing semantics for. In practice this warning will probably never be hit. Shell.Error("Loaded PDB path differs from requested path: " + pdbFile); } Console.WriteLine(); ScanDacFile(dacFile, pdbSymProvider, rvaArray, out numGlobals); if (mapFile != null) { List<UInt32> mapRvaArray = new List<UInt32>(); UInt32 mapNumGlobals; // check that both map file and pdb file produce same output to avoid breakages on Rotor ScanDacFile(dacFile, new MapSymbolProvider(mapFile), mapRvaArray, out mapNumGlobals); // Produce a nice message to include with any errors. For some reason, binplace will silently fail // when a PDB can't be updated due to file locking. This means that problems of this nature usually // occur when mscorwks.pdb was locked when mscorwks.dll was last rebuilt. string diagMsg = String.Format(". This is usually caused by mscorwks.pdb and mscorwks.map being out of sync. " + "Was {0} (last modified {1}) in-use and locked when {2} was built (last modified {3})? " + "Both should have been created when {4} was last rebuilt (last modified {5}).", pdbFile, File.GetLastWriteTime(pdbFile), mapFile, File.GetLastWriteTime(mapFile), dllFile, File.GetLastWriteTime(dllFile)); if (rvaArray.Count != mapRvaArray.Count) throw new InvalidOperationException("Number of RVAs differes between pdb file and map file: " + numGlobals + " " + mapNumGlobals + diagMsg); for (int i = 0; i < rvaArray.Count; i++) { if (rvaArray[i] != mapRvaArray[i] // it is ok if we find more stuff in the MAP file && rvaArray[i] != UInt32.MaxValue) { throw new InvalidOperationException("RVAs differ between pdb file and map file: " + ToHexNB(rvaArray[i]) + " " + ToHexNB(mapRvaArray[i]) + diagMsg); } } if (numGlobals != mapNumGlobals) throw new InvalidOperationException("Number of globals differes between pdb file and map file: " + numGlobals + " " + mapNumGlobals + diagMsg); } #endif } else { ScanDacFile(dacFile, new MapSymbolProvider(mapFile), rvaArray, out numGlobals); } if (s_errors && !s_ignoreErrors) { Console.Error.WriteLine( "DacTableGen : fatal error : Failing due to above validation errors. " + "Do you have an #ifdef (or name) mismatch between the symbol definition and the entry specified? " + "Or perhaps the symbol referenced was optimized away as unused? " + "If you're stuck, send e-mail to 'ClrDac'. Worst case, these errors can be temporarily ignored by passing the /ignoreerrors switch - but you may cause runtime failures instead."); return 1; } UInt32 numVptrs; numVptrs = (UInt32)rvaArray.Count - numGlobals; FileStream outFile = new FileStream(binFile, FileMode.Create, FileAccess.Write); BinaryWriter binWrite = new BinaryWriter(outFile); // Write header information binWrite.Write(numGlobals); binWrite.Write(numVptrs); binWrite.Write(debugTimestamp); binWrite.Write(0); // On Windows we only need a 4-byte timestamp, but on Mac we use binWrite.Write(0); // a 16-byte UUID. We need to be consistent here. binWrite.Write(0); // Write out the table of RVAs for (int i = 0; i < numGlobals + numVptrs; i++) { binWrite.Write(rvaArray[i]); } binWrite.Close(); return 0; }