/// <summary> /// Returns the ELF module build id or the MachO module uuid /// </summary> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <returns>build id or null</returns> internal byte[] GetBuildId(ulong address, ulong size) { Debug.Assert(size > 0); Stream stream = MemoryService.CreateMemoryStream(address, size); byte[] buildId = null; try { if (Target.OperatingSystem == OSPlatform.Linux) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); if (elfFile.IsValid()) { buildId = elfFile.BuildID; } } else if (Target.OperatingSystem == OSPlatform.OSX) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); if (machOFile.IsValid()) { buildId = machOFile.Uuid; } } } catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException) { Trace.TraceError($"GetBuildId: {address:X16} exception {ex.Message}"); } return(buildId); }
/// <summary> /// Returns information about the PE file. /// </summary> /// <param name="isVirtual">the memory layout of the module</param> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <param name="pdbFileInfo">the pdb record or null</param> /// <param name="flags">module flags</param> /// /// <returns>PEImage instance or null</returns> private PEImage GetPEInfo(bool isVirtual, ulong address, ulong size, ref PdbFileInfo pdbFileInfo, ref Module.Flags flags) { Stream stream = MemoryService.CreateMemoryStream(address, size); try { stream.Position = 0; var peImage = new PEImage(stream, leaveOpen: false, isVirtual); if (peImage.IsValid) { flags |= Module.Flags.IsPEImage; flags |= peImage.IsManaged ? Module.Flags.IsManaged : Module.Flags.None; pdbFileInfo = peImage.DefaultPdb?.ToPdbFileInfo(); flags &= ~(Module.Flags.IsLoadedLayout | Module.Flags.IsFileLayout); flags |= isVirtual ? Module.Flags.IsLoadedLayout : Module.Flags.IsFileLayout; return(peImage); } else { Trace.TraceError($"GetPEInfo: PE invalid {address:X16} isVirtual {isVirtual}"); } } catch (Exception ex) when(ex is BadImageFormatException || ex is EndOfStreamException || ex is IOException) { Trace.TraceError($"GetPEInfo: {address:X16} isVirtual {isVirtual} exception {ex.Message}"); } return(null); }
/// <summary> /// Checks availability of debugging information for given assembly. /// </summary> /// <param name="assemblyPath"> /// File path of the assembly or null if the module is in-memory or dynamic (generated by Reflection.Emit) /// </param> /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> /// <param name="loadedPeAddress"> /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit). /// Dynamic modules have their PDBs (if any) generated to an in-memory stream /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>). /// </param> /// <param name="loadedPeSize">loaded PE image size</param> /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param> /// <param name="inMemoryPdbSize">in memory PDB size</param> /// <returns>Symbol reader handle or zero if error</returns> private IntPtr LoadSymbolsForModule( IntPtr self, string assemblyPath, bool isFileLayout, ulong loadedPeAddress, uint loadedPeSize, ulong inMemoryPdbAddress, uint inMemoryPdbSize) { try { Stream peStream = null; if (loadedPeAddress != 0) { peStream = MemoryService.CreateMemoryStream(loadedPeAddress, loadedPeSize); } Stream pdbStream = null; if (inMemoryPdbAddress != 0) { pdbStream = MemoryService.CreateMemoryStream(inMemoryPdbAddress, inMemoryPdbSize); } OpenedReader openedReader = GetReader(assemblyPath, isFileLayout, peStream, pdbStream); if (openedReader != null) { GCHandle gch = GCHandle.Alloc(openedReader); return(GCHandle.ToIntPtr(gch)); } } catch (Exception ex) { Trace.TraceError($"LoadSymbolsForModule: {ex.Message}"); } return(IntPtr.Zero); }
/// <summary> /// Get the version string from a Linux or MacOS image /// </summary> /// <param name="address">image base</param> /// <param name="size">image size</param> /// <returns>version string or null</returns> protected string GetVersionString(ulong address, ulong size) { Stream stream = MemoryService.CreateMemoryStream(address, size); try { if (Target.OperatingSystem == OSPlatform.Linux) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); if (elfFile.IsValid()) { foreach (ELFProgramHeader programHeader in elfFile.Segments.Select((segment) => segment.Header)) { uint flags = MemoryService.PointerSize == 8 ? programHeader.Flags : programHeader.Flags32; if (programHeader.Type == ELFProgramHeaderType.Load && (flags & (uint)ELFProgramHeaderAttributes.Writable) != 0) { ulong loadAddress = programHeader.VirtualAddress.Value; long loadSize = (long)programHeader.VirtualSize; if (SearchVersionString(address + loadAddress, loadSize, out string productVersion)) { return(productVersion); } } } } } else if (Target.OperatingSystem == OSPlatform.OSX) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); if (machOFile.IsValid()) { foreach (MachSegmentLoadCommand loadCommand in machOFile.Segments.Select((segment) => segment.LoadCommand)) { if (loadCommand.Command == LoadCommandType.Segment64 && (loadCommand.InitProt & VmProtWrite) != 0 && loadCommand.SegName.ToString() != "__LINKEDIT") { ulong loadAddress = loadCommand.VMAddress; long loadSize = (long)loadCommand.VMSize; if (SearchVersionString(address + loadAddress, loadSize, out string productVersion)) { return(productVersion); } } } } } else { Trace.TraceError("GetVersionString: unsupported platform {0}", Target.OperatingSystem); } } catch (Exception ex) when(ex is InvalidVirtualAddressException || ex is BadInputFormatException || ex is IOException) { Trace.TraceError($"GetVersionString: {address:X16} exception {ex.Message}"); } return(null); }
/// <summary> /// Load native symbols and modules (i.e. DAC, DBI). /// </summary> /// <param name="callback">called back for each symbol file loaded</param> /// <param name="parameter">callback parameter</param> /// <param name="config">Target configuration: Windows, Linux or OSX</param> /// <param name="moduleFilePath">module path</param> /// <param name="address">module base address</param> /// <param name="size">module size</param> /// <param name="readMemory">read memory callback delegate</param> private void LoadNativeSymbols( IntPtr self, SymbolFileCallback callback, IntPtr parameter, RuntimeConfiguration config, string moduleFilePath, ulong address, uint size) { if (_symbolService.IsSymbolStoreEnabled) { try { Stream stream = MemoryService.CreateMemoryStream(address, size); KeyGenerator generator = null; if (config == RuntimeConfiguration.UnixCore) { var elfFile = new ELFFile(new StreamAddressSpace(stream), 0, true); generator = new ELFFileKeyGenerator(Tracer.Instance, elfFile, moduleFilePath); } else if (config == RuntimeConfiguration.OSXCore) { var machOFile = new MachOFile(new StreamAddressSpace(stream), 0, true); generator = new MachOFileKeyGenerator(Tracer.Instance, machOFile, moduleFilePath); } else if (config == RuntimeConfiguration.WindowsCore || config == RuntimeConfiguration.WindowsDesktop) { var peFile = new PEFile(new StreamAddressSpace(stream), true); generator = new PEFileKeyGenerator(Tracer.Instance, peFile, moduleFilePath); } else { Trace.TraceError("LoadNativeSymbols: unsupported config {0}", config); } if (generator != null) { IEnumerable <SymbolStoreKey> keys = generator.GetKeys(KeyTypeFlags.SymbolKey | KeyTypeFlags.DacDbiKeys); foreach (SymbolStoreKey key in keys) { string moduleFileName = Path.GetFileName(key.FullPathName); Trace.TraceInformation("{0} {1}", key.FullPathName, key.Index); string downloadFilePath = _symbolService.DownloadFile(key); if (downloadFilePath != null) { Trace.TraceInformation("{0}: {1}", moduleFileName, downloadFilePath); callback(parameter, moduleFileName, downloadFilePath); } } } } catch (Exception ex) when (ex is DiagnosticsException || ex is BadInputFormatException || ex is InvalidVirtualAddressException || ex is ArgumentOutOfRangeException || ex is IndexOutOfRangeException || ex is TaskCanceledException) { Trace.TraceError("{0} address {1:X16}: {2}", moduleFilePath, address, ex.Message); } } }