// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Diagnostics.Runtime.Utilities;
using Microsoft.FileFormats;
using Microsoft.FileFormats.ELF;
using Microsoft.FileFormats.MachO;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
-using System.Runtime.InteropServices;
namespace Microsoft.Diagnostics.DebugServices.Implementation
{
IModule module = _moduleService.GetModuleFromAddress(address);
if (module != null)
{
- Trace.TraceInformation("ReadMemory: address {0:X16} size {1:X8} found module {2}", address, bytesRequested, module.FileName);
-
- // Recursion can happen in the extreme case where the PE, ELF or MachO headers (in the module.Services.GetService<>() calls)
+ // Recursion can happen in the case where the PE, ELF or MachO headers (in the module.Services.GetService<>() calls)
// used to get the timestamp/filesize or build id are not in the dump.
- if (!_recursionProtection.Contains(module.ImageBase))
+ if (!_recursionProtection.Contains(address))
{
- _recursionProtection.Add(module.ImageBase);
+ _recursionProtection.Add(address);
try
{
// We found a module that contains the memory requested. Now find or download the PE image.
PEReader reader = module.Services.GetService<PEReader>();
if (reader is not null)
{
- // Read the memory from the PE image.
int rva = (int)(address - module.ImageBase);
Debug.Assert(rva >= 0);
+ Debug.Assert(!reader.IsLoadedImage);
+ Debug.Assert(reader.IsEntireImageAvailable);
+#if TRACE_VERBOSE
+ Trace.TraceInformation($"ReadMemoryFromModule: address {address:X16} rva {rva:X8} bytesRequested {bytesRequested:X8} {module.FileName}");
+#endif
+ // Not reading anything in the PE's header
+ if (rva > reader.PEHeaders.PEHeader.SizeOfHeaders)
+ {
+ // This property can cause recursion because this PE being mapped here is read to determine the layout
+ if (!module.IsFileLayout.GetValueOrDefault(true))
+ {
+ // If the PE image that we are mapping into has the "loaded" layout convert the rva to a flat/file based one.
+ for (int i = 0; i < reader.PEHeaders.SectionHeaders.Length; i++)
+ {
+ SectionHeader section = reader.PEHeaders.SectionHeaders[i];
+ if (rva >= section.VirtualAddress && rva < (section.VirtualAddress + section.VirtualSize))
+ {
+ rva = section.PointerToRawData + (rva - section.VirtualAddress);
+ break;
+ }
+ }
+ }
+ }
+
try
{
byte[] data = null;
- int sizeOfHeaders = reader.PEHeaders.PEHeader.SizeOfHeaders;
- if (rva < sizeOfHeaders)
- {
- // If the address isn't contained in one of the sections, assume that SOS is reading the PE headers directly.
- Trace.TraceInformation("ReadMemory: rva {0:X8} size {1:X8} in PE Header", rva, bytesRequested);
- data = reader.GetEntireImage().GetReader(rva, bytesRequested).ReadBytes(bytesRequested);
- }
- else
+ // Read the memory from the PE image found/downloaded above
+ PEMemoryBlock block = reader.GetEntireImage();
+ if (rva < block.Length)
{
- PEMemoryBlock block = reader.GetSectionData(rva);
- if (block.Length > 0)
+ int size = Math.Min(block.Length - rva, bytesRequested);
+ if ((rva + size) <= block.Length)
{
- int size = Math.Min(block.Length, bytesRequested);
- data = block.GetReader().ReadBytes(size);
+ data = block.GetReader(rva, size).ReadBytes(size);
ApplyRelocations(module, reader, rva, data);
}
else
{
- Trace.TraceError($"ReadMemory: FAILED rva {rva:X8}");
+ Trace.TraceError($"ReadMemoryFromModule: FAILED address {address:X16} rva {rva:X8} {module.FileName}");
}
}
-
+
return data;
}
catch (Exception ex) when (ex is BadImageFormatException || ex is InvalidOperationException || ex is IOException)
{
- Trace.TraceError($"ReadMemory: exception {ex.Message}");
- return null;
+ Trace.TraceError($"ReadMemoryFromModule: exception: address {address:X16} {ex.Message} {module.FileName}");
}
}
-
- // Find or download the ELF image, if one.
- Reader virtualAddressReader = module.Services.GetService<ELFFile>()?.VirtualAddressReader;
- if (virtualAddressReader is null)
+ else
{
- // Find or download the MachO image, if one.
- virtualAddressReader = module.Services.GetService<MachOFile>()?.VirtualAddressReader;
- }
- if (virtualAddressReader is not null)
- {
- // Read the memory from the image.
- ulong rva = address - module.ImageBase;
- Debug.Assert(rva >= 0);
- try
+ // Find or download the ELF image, if one.
+ Reader virtualAddressReader = module.Services.GetService<ELFFile>()?.VirtualAddressReader;
+ if (virtualAddressReader is null)
{
- Trace.TraceInformation("ReadMemory: rva {0:X16} size {1:X8} in ELF or MachO file", rva, bytesRequested);
- byte[] data = new byte[bytesRequested];
- uint read = virtualAddressReader.Read(rva, data, 0, (uint)bytesRequested);
- if (read == 0)
- {
- Trace.TraceError($"ReadMemory: FAILED rva {rva:X8}");
- data = null;
- }
- return data;
+ // Find or download the MachO image, if one.
+ virtualAddressReader = module.Services.GetService<MachOFile>()?.VirtualAddressReader;
}
- catch (Exception ex) when (ex is BadInputFormatException || ex is InvalidVirtualAddressException)
+ if (virtualAddressReader is not null)
{
- Trace.TraceError($"ReadMemory: ELF or MachO file exception {ex.Message}");
- return null;
+ // Read the memory from the image.
+ ulong rva = address - module.ImageBase;
+ Debug.Assert(rva >= 0);
+ try
+ {
+ Trace.TraceInformation($"ReadMemoryFromModule: address {address:X16} rva {rva:X16} size {bytesRequested:X8} in ELF or MachO file {module.FileName}");
+ byte[] data = new byte[bytesRequested];
+ uint read = virtualAddressReader.Read(rva, data, 0, (uint)bytesRequested);
+ if (read == 0)
+ {
+ Trace.TraceError($"ReadMemoryFromModule: FAILED address {address:X16} rva {rva:X16} {module.FileName}");
+ data = null;
+ }
+ return data;
+ }
+ catch (Exception ex) when (ex is BadInputFormatException || ex is InvalidVirtualAddressException)
+ {
+ Trace.TraceError($"ReadMemoryFromModule: ELF or MachO file exception: address {address:X16} {ex.Message} {module.FileName}");
+ }
}
}
}
finally
{
- _recursionProtection.Remove(module.ImageBase);
+ _recursionProtection.Remove(address);
}
}
else
{
- Trace.TraceError("ReadMemory: recursion");
+ Trace.TraceError($"ReadMemoryFromModule: recursion: address {address:X16} size {bytesRequested:X8} {module.FileName}");
}
}
return null;
break;
case BaseRelocationType.ImageRelBasedHighLow:
- {
- uint value = BitConverter.ToUInt32(data, offset);
- value += (uint)baseDelta;
- byte[] source = BitConverter.GetBytes(value);
- Array.Copy(source, 0, data, offset, source.Length);
+ if ((offset + sizeof(uint)) <= data.Length)
+ {
+ uint value = BitConverter.ToUInt32(data, offset);
+ value += (uint)baseDelta;
+ byte[] source = BitConverter.GetBytes(value);
+ Array.Copy(source, 0, data, offset, source.Length);
+ }
break;
- }
+
case BaseRelocationType.ImageRelBasedDir64:
- {
- ulong value = BitConverter.ToUInt64(data, offset);
- value += baseDelta;
- byte[] source = BitConverter.GetBytes(value);
- Array.Copy(source, 0, data, offset, source.Length);
+ if ((offset + sizeof(ulong)) <= data.Length)
+ {
+ ulong value = BitConverter.ToUInt64(data, offset);
+ value += baseDelta;
+ byte[] source = BitConverter.GetBytes(value);
+ Array.Copy(source, 0, data, offset, source.Length);
+ }
break;
- }
+
default:
Debug.Fail($"ApplyRelocations: invalid relocation type {type}");
break;
// See the LICENSE file in the project root for more information.
using Microsoft.Diagnostics.Runtime;
-using System.Linq;
+using Microsoft.Diagnostics.Runtime.Utilities;
using System;
using System.Collections.Immutable;
-using System.IO;
-using Microsoft.Diagnostics.Runtime.Utilities;
using System.Diagnostics;
-using System.Diagnostics.Contracts;
+using System.IO;
+using System.Linq;
namespace Microsoft.Diagnostics.DebugServices.Implementation
{
using System.Diagnostics;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
+using FileVersionInfo = Microsoft.Diagnostics.Runtime.Utilities.FileVersionInfo;
namespace Microsoft.Diagnostics.DebugServices.Implementation
{
private Flags _flags;
private PdbFileInfo _pdbFileInfo;
private ImmutableArray<byte> _buildId;
- private VersionData _versionData;
private PEImage _peImage;
public readonly ServiceProvider ServiceProvider;
{
get
{
- GetPEInfo();
- if ((_flags & Flags.IsFileLayout) != 0)
+ // For Windows targets we can assume that the file layout is always "loaded". The
+ // ImageMappingMemoryService depends on no recursion memory access for this property
+ // i.e. calling GetPEInfo().
+ if (Target.OperatingSystem == OSPlatform.Windows)
{
- return true;
+ return false;
}
- if ((_flags & Flags.IsLoadedLayout) != 0)
+ else
{
- return false;
+ GetPEInfo();
+ if ((_flags & Flags.IsFileLayout) != 0)
+ {
+ return true;
+ }
+ if ((_flags & Flags.IsLoadedLayout) != 0)
+ {
+ return false;
+ }
+ return null;
}
- return null;
}
}
}
}
- public virtual VersionData VersionData
- {
- get { return _versionData; }
- set { _versionData = value; }
- }
+ public abstract VersionData VersionData { get; }
public abstract string VersionString { get; }
#endregion
- protected void GetVersionFromVersionString()
+ protected VersionData GetVersion()
{
- GetPEInfo();
+ VersionData versionData = null;
- // If we can't get the version from the PE, search for version string embedded in the module data
- if (_versionData is null && !IsPEImage)
+ PEImage peImage = GetPEInfo();
+ if (peImage != null)
{
+ FileVersionInfo fileVersionInfo = peImage.GetFileVersionInfo();
+ if (fileVersionInfo != null)
+ {
+ versionData = fileVersionInfo.VersionInfo.ToVersionData();
+ }
+ }
+ else
+ {
+ // If we can't get the version from the PE, search for version string embedded in the module data
string versionString = VersionString;
if (versionString != null)
{
try
{
Version version = System.Version.Parse(versionToParse);
- _versionData = new VersionData(version.Major, version.Minor, version.Build, version.Revision);
+ versionData = new VersionData(version.Major, version.Minor, version.Build, version.Revision);
}
catch (ArgumentException ex)
{
}
}
}
+
+ return versionData;
}
protected PEImage GetPEInfo()
{
if (InitializeValue(Flags.InitializePEInfo)) {
- _peImage = ModuleService.GetPEInfo(ImageBase, ImageSize, ref _pdbFileInfo, ref _versionData, ref _flags);
+ _peImage = ModuleService.GetPEInfo(ImageBase, ImageSize, ref _pdbFileInfo, ref _flags);
}
return _peImage;
}
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Text;
-using FileVersionInfo = Microsoft.Diagnostics.Runtime.Utilities.FileVersionInfo;
namespace Microsoft.Diagnostics.DebugServices.Implementation
{
/// <param name="address">module base address</param>
/// <param name="size">module size</param>
/// <param name="pdbFileInfo">the pdb record or null</param>
- /// <param name="versionData">the PE version or null</param>
/// <param name="flags">module flags</param>
/// <returns>PEImage instance or null</returns>
- internal PEImage GetPEInfo(ulong address, ulong size, ref PdbFileInfo pdbFileInfo, ref VersionData versionData, ref Module.Flags flags)
+ internal PEImage GetPEInfo(ulong address, ulong size, ref PdbFileInfo pdbFileInfo, ref Module.Flags flags)
{
PEImage peImage = null;
if (Target.Host.HostType != HostType.Lldb)
{
// First try getting the PE info as load layout (native Windows DLLs and most managed PEs on Linux/MacOS).
- peImage = GetPEInfo(isVirtual: true, address, size, ref pdbFileInfo, ref versionData, ref flags);
+ peImage = GetPEInfo(isVirtual: true, address: address, size: size, pdbFileInfo: ref pdbFileInfo, flags: ref flags);
if (peImage == null)
{
if (Target.OperatingSystem != OSPlatform.Windows)
{
// Then try getting the PE info as file layout (some managed PEs on Linux/MacOS).
- peImage = GetPEInfo(isVirtual: false, address, size, ref pdbFileInfo, ref versionData, ref flags);
+ peImage = GetPEInfo(isVirtual: false, address: address, size: size, pdbFileInfo: ref pdbFileInfo, flags: ref flags);
}
}
}
/// <param name="address">module base address</param>
/// <param name="size">module size</param>
/// <param name="pdbFileInfo">the pdb record or null</param>
- /// <param name="versionData">the PE version 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 VersionData versionData, ref Module.Flags flags)
+ private PEImage GetPEInfo(bool isVirtual, ulong address, ulong size, ref PdbFileInfo pdbFileInfo, ref Module.Flags flags)
{
Stream stream = MemoryService.CreateMemoryStream(address, size);
try
{
flags |= Module.Flags.IsPEImage;
flags |= peImage.IsManaged ? Module.Flags.IsManaged : Module.Flags.None;
- pdbFileInfo = peImage.DefaultPdb.ToPdbFileInfo();
- if (versionData is null)
- {
- FileVersionInfo fileVersionInfo = peImage.GetFileVersionInfo();
- if (fileVersionInfo != null)
- {
- versionData = fileVersionInfo.VersionInfo.ToVersionData();
- }
- }
+ pdbFileInfo = peImage.DefaultPdb?.ToPdbFileInfo();
flags &= ~(Module.Flags.IsLoadedLayout | Module.Flags.IsFileLayout);
flags |= isVirtual ? Module.Flags.IsLoadedLayout : Module.Flags.IsFileLayout;
return peImage;
}
catch (Exception ex) when (ex is BadImageFormatException || ex is EndOfStreamException || ex is IOException)
{
- Trace.TraceError($"GetPEInfo: loaded {address:X16} isVirtual {isVirtual} exception {ex.Message}");
+ Trace.TraceError($"GetPEInfo: {address:X16} isVirtual {isVirtual} exception {ex.Message}");
}
return null;
}
private readonly IExportReader _exportReader;
private readonly ModuleInfo _moduleInfo;
private readonly ulong _imageSize;
+ private VersionData _versionData;
private string _versionString;
public ModuleFromDataReader(ModuleServiceFromDataReader moduleService, IExportReader exportReader, int moduleIndex, ModuleInfo moduleInfo, ulong imageSize)
{
if (_moduleInfo.Version != EmptyVersionInfo)
{
- base.VersionData = _moduleInfo.Version.ToVersionData();
+ _versionData = _moduleInfo.Version.ToVersionData();
}
else
{
if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
{
- GetVersionFromVersionString();
+ _versionData = GetVersion();
}
}
}
- return base.VersionData;
+ return _versionData;
}
}
using Microsoft.Diagnostics.DebugServices;
using Microsoft.Diagnostics.DebugServices.Implementation;
-using Microsoft.Diagnostics.Runtime;
using Microsoft.Diagnostics.Runtime.Interop;
using Microsoft.Diagnostics.Runtime.Utilities;
-using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.IO;
using System.Runtime.InteropServices;
namespace SOS.Extensions
private const uint InvalidTimeStamp = 0xFFFFFFFE;
private readonly ModuleServiceFromDebuggerServices _moduleService;
+ private VersionData _versionData;
private string _versionString;
public ModuleFromDebuggerServices(
int minor = (int)fileInfo.dwFileVersionMS & 0xffff;
int revision = (int)fileInfo.dwFileVersionLS >> 16;
int patch = (int)fileInfo.dwFileVersionLS & 0xffff;
- base.VersionData = new VersionData(major, minor, revision, patch);
+ _versionData = new VersionData(major, minor, revision, patch);
}
else
{
if (_moduleService.Target.OperatingSystem != OSPlatform.Windows)
{
- GetVersionFromVersionString();
+ _versionData = GetVersion();
}
}
}
- return base.VersionData;
+ return _versionData;
}
}