Navigation

    Inedo Community Forums

    Forums

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    1. Home
    2. it_9582
    I
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    it_9582

    @it_9582

    0
    Reputation
    20
    Posts
    3
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    it_9582 Follow

    Best posts made by it_9582

    This user hasn't posted anything yet.

    Latest posts made by it_9582

    • RE: Symbol Server id issue

      Hi @atripp,

      sorry for my late response, but I was in vocation. We have tested your send MicrosoftPdbFile class without any issues.
      The read out PDB Informations (Guid and Age) are the same as our code read and the llvm-pdbutil dump --summary tool.

      It seams so that another code fragment around this class will cause this issue.

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,
      I understand that it will not be simple to find the possible issue in the huge MicrosoftPdbFile class. As first step it would be nice if you could compare the code of my colleague with your class and if this not help than you could possibly share the class code with me so that we could verify this.

      The PdbFile class of my colleague is the following:

      namespace Pdbreader;
      
      // Adapted and ported from https://github.com/symstore/symstore/blob/master/symstore/pdb.py
      /*
       * Copyright(c) 2019 Lennart Blanco
       *
       * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
       * associated documentation files (the "Software"), to deal in the Software without restriction,
       * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
       * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
       * subject to the following conditions:
       *
       * The above copyright notice and this permission notice shall be included in all copies or substantial
       * portions of the Software.
       *
       * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       */
      
      using System.Buffers.Binary;
      
      public class PdbInvalidSignatureException : Exception
      {
          public PdbInvalidSignatureException() : base("Invalid PDB signature.") { }
          public PdbInvalidSignatureException(string message) : base(message) { }
          public PdbInvalidSignatureException(string message, Exception inner) : base(message, inner) { }
      }
      
      /// <summary>
      /// This class supports reading Windows PDB files and extracting the GUID and Age found
      /// inside to create the GUID used by the Symbol server path.
      /// </summary>
      public class PdbFile
      {
          private static ReadOnlySpan<byte> ExpectedSignature =>
          [
              0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x2F,
              0x43, 0x2B, 0x2B, 0x20, 0x4D, 0x53, 0x46, 0x20, 0x37, 0x2E, 0x30, 0x30,
              0x0D, 0x0A, 0x1A, 0x44, 0x53, 0x00, 0x00, 0x00
          ];
      
          /// <summary>
          /// Parses a PDB file at the given path, extracting its GUID and age.
          /// </summary>
          /// <param name="filepath">The full path to the <c>.pdb</c> file to read.</param>
          /// <exception cref="PdbInvalidSignatureException">
          /// Thrown if the file does not begin with the expected MSF 7.00 signature.
          /// </exception>
          public PdbFile(string filepath)
          {
              using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
              using var reader = new BinaryReader(fs);
      
              Span<byte> sig = stackalloc byte[ExpectedSignature.Length];
              var bytesRead = reader.Read(sig);
              if (bytesRead < ExpectedSignature.Length || !sig.SequenceEqual(ExpectedSignature))
              {
                  throw new PdbInvalidSignatureException();
              }
      
              var pageSize    = reader.ReadInt32();
              reader.ReadInt32(); // free page map index
              reader.ReadInt32(); // pages used
              var rootDirSize = reader.ReadInt32();
              reader.ReadInt32(); // reserved
      
              var root = new Root(reader, pageSize, rootDirSize);
      
              // --- Read PDB stream (stream index 1) ---
              var pdbStreamData = root.ReadStream(1);
              using var pdbMs = new MemoryStream(pdbStreamData);
              using var pdbBr = new BinaryReader(pdbMs);
      
              pdbBr.ReadInt32(); // Version
              pdbBr.ReadInt32(); // Signature/Timestamp
              var pdbAge    = pdbBr.ReadInt32();
              var guidBytes = pdbBr.ReadBytes(16);
              Guid = new Guid(guidBytes);
      
              // --- Read DBI stream (stream index 3) ---
              var dbiStreamData = root.ReadStream(3);
              if (dbiStreamData.Length >= 12)
              {
                  using var dbiBr = new BinaryReader(new MemoryStream(dbiStreamData));
                  dbiBr.ReadInt32(); // Signature
                  dbiBr.ReadInt32(); // Version
                  Age = dbiBr.ReadInt32();
              }
              else
              {
                  Age = pdbAge;
              }
          }
      
          /// <summary>
          /// Get the Guid found in the PDB file
          /// </summary>
          public Guid Guid { get; }
          
          /// <summary>
          /// The age of the PDB, used to match it against its corresponding binary.
          /// Sourced from the DBI stream where available, falling back to the PDB info stream.
          /// </summary>
          public int Age   { get; }
      
          /// <summary>
          /// Returns the symbol store lookup key for this PDB in the format <c>{GUID}{Age}</c>,
          /// e.g. <c>3844DBD05CC449FEB97320D39D627B2F1</c>.
          /// </summary>
          public string ToStoreFormat() => $"{Guid:N}".ToUpperInvariant() + Age;
      }
      
      internal class Root
      {
          private readonly BinaryReader _reader;
          private readonly int _pageSize;
          private readonly int _size;
      
          private uint[]? _rootPages;
          private uint? _cachedNumStreams;
          private int[]? _cachedStreamSizes;
      
          private const int HeaderSize = 32; // signature
          private const int HeaderInts = 5;  // pageSize, fpmIdx, pagesUsed, rootDirSize, reserved
      
          public Root(BinaryReader reader, int pageSize, int size)
          {
              _reader   = reader;
              _pageSize = pageSize;
              _size     = size;
          }
      
          private static int PageCount(int size, int pageSize) => (int)Math.Ceiling((double)size / pageSize);
      
          private uint[] GetRootPages()
          {
              if (_rootPages is not null) return _rootPages;
      
              var numPages = PageCount(_size, _pageSize);
      
              _reader.BaseStream.Seek(HeaderSize + 4 * HeaderInts, SeekOrigin.Begin);
      
              var numIndexPages = PageCount(numPages * 4, _pageSize);
              var indexPages    = new uint[numIndexPages];
              for (var i = 0; i < numIndexPages; i++)
              {
                  indexPages[i] = _reader.ReadUInt32();
              }
      
              var rootPageData = new byte[numIndexPages * _pageSize];
              for (var i = 0; i < indexPages.Length; i++)
              {
                  _reader.BaseStream.Seek(indexPages[i] * _pageSize, SeekOrigin.Begin);
                  var chunk = _reader.ReadBytes(_pageSize);
                  Buffer.BlockCopy(chunk, 0, rootPageData, i * _pageSize, chunk.Length);
              }
      
              _rootPages = new uint[numPages];
              using var br = new BinaryReader(new MemoryStream(rootPageData));
              for (var i = 0; i < numPages; i++)
              {
                  _rootPages[i] = br.ReadUInt32();
              }
      
              return _rootPages;
          }
      
          /// <summary>Reads <paramref name="length"/> bytes starting at <paramref name="start"/> within
          /// the root directory stream (not an arbitrary stream).</summary>
          private byte[] ReadFromRoot(int start, int length)
          {
              var pages      = GetRootPages();
              var result     = new byte[length];
              var destOffset = 0;
              var startPage  = start / _pageSize;
              var startByte  = start % _pageSize;
      
              _reader.BaseStream.Seek(pages[startPage] * _pageSize + startByte, SeekOrigin.Begin);
      
              var toRead = Math.Min(length, _pageSize - startByte);
              Buffer.BlockCopy(_reader.ReadBytes(toRead), 0, result, destOffset, toRead);
              destOffset += toRead;
              length     -= toRead;
              startPage++;
      
              while (length > 0)
              {
                  _reader.BaseStream.Seek(pages[startPage] * _pageSize, SeekOrigin.Begin);
                  toRead = Math.Min(_pageSize, length);
                  Buffer.BlockCopy(_reader.ReadBytes(toRead), 0, result, destOffset, toRead);
                  destOffset += toRead;
                  length     -= toRead;
                  startPage++;
              }
      
              return result;
          }
      
          private uint GetNumStreams() =>
              _cachedNumStreams ??= BinaryPrimitives.ReadUInt32LittleEndian(ReadFromRoot(0, 4));
      
          private int[] GetAllStreamSizes()
          {
              if (_cachedStreamSizes is not null) return _cachedStreamSizes;
      
              var count = (int)GetNumStreams();
              var raw   = ReadFromRoot(4, count * 4);
              _cachedStreamSizes = new int[count];
              for (var i = 0; i < count; i++)
              {
                  _cachedStreamSizes[i] = BinaryPrimitives.ReadInt32LittleEndian(raw.AsSpan(i * 4, 4));
              }
      
              return _cachedStreamSizes;
          }
      
          private uint[] GetStreamPages(int streamIndex)
          {
              var sizes     = GetAllStreamSizes();
              var numStreams = (int)GetNumStreams();
      
              if (streamIndex >= numStreams)
              {
                  throw new IndexOutOfRangeException($"Stream index {streamIndex} out of range (count: {numStreams}).");
              }
      
              var pagesOffset = 4 + 4 * numStreams;
              for (var i = 0; i < streamIndex; i++)
              {
                  var sz = sizes[i];
                  if (sz > 0)
                  {
                      pagesOffset += PageCount(sz, _pageSize) * 4;
                  }
              }
      
              var streamSize = sizes[streamIndex];
              if (streamSize <= 0) return []; // nil or empty stream
      
              var numPages = PageCount(streamSize, _pageSize);
              var rawPages = ReadFromRoot(pagesOffset, 4 * numPages);
              var pages    = new uint[numPages];
              for (var i = 0; i < numPages; i++)
              {
                  pages[i] = BinaryPrimitives.ReadUInt32LittleEndian(rawPages.AsSpan(i * 4, 4));
              }
      
              return pages;
          }
      
          /// <summary>Reads the full contents of a numbered MSF stream across all its pages.</summary>
          public byte[] ReadStream(int streamIndex)
          {
              var sizes = GetAllStreamSizes();
              if (streamIndex >= sizes.Length)
              {
                  return [];
              }
      
              var streamSize = sizes[streamIndex];
              if (streamSize <= 0)
              {
                  return [];
              }
      
              var pages      = GetStreamPages(streamIndex);
              var result     = new byte[streamSize];
              var remaining  = streamSize;
              var destOffset = 0;
      
              foreach (var page in pages)
              {
                  _reader.BaseStream.Seek(page * _pageSize, SeekOrigin.Begin);
                  var toRead = Math.Min(_pageSize, remaining);
                  var chunk  = _reader.ReadBytes(toRead);
                  Buffer.BlockCopy(chunk, 0, result, destOffset, toRead);
                  destOffset += toRead;
                  remaining  -= toRead;
              }
      
              return result;
          }
      }
      

      and he wrote this simple test program for this:

      namespace Pdbreader;
      
      public static class PdbReader
      {
          public static void Main(string[] args)
          {
              if (args.Length != 1)
              {
                  Console.WriteLine("Usage: PdbReader <pdb_file>");
                  return;
              }
      
              try
              {
                  var path = args[0];
                  var filename = Path.GetFileName(path);
                  var pdb = new PdbFile(path);
                  Console.WriteLine($"GUID: {pdb.ToStoreFormat()}");
                  Console.WriteLine($"Symstore path should be: <root>/{filename}/{pdb.ToStoreFormat()}/{filename}");
      
                  // The following will not work with windows pdbs, only the portable ones
                  //var metaStr = PortableMetaData.GetGuidString(args[0]);
                  //Console.WriteLine($"Meta-GUID: {metaStr}");
              }
              catch (Exception e)
              {
                  Console.WriteLine($"Exception: {e}");
              }
          }
      }
      

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,
      that makes sense. Than in our situation the the PortablePdbFile load will fail and your MicrosoftPdbFile class will load the informations, but that seems to be wrong, because the ID not match.

      Are there any possibilities to fix this possible failed readout in the MicrosoftPdbFile class?

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,
      thanks for the informationsand the Code snippet. We have tested the code but with our PDB File we get the following exception: System.BadImageFormatException: Invalid COR20 header signature on the call of GetMetadataReader(). Could this the reason for the issue?

      A college of me has implemented a sample C# readout of the GUID and AGE for the old Windows PDB Full format. Would it be a possibility to you, to add this code which allows to readout the needed information and publish the pdb correctly on the nuget symbol server feed? I could oversend you the implementation.

      As a side note. We have successfully used a Asset-Feed to fake a Symbol-Server:

      • Create the needed Folder-Structure on the Asset-Feed
        • <pdb-filename>/<PDB-GUID><PDB-AGE>
      • Store the PDB into this Folder-Structure
        • <pdb-filename>/<PDB-GUID><PDB-AGE>/<pdb-file>

      This was a working workaround, but it is not really nice to handle this construct, instead of bundling a nuget-Package with the pdb.

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,

      yes, this is correct. Windbg wants to download the symbol with ID 0511335... but ProGet shows me Symbol 58544d5... for the pdb in my uploaded nupkg.

      I have now dumped now the pdb file header which shows me that our pdb is a Windows PDB (Full) not a PortablePdb. Could it be possible that the MetadataReader is impossible to read the Windows PDB Files, because it reads the metadata defined by ECMA 335 instead of MSF?

      Why the Download of the 58544d5... Symbol file is impossible although it is listed, remains a mystery to me too. Is it possible to get more debug informations from the System to analyse it deeper?

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,
      we have upgraded our ProGet Version to v2025.22 (Build 14) but the issue seems to be persist.
      I have also repackage and reupload the package but the result is still the same.

      The Information on windbg is also the same (it attempts to download the pdb-file with the ID 0511335DB9CE4BAF97DE8C9227DF7E101 but the Symbol on ProGet-Symbol shows me the ID 58544d524263363572307558336f79534a39392b45413d3d).
      The Log in Windbg looks like the following:

      SYMSRV:  BYINDEX: 0x2
               c:\symcache*<ProGet-Base-URL>/symbols/<feed-name>
               <pdb-name>.pdb
               0511335DB9CE4BAF97DE8C9227DF7E101
      SYMSRV:  HTTPGET: /symbols/<feed-name>/<pdb-name>.pdb/0511335DB9CE4BAF97DE8C9227DF7E101/<pdb-name>.pdb
      SYMSRV:  HttpQueryInfo: 80190194 - HTTP_STATUS_NOT_FOUND
      DBGHELP: <pdb-name> - no symbols loaded
      

      I have tested to manually download the file (over both IDs) but each time I get a 404 from the ProGet-Server with:

      • <ProGet-Base-URL>/symbols/<feed-name>/<pdb-name>.pdb/0511335DB9CE4BAF97DE8C9227DF7E101/<pdb-name>.pdb
      • <ProGet-Base-URL>/symbols/<feed-name>/<pdb-name>.pdb/58544d524263363572307558336f79534a39392b45413d3d/<pdb-name>.pdb

      Best regards

      posted in Support
      I
      it_9582
    • RE: Symbol Server id issue

      Hi @atripp,

      currently we are using ProGet 2025.14, so we first check if an upgrade of ProGet 2024.19 or higher would fix the Issue.
      I will reply to this topic if the Issue always exists.

      Best regards

      posted in Support
      I
      it_9582
    • Symbol Server id issue

      Hi there,

      I currently want to evaluate the possibility to of using a nuget Feed as Symbol-Server (configured as Mixed) for our self compiled applications.
      To do this I attached the *.pdb File into a simple nuget package based on the following sample nuspec File:

      <?xml version="1.0"?>
      <package >
        <metadata>
          <id>Sample Tool</id>
          <version>1.0.0</version>
          <authors>Our Company</authors>
          <description>Native C++ Application</description>
        </metadata>
        <files>
          <file src="sample_tool.pdb" target="lib" />
        </files>
      </package>
      

      I uploaded this package into the feed, which shows me the package and also on the Symbols tab the pdb file with Id (58544d524263363572307558336f79534a39392b45413d3d) and Age (1).

      Now I configured the windbg to interact with the Feed Symbol-Server (set Symbol path to <Server-URL>/symbols/<feed-name>) and open the Executable for this pdb File.
      I activated than the noisy symbol loading (!sym noisy) because there are some issues while loading the symbols. The Log shows me that windbg want to download the pdb File from the a different URL, because the id is different (/symbols/<feed-name>/sample_tool.pdb/0511335DB9CE4BAF97DE8C9227DF7E101/sample_tool.pdb
      ).

      I analysed our PDB File and it seems that the ID generation of ProGet has possibly a issue because a call of llvm-pdbutil dump --summary sample_tool.pdb results in the following Information:

      • Age = 1
      • GUID = {0511335D-B9CE-4BAF-97DE-8C9227DF7E10}

      After combining this data (GUID + Age) the result is 0511335DB9CE4BAF97DE8C9227DF7E101 which is the same as Windbg want to download 0511335DB9CE4BAF97DE8C9227DF7E101.

      Do you have any suggestions what I can do to use this feature?

      Best regards

      posted in Support
      I
      it_9582
    • RE: ProGet 2025.14 (Build 12) - PostgreSQL Error when uploading

      For now we try to use a workaround - It would be really helpful for us if this would be implemented into the code in the future.

      posted in Support
      I
      it_9582
    • RE: File download with wget only works with auth-no-challenge argument

      Hi @atripp,

      thanks for the explanation.
      I can understand that you are not willing/able to change this behavior. Now I will check if it is possible for us to modify the underlying wget call to allow downloading of the files from ProGet.

      Best regards

      posted in Support
      I
      it_9582