Exemple #1
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);
    }
Exemple #2
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;
    }