PDB - Corrected symbol mapping using OMAP and enabled PDB Universal

Analyzer as default.  Renamed old PDB analyzer to PDB MSDIA.
This commit is contained in:
ghidra1 2020-10-06 17:38:55 -04:00
parent 10702d0569
commit b2eb2aaa65
11 changed files with 251 additions and 209 deletions

View file

@ -15,16 +15,18 @@
*/ */
package ghidra.app.util.datatype.microsoft; package ghidra.app.util.datatype.microsoft;
import java.io.*;
import java.util.Hashtable;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.docking.settings.SettingsImpl;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.*; import ghidra.util.*;
import java.io.*;
import java.util.Hashtable;
public class GuidUtil { public class GuidUtil {
public enum GuidType { public enum GuidType {
@ -63,8 +65,8 @@ public class GuidUtil {
return; return;
} }
idTables = new Hashtable<GuidType, Hashtable<String, GuidInfo>>(); idTables = new Hashtable<GuidType, Hashtable<String, GuidInfo>>();
for (int i = 0; i < guidTypes.length; i++) { for (GuidType guidType : guidTypes) {
idTables.put(guidTypes[i], new Hashtable<String, GuidInfo>()); idTables.put(guidType, new Hashtable<String, GuidInfo>());
} }
buildGuidMap(); buildGuidMap();
initialized = true; initialized = true;
@ -81,11 +83,11 @@ public class GuidUtil {
} }
initialize(); initialize();
guidString = guidString.toUpperCase(); guidString = guidString.toUpperCase();
for (int i = 0; i < guidTypes.length; i++) { for (GuidType guidType : guidTypes) {
if (guidTypes[i].equals(GuidType.SYNTAX)) { if (guidType.equals(GuidType.SYNTAX)) {
continue; continue;
} }
Hashtable<String, GuidInfo> table = idTables.get(guidTypes[i]); Hashtable<String, GuidInfo> table = idTables.get(guidType);
GuidInfo guidInfo = table.get(guidString); GuidInfo guidInfo = table.get(guidString);
if (guidInfo != null) { if (guidInfo != null) {
return guidInfo; return guidInfo;
@ -106,11 +108,11 @@ public class GuidUtil {
} }
private static void buildGuidMap() { private static void buildGuidMap() {
for (int i = 0; i < guidTypes.length; i++) { for (GuidType guidType : guidTypes) {
Hashtable<String, GuidInfo> table = idTables.get(guidTypes[i]); Hashtable<String, GuidInfo> table = idTables.get(guidType);
String filename = guidTypes[i].getFilename(); String filename = guidType.getFilename();
readGuidFile(guidTypes[i], filename, table); readGuidFile(guidType, filename, table);
} }
} }
@ -195,8 +197,8 @@ public class GuidUtil {
} }
private static boolean isOK(long[] data) { private static boolean isOK(long[] data) {
for (int i = 0; i < data.length; i++) { for (long element : data) {
if ((data[i] != 0) || (data[i] != 0xFFFFFFFFL)) { if ((element != 0) || (element != 0xFFFFFFFFL)) {
return true; return true;
} }
} }
@ -229,8 +231,9 @@ public class GuidUtil {
guidString += Conv.toHexString((short) (data[1] >> 16)) + delim; guidString += Conv.toHexString((short) (data[1] >> 16)) + delim;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
guidString += Conv.toHexString((byte) (data[2] >> i * 8)); guidString += Conv.toHexString((byte) (data[2] >> i * 8));
if (i == 1) if (i == 1) {
guidString += delim; guidString += delim;
}
} }
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
guidString += Conv.toHexString((byte) (data[3] >> i * 8)); guidString += Conv.toHexString((byte) (data[3] >> i * 8));
@ -270,8 +273,9 @@ public class GuidUtil {
guidString += Conv.toHexString((short) (data[1] >> 16)) + delim; guidString += Conv.toHexString((short) (data[1] >> 16)) + delim;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
guidString += Conv.toHexString((byte) (data[2] >> i * 8)); guidString += Conv.toHexString((byte) (data[2] >> i * 8));
if (i == 1) if (i == 1) {
guidString += delim; guidString += delim;
}
} }
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
guidString += Conv.toHexString((byte) (data[3] >> i * 8)); guidString += Conv.toHexString((byte) (data[3] >> i * 8));
@ -291,4 +295,32 @@ public class GuidUtil {
return guidString; return guidString;
} }
private static final String MS_GUID_PREFIX = "_GUID_";
/**
* Verify that the specified label correpsonds to a Microsoft symbol name
* for the GUID stored at the specified address within program.
* @param program program
* @param address memory address
* @param label symbol name to be checked
* @return true if label is a valid GUID label which corresponds to the GUID
* stored at address within program
*/
public static boolean isGuidLabel(Program program, Address address, String label) {
if (!label.startsWith(MS_GUID_PREFIX)) {
return false;
}
String guidString = label.substring(MS_GUID_PREFIX.length()).replace("_", "-");
try {
new GUID(guidString);
}
catch (Exception e) {
return false;
}
GuidDataType dt = new GuidDataType();
String guidRep = dt.getRepresentation(new DumbMemBufferImpl(program.getMemory(), address),
new SettingsImpl(), -1);
return guidRep.endsWith(guidString);
}
} }

View file

@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
* Finds and applies PDB debug information to the given Windows executable. * Finds and applies PDB debug information to the given Windows executable.
*/ */
public class PdbAnalyzer extends AbstractAnalyzer { public class PdbAnalyzer extends AbstractAnalyzer {
static final String NAME = "PDB"; static final String NAME = "PDB MSDIA";
static final boolean DEFAULT_ENABLEMENT = !PdbUniversalAnalyzer.DEFAULT_ENABLEMENT; static final boolean DEFAULT_ENABLEMENT = !PdbUniversalAnalyzer.DEFAULT_ENABLEMENT;
private static final String DESCRIPTION = private static final String DESCRIPTION =
"PDB Analyzer.\n" + "Requires MS DIA-SDK for raw PDB processing (Windows only).\n" + "PDB Analyzer.\n" + "Requires MS DIA-SDK for raw PDB processing (Windows only).\n" +

View file

@ -61,9 +61,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
//============================================================================================== //==============================================================================================
static final String NAME = "PDB Universal"; static final String NAME = "PDB Universal";
// TODO: decide which PDB Analyzer should be enabled by default for release // TODO: decide which PDB Analyzer should be enabled by default for release
static final boolean DEFAULT_ENABLEMENT = false; static final boolean DEFAULT_ENABLEMENT = true;
private static final String DESCRIPTION = private static final String DESCRIPTION =
"[Prototype V1] Platform-indepent PDB analyzer (No XML support).\n" + "Platform-indepent PDB analyzer (No XML support).\n" +
"NOTE: still undergoing development, so options may change."; "NOTE: still undergoing development, so options may change.";
//============================================================================================== //==============================================================================================
@ -203,7 +203,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
//============================================================================================== //==============================================================================================
public PdbUniversalAnalyzer() { public PdbUniversalAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER); super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setPrototype(); //setPrototype();
setDefaultEnablement(DEFAULT_ENABLEMENT); setDefaultEnablement(DEFAULT_ENABLEMENT);
setPriority(AnalysisPriority.FORMAT_ANALYSIS.after()); setPriority(AnalysisPriority.FORMAT_ANALYSIS.after());
setSupportsOneTimeAnalysis(); setSupportsOneTimeAnalysis();

View file

@ -20,14 +20,12 @@ import java.util.Set;
import ghidra.app.cmd.disassemble.DisassembleCommand; import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.util.NamespaceUtils; import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.datatype.microsoft.GUID;
import ghidra.app.util.datatype.microsoft.GuidDataType; import ghidra.app.util.datatype.microsoft.GuidDataType;
import ghidra.app.util.datatype.microsoft.GuidUtil;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.docking.settings.SettingsImpl;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -37,11 +35,9 @@ import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser; import ghidra.xml.XmlPullParser;
class ApplySymbols { class ApplySymbols {
private static final String MS_VF_TABLE_PREFIX = "??_7"; // private static final String MS_VF_TABLE_PREFIX = "??_7";
private static final String MS_VB_TABLE_PREFIX = "??_8"; // private static final String MS_VB_TABLE_PREFIX = "??_8";
private static final String MS_STRING_PREFIX = "??_C@_"; // private static final String MS_STRING_PREFIX = "??_C@_";
private static final String MS_GUID_PREFIX = "_GUID_";
private ApplySymbols() { private ApplySymbols() {
// static use only // static use only
@ -146,11 +142,11 @@ class ApplySymbols {
// } // }
// } // }
// else // else
if (name.startsWith(MS_STRING_PREFIX)) { // if (name.startsWith(MS_STRING_PREFIX)) {
// TODO: Should this be handled by the demangler instead of here? // TODO: Should this be handled by the demangler instead of here?
boolean isUnicode = isUnicode(name); // boolean isUnicode = isUnicode(name);
pdbParser.createString(isUnicode, address, log); // pdbParser.createString(isUnicode, address, log);
} // }
//////////// ////////////
// Commented out the following for now, because it appears to be doing things it // Commented out the following for now, because it appears to be doing things it
// shouldn't. Many of the things are very loosely speculative. // shouldn't. Many of the things are very loosely speculative.
@ -170,7 +166,7 @@ class ApplySymbols {
// pdbParser.createData(address, DoubleDataType.dataType, log, monitor); // pdbParser.createData(address, DoubleDataType.dataType, log, monitor);
// } // }
// } // }
else if (isGuidLabel(name, address, program)) { if (GuidUtil.isGuidLabel(program, address, name)) {
pdbParser.createData(address, new GuidDataType(), log); pdbParser.createData(address, new GuidDataType(), log);
} }
else if (tag.equals("Data")) { else if (tag.equals("Data")) {
@ -193,23 +189,6 @@ class ApplySymbols {
} }
private static boolean isGuidLabel(String name, Address address, Program program) {
if (!name.startsWith(MS_GUID_PREFIX)) {
return false;
}
String guidString = name.substring(MS_GUID_PREFIX.length()).replace("_", "-");
try {
new GUID(guidString);
}
catch (Exception e) {
return false;
}
GuidDataType dt = new GuidDataType();
String guidRep = dt.getRepresentation(new DumbMemBufferImpl(program.getMemory(), address),
new SettingsImpl(), -1);
return guidRep.endsWith(guidString);
}
private static boolean shouldForcePrimarySymbol(Program program, Address address) { private static boolean shouldForcePrimarySymbol(Program program, Address address) {
Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address); Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address);
if (primarySymbol != null) { if (primarySymbol != null) {
@ -222,13 +201,13 @@ class ApplySymbols {
return false; return false;
} }
private static boolean isUnicode(String name) { // private static boolean isUnicode(String name) {
if (name.startsWith(MS_STRING_PREFIX)) { // if (name.startsWith(MS_STRING_PREFIX)) {
if (name.charAt(MS_STRING_PREFIX.length()) == '1') { // if (name.charAt(MS_STRING_PREFIX.length()) == '1') {
return true; // return true;
} // }
} // }
return false; // return false;
} // }
} }

View file

@ -67,9 +67,10 @@ public class DebugData {
private List<Integer> debugStreams = new ArrayList<>(); private List<Integer> debugStreams = new ArrayList<>();
private List<FramePointerOmissionRecord> framePointerOmissionData; private List<FramePointerOmissionRecord> framePointerOmissionData;
private Map<Long, Long> omapToSource; // private SortedMap<Long, Long> omapToSource;
private Map<Long, Long> omapFromSource; private SortedMap<Long, Long> omapFromSource;
private List<ImageSectionHeader> imageSectionHeaders; private List<ImageSectionHeader> imageSectionHeaders;
private List<ImageSectionHeader> imageSectionHeadersOrig;
private List<ImageFunctionEntry> pData; private List<ImageFunctionEntry> pData;
@ -96,19 +97,19 @@ public class DebugData {
return framePointerOmissionData; return framePointerOmissionData;
} }
/** // /**
* Returns the OMAP_TO_SOURCE mapping of RVA to RVA // * Returns the OMAP_TO_SOURCE mapping of RVA to RVA
* @return the omapToSource or null if does not exist. // * @return the omapToSource or null if does not exist.
*/ // */
public Map<Long, Long> getOmapToSource() { // public SortedMap<Long, Long> getOmapToSource() {
return omapToSource; // return omapToSource;
} // }
/** /**
* Returns the OMAP_FROM_SOURCE mapping of RVA to RVA * Returns the OMAP_FROM_SOURCE mapping of RVA to RVA
* @return the omapFromSource or null if does not exist. * @return the omapFromSource or null if does not exist.
*/ */
public Map<Long, Long> getOmapFromSource() { public SortedMap<Long, Long> getOmapFromSource() {
return omapFromSource; return omapFromSource;
} }
@ -120,6 +121,16 @@ public class DebugData {
return imageSectionHeaders; return imageSectionHeaders;
} }
/**
* Returns the {@link List}&lt;{@link ImageSectionHeader}&gt;.
* When this return a non-null list the OMAP_FROM_SRC should be
* used for remapping global symbols.
* @return the imageSectionHeadersOrig or null if does not exist.
*/
public List<ImageSectionHeader> getImageSectionHeadersOrig() {
return imageSectionHeadersOrig;
}
/** /**
* Deserialize {@link DebugData} header from the {@link PdbByteReader} input. This parses * Deserialize {@link DebugData} header from the {@link PdbByteReader} input. This parses
* stream numbers for varying Debug Types--the order/location of the stream number is for * stream numbers for varying Debug Types--the order/location of the stream number is for
@ -178,13 +189,13 @@ public class DebugData {
// TODO: implement. // TODO: implement.
break; break;
case OMAP_TO_SOURCE: case OMAP_TO_SOURCE:
deserializeOMapToSource(streamNum, monitor); // omapToSource = deserializeOMap(streamNum, monitor);
break; break;
case OMAP_FROM_SOURCE: case OMAP_FROM_SOURCE:
deserializeOMapFromSource(streamNum, monitor); omapFromSource = deserializeOMap(streamNum, monitor);
break; break;
case SECTION_HEADER: case SECTION_HEADER:
deserializeSectionHeader(streamNum, monitor); imageSectionHeaders = deserializeSectionHeaders(streamNum, monitor);
break; break;
case TOKEN_RID_MAP: case TOKEN_RID_MAP:
// TODO: implement. // TODO: implement.
@ -199,7 +210,7 @@ public class DebugData {
// TODO: implement. // TODO: implement.
break; break;
case SECTION_HEADER_ORIG: case SECTION_HEADER_ORIG:
// TODO: implement. imageSectionHeadersOrig = deserializeSectionHeaders(streamNum, monitor);
break; break;
} }
} }
@ -219,58 +230,30 @@ public class DebugData {
} }
} }
private void deserializeOMapToSource(int streamNum, TaskMonitor monitor) private SortedMap<Long, Long> deserializeOMap(int streamNum, TaskMonitor monitor)
throws CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
// PdbLog.message("OMAP_TO_SOURCE DUMP");
// PdbLog.message(reader::dump);
omapToSource = new HashMap<>();
while (reader.hasMore()) {
monitor.checkCanceled();
try {
long v1 = reader.parseUnsignedIntVal();
long v2 = reader.parseUnsignedIntVal();
omapToSource.put(v1, v2);
}
catch (PdbException e) {
// catching if we do not have a matching pair and then breaking from loop.
PdbLog.message("OmapToSource unmatched pair");
break;
}
}
}
private void deserializeOMapFromSource(int streamNum, TaskMonitor monitor)
throws CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
// PdbLog.message("OMAP_FROM_SOURCE DUMP");
// PdbLog.message(reader::dump);
omapFromSource = new HashMap<>();
while (reader.hasMore()) {
monitor.checkCanceled();
try {
long v1 = reader.parseUnsignedIntVal();
long v2 = reader.parseUnsignedIntVal();
omapFromSource.put(v1, v2);
}
catch (PdbException e) {
// catching if we do not have a matching pair and then breaking from loop.
PdbLog.message("OmapFromSource unmatched pair");
break;
}
}
}
private void deserializeSectionHeader(int streamNum, TaskMonitor monitor)
throws PdbException, CancelledException, IOException { throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor); PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
imageSectionHeaders = new ArrayList<>(); SortedMap<Long, Long> omap = new TreeMap<>();
while (reader.hasMore()) {
monitor.checkCanceled();
long v1 = reader.parseUnsignedIntVal();
long v2 = reader.parseUnsignedIntVal();
omap.put(v1, v2);
}
return omap;
}
private List<ImageSectionHeader> deserializeSectionHeaders(int streamNum, TaskMonitor monitor)
throws PdbException, CancelledException, IOException {
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum, monitor);
List<ImageSectionHeader> sectionHeaders = new ArrayList<>();
while (reader.hasMore()) { while (reader.hasMore()) {
monitor.checkCanceled(); monitor.checkCanceled();
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb); ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
imageSectionHeader.parse(reader); imageSectionHeader.parse(reader);
imageSectionHeaders.add(imageSectionHeader); sectionHeaders.add(imageSectionHeader);
} }
return sectionHeaders;
} }
// TODO: This is incomplete. // TODO: This is incomplete.
@ -372,15 +355,15 @@ public class DebugData {
} }
writer.write("End FramePointerOmissionData--------------------------------\n"); writer.write("End FramePointerOmissionData--------------------------------\n");
writer.write("OmapToSource------------------------------------------------\n"); // writer.write("OmapToSource------------------------------------------------\n");
if (omapToSource != null) { // if (omapToSource != null) {
int num = 0; // int num = 0;
for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) { // for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) {
writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(), // writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(),
entry.getValue())); // entry.getValue()));
} // }
} // }
writer.write("End OmapToSource--------------------------------------------\n"); // writer.write("End OmapToSource--------------------------------------------\n");
writer.write("OmapFromSource----------------------------------------------\n"); writer.write("OmapFromSource----------------------------------------------\n");
if (omapFromSource != null) { if (omapFromSource != null) {
@ -401,6 +384,15 @@ public class DebugData {
} }
writer.write("End ImageSectionHeaders-------------------------------------\n"); writer.write("End ImageSectionHeaders-------------------------------------\n");
writer.write("ImageSectionHeadersOrig-------------------------------------\n");
if (imageSectionHeadersOrig != null) {
int sectionNum = 0;
for (ImageSectionHeader imageSectionHeader : imageSectionHeadersOrig) {
imageSectionHeader.dump(writer, sectionNum++);
}
}
writer.write("End ImageSectionHeadersOrig---------------------------------\n");
writer.write("PData-------------------------------------------------------\n"); writer.write("PData-------------------------------------------------------\n");
if (pData != null) { if (pData != null) {
for (ImageFunctionEntry entry : pData) { for (ImageFunctionEntry entry : pData) {

View file

@ -36,18 +36,20 @@ public class PdbAddressManager {
// This could be a valid address for the program, but we are using it as a flag. We return // This could be a valid address for the program, but we are using it as a flag. We return
// it to designate that an address is an external address, and we use it outside of this class // it to designate that an address is an external address, and we use it outside of this class
// to test for it being an external address. // to test for it being an external address. These marker addresses should never be used
static final Address EXTERNAL_ADDRESS = AddressSpace.EXTERNAL_SPACE.getAddress(0); // for symbol creation.
static final Address BAD_ADDRESS = Address.NO_ADDRESS; // using NO_ADDRESS as a marker static final Address EXTERNAL_ADDRESS = AddressSpace.EXTERNAL_SPACE.getAddress(1);
static final Address ZERO_ADDRESS = AddressSpace.EXTERNAL_SPACE.getAddress(0);
static final Address BAD_ADDRESS = Address.NO_ADDRESS;
//============================================================================================== //==============================================================================================
private Map<Integer, Long> realAddressesBySection; private Map<Integer, Long> realAddressesBySection;
private List<SegmentMapDescription> segmentMapList; private List<SegmentMapDescription> segmentMapList;
private List<ImageSectionHeader> imageSectionHeaders; private List<ImageSectionHeader> imageSectionHeaders;
private Map<Long, Long> omapFromSource; private SortedMap<Long, Long> omapFromSource;
private List<PeCoffGroupMsSymbol> memoryGroupRefinement; private List<PeCoffGroupMsSymbol> memoryGroupRefinement;
private List<PeCoffSectionMsSymbol> memorySectionRefinement; private List<PeCoffSectionMsSymbol> memorySectionRefinement;
private List<SegmentInfo> allSegmentsInfo; // private List<SegmentInfo> allSegmentsInfo;
// Map of Address by symbol name... if a name has appeared more than once, then the Address // Map of Address by symbol name... if a name has appeared more than once, then the Address
// is written with Address.NO_ADDRESS to indicate that the name is found at more than one // is written with Address.NO_ADDRESS to indicate that the name is found at more than one
@ -85,11 +87,11 @@ public class PdbAddressManager {
memoryGroupRefinement = new ArrayList<>(); memoryGroupRefinement = new ArrayList<>();
memorySectionRefinement = new ArrayList<>(); memorySectionRefinement = new ArrayList<>();
// TODO allSegmentInfo might go away if we use ImageSectionHeader. Under investigation. // TODO allSegmentInfo might go away if we use ImageSectionHeader. Under investigation.
allSegmentsInfo = new ArrayList<>(); // allSegmentsInfo = new ArrayList<>();
addressByPreExistingSymbolName = new HashMap<>(); addressByPreExistingSymbolName = new HashMap<>();
primarySymbolByAddress = new HashMap<>(); primarySymbolByAddress = new HashMap<>();
determineMemoryBlocks(); determineMemoryBlocks();
determineMemoryBlocks_orig(); // determineMemoryBlocks_orig();
mapPreExistingSymbols(); mapPreExistingSymbols();
createAddressRemap(); createAddressRemap();
} }
@ -144,16 +146,10 @@ public class PdbAddressManager {
* {@code Address.EXTERNAL_ADDRESS} if the address is external to the program. * {@code Address.EXTERNAL_ADDRESS} if the address is external to the program.
*/ */
Address getRawAddress(int segment, long offset) { Address getRawAddress(int segment, long offset) {
// Investigating
return getRawAddress_new(segment, offset);
//return getRawAddress_orig(segment, offset);
}
private Address getRawAddress_new(int segment, long offset) {
if (segment < 0) { if (segment < 0) {
return BAD_ADDRESS; return BAD_ADDRESS;
} }
Long relativeVirtualAddress; Long relativeVirtualAddress = null;
if (imageSectionHeaders != null) { if (imageSectionHeaders != null) {
if (segment > imageSectionHeaders.size() + 1) { if (segment > imageSectionHeaders.size() + 1) {
return BAD_ADDRESS; return BAD_ADDRESS;
@ -164,8 +160,16 @@ public class PdbAddressManager {
} }
relativeVirtualAddress = relativeVirtualAddress =
imageSectionHeaders.get(segment - 1).getVirtualAddress() + offset; imageSectionHeaders.get(segment - 1).getVirtualAddress() + offset;
relativeVirtualAddress = applyOMap(relativeVirtualAddress);
if (relativeVirtualAddress == null) {
return BAD_ADDRESS;
}
if (relativeVirtualAddress == 0) {
return ZERO_ADDRESS;
}
} }
else { else {
// TODO: need to verify use of segments here!
if (segment > segmentMapList.size() + 1) { if (segment > segmentMapList.size() + 1) {
return BAD_ADDRESS; return BAD_ADDRESS;
} }
@ -176,32 +180,25 @@ public class PdbAddressManager {
// TODO: Need to verify. Guessing at the moment // TODO: Need to verify. Guessing at the moment
relativeVirtualAddress = segmentMapList.get(segment - 1).getSegmentOffset(); relativeVirtualAddress = segmentMapList.get(segment - 1).getSegmentOffset();
} }
if (omapFromSource != null) {
relativeVirtualAddress = omapFromSource.get(relativeVirtualAddress);
if (relativeVirtualAddress == null) {
return BAD_ADDRESS;
}
}
return imageBase.add(relativeVirtualAddress); return imageBase.add(relativeVirtualAddress);
} }
private Address getRawAddress_orig(int segment, long offset) { private Long applyOMap(Long relativeVirtualAddress) {
if (segment < 0 || segment > allSegmentsInfo.size()) { if (omapFromSource == null) {
return BAD_ADDRESS; return relativeVirtualAddress;
} }
// We are lumping 0 and size as EXTERNAL... one or other could be image base... but not // NOTE: Original map entries are 32-bit values zero-extended to a java long (64-bits)
// necessarily consistent... but that's OK... it is still "EXTERNAL" from the program. SortedMap<Long, Long> headMap = omapFromSource.headMap(relativeVirtualAddress + 1);
else if (segment == 0 || segment == allSegmentsInfo.size()) { if (headMap.isEmpty()) {
// External address. return null;
// Was getting issues of _IMAGE_DOSHEADER showing up with a segment index one
// beyond the end.
return EXTERNAL_ADDRESS;
} }
SegmentInfo segmentInfo = allSegmentsInfo.get(segment); long from = headMap.lastKey();
if (offset >= segmentInfo.getLength()) { long to = headMap.get(from);
return BAD_ADDRESS; if (to == 0) {
return 0L;
} }
return segmentInfo.getStartAddress().add(offset); return to + (relativeVirtualAddress - from);
} }
/** /**
@ -297,45 +294,50 @@ public class PdbAddressManager {
} }
} }
private void determineMemoryBlocks_orig() { // private void determineMemoryBlocks_orig() {
// Set section/segment 0 to image base. (should be what is header), but what is its size? // // Set section/segment 0 to image base. (should be what is header), but what is its size?
// TODO... made up size for now... is there something else? We could put null instead. // // TODO... made up size for now... is there something else? We could put null instead.
// For now, the method that reads this information might report EXTERNAL instead of // // For now, the method that reads this information might report EXTERNAL instead of
// trying to use this. // // trying to use this.
long segmentZeroLength = 0x7fffffff; // long segmentZeroLength = 0x7fffffff;
allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength)); // allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength));
PdbDebugInfo dbi = applicator.getPdb().getDebugInfo(); // PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
if (dbi instanceof PdbNewDebugInfo) { // if (dbi instanceof PdbNewDebugInfo) {
DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData(); // DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
List<ImageSectionHeader> imageSectionHeaders = debugData.getImageSectionHeaders(); // List<ImageSectionHeader> imageSectionHeaders = debugData.getImageSectionHeaders();
for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) { // for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
long virtualAddress = imageSectionHeader.getVirtualAddress(); // long virtualAddress = imageSectionHeader.getVirtualAddress();
// TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps // // TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps
// it keys off whether virtualAddress is not some special value such as // // it keys off whether virtualAddress is not some special value such as
// 0x00000000 or 0xffffffff. // // 0x00000000 or 0xffffffff.
long size = imageSectionHeader.getUnionPAVS(); // long size = imageSectionHeader.getUnionPAVS();
allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size)); // allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size));
} // }
} // }
// else instance of PdbDebugInfo; TODO: what can we do here? // // else instance of PdbDebugInfo; TODO: what can we do here?
// Maybe get information from the program itself. // // Maybe get information from the program itself.
//
// TODO: what should we do with these? Not doing anything at the moment // // TODO: what should we do with these? Not doing anything at the moment
AbstractPdb pdb = applicator.getPdb(); // AbstractPdb pdb = applicator.getPdb();
List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList(); // List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList();
for (SegmentMapDescription segmentMapDescription : segmentMapList) { // for (SegmentMapDescription segmentMapDescription : segmentMapList) {
segmentMapDescription.getSegmentOffset(); // segmentMapDescription.getSegmentOffset();
segmentMapDescription.getLength(); // segmentMapDescription.getLength();
} // }
} // }
private void determineMemoryBlocks() { private void determineMemoryBlocks() {
PdbDebugInfo dbi = applicator.getPdb().getDebugInfo(); PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
segmentMapList = dbi.getSegmentMapList(); segmentMapList = dbi.getSegmentMapList();
if (dbi instanceof PdbNewDebugInfo) { if (dbi instanceof PdbNewDebugInfo) {
DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData(); DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
omapFromSource = debugData.getOmapFromSource(); imageSectionHeaders = debugData.getImageSectionHeadersOrig();
imageSectionHeaders = debugData.getImageSectionHeaders(); if (imageSectionHeaders != null) {
omapFromSource = debugData.getOmapFromSource();
}
else {
imageSectionHeaders = debugData.getImageSectionHeaders();
}
} }
} }
@ -399,6 +401,7 @@ public class PdbAddressManager {
// Put in two basic entries so we do not have to do conditional tests before looking // Put in two basic entries so we do not have to do conditional tests before looking
// up values in the table. // up values in the table.
remapAddressByAddress.put(BAD_ADDRESS, BAD_ADDRESS); remapAddressByAddress.put(BAD_ADDRESS, BAD_ADDRESS);
remapAddressByAddress.put(ZERO_ADDRESS, ZERO_ADDRESS);
remapAddressByAddress.put(EXTERNAL_ADDRESS, EXTERNAL_ADDRESS); remapAddressByAddress.put(EXTERNAL_ADDRESS, EXTERNAL_ADDRESS);
} }

View file

@ -200,9 +200,8 @@ public class PdbApplicator {
pdbAddressManager.logReport(); pdbAddressManager.logReport();
String applicatorMetrics = pdbApplicatorMetrics.getPostProcessingReport(); pdbApplicatorMetrics.logReport();
Msg.info(this, applicatorMetrics);
PdbLog.message(applicatorMetrics);
Msg.info(this, "PDB Terminated Normally"); Msg.info(this, "PDB Terminated Normally");
} }
@ -800,6 +799,10 @@ public class PdbApplicator {
appendLogMsg("Invalid address encountered for: " + name); appendLogMsg("Invalid address encountered for: " + name);
return true; return true;
} }
if (address == PdbAddressManager.ZERO_ADDRESS) {
// Symbol OMAP resulted in 0 RVA - Discard silently
return true;
}
if (address == PdbAddressManager.EXTERNAL_ADDRESS) { if (address == PdbAddressManager.EXTERNAL_ADDRESS) {
//Msg.info(this, "External address not known for: " + name); //Msg.info(this, "External address not known for: " + name);
return true; return true;

View file

@ -18,10 +18,12 @@ package ghidra.app.util.pdb.pdbapplicator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
/** /**
* Metrics captured during the application of a PDB. This is a Ghidra class separate from the * Metrics captured during the application of a PDB. This is a Ghidra class separate from the
@ -200,12 +202,12 @@ public class PdbApplicatorMetrics {
//============================================================================================== //==============================================================================================
/** /**
* Return some post-processing metrics for applying the PDB * Generate some post-processing metrics and write to log
* @return {@link String} of pretty output.
*/ */
String getPostProcessingReport() { void logReport() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("===Begin PdbApplicatorMetrics Report===\n");
builder.append(reportNonappliableTypes()); builder.append(reportNonappliableTypes());
builder.append(reportUnunsualThisPointerTypes()); builder.append(reportUnunsualThisPointerTypes());
builder.append(reportUnunsualThisPointerUnderlyingTypes()); builder.append(reportUnunsualThisPointerUnderlyingTypes());
@ -214,8 +216,17 @@ public class PdbApplicatorMetrics {
builder.append(reportUnexpectedPublicSymbols()); builder.append(reportUnexpectedPublicSymbols());
builder.append(reportUnexpectedGlobalSymbols()); builder.append(reportUnexpectedGlobalSymbols());
builder.append(reportEnumerateNarrowing()); builder.append(reportEnumerateNarrowing());
if (builder.length() == 0) {
return; // nothing reported
}
builder.insert(0, "===Begin PdbApplicatorMetrics Report===\n");
builder.append("====End PdbApplicatorMetrics Report====\n"); builder.append("====End PdbApplicatorMetrics Report====\n");
return builder.toString(); String text = builder.toString();
Msg.info(this, text);
PdbLog.message(text);
} }
private String reportNonappliableTypes() { private String reportNonappliableTypes() {

View file

@ -18,8 +18,14 @@ package ghidra.app.util.pdb.pdbapplicator;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol; import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractPublicMsSymbol;
import ghidra.app.util.datatype.microsoft.GuidDataType;
import ghidra.app.util.datatype.microsoft.GuidUtil;
import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator; import ghidra.app.util.pdb.pdbapplicator.SymbolGroup.AbstractMsSymbolIterator;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -56,9 +62,12 @@ public class PublicSymbolApplier extends MsSymbolApplier {
void apply() throws CancelledException, PdbException { void apply() throws CancelledException, PdbException {
symbolAddress = applicator.getAddress(symbol); symbolAddress = applicator.getAddress(symbol);
if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) {
String name = symbol.getName();
if (applicator.isInvalidAddress(symbolAddress, name)) {
return; return;
} }
existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress); existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress);
// TODO: Consider... could add restriction of not putting down symbol if it is mangled, // TODO: Consider... could add restriction of not putting down symbol if it is mangled,
// as this would violate the uniqueness of the symbol... but we would also want to // as this would violate the uniqueness of the symbol... but we would also want to
@ -67,7 +76,18 @@ public class PublicSymbolApplier extends MsSymbolApplier {
// Note: there might be issues of thunk functions getting the same mangled name // Note: there might be issues of thunk functions getting the same mangled name
// as thunked functions, which violates the thesis of their being unique. // as thunked functions, which violates the thesis of their being unique.
// TODO: investigate this. // TODO: investigate this.
applicator.createSymbol(symbolAddress, symbol.getName(), true); applicator.createSymbol(symbolAddress, name, true);
Program program = applicator.getProgram();
if (GuidUtil.isGuidLabel(program, symbolAddress, name)) {
try {
DataUtilities.createData(program, symbolAddress, new GuidDataType(), -1, false,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
}
catch (CodeUnitInsertionException e) {
// ignore
}
}
} }
} }

View file

@ -15,7 +15,8 @@
*/ */
package pdb; package pdb;
import java.awt.*; import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.*; import javax.swing.*;
@ -30,7 +31,7 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
private boolean isCanceled; private boolean isCanceled;
private boolean useMsDiaParser = true; private boolean useMsDiaParser;
private PdbApplicatorRestrictions restrictions = PdbApplicatorRestrictions.NONE; private PdbApplicatorRestrictions restrictions = PdbApplicatorRestrictions.NONE;
/** /**
@ -57,9 +58,10 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
optionsPanel.add(new JLabel("PDB Parser:")); optionsPanel.add(new JLabel("PDB Parser:"));
if (isPdbFile) { if (isPdbFile) {
useMsDiaParser = false; // Use PDB Universal by default
if (PdbParser.onWindows) { if (PdbParser.onWindows) {
final GComboBox<String> combo = final GComboBox<String> combo =
new GComboBox<>(new String[] { "PDB MSDIA", "PDB Universal (Prototype)" }); new GComboBox<>(new String[] { "PDB Universal", "PDB MSDIA" });
combo.setSelectedIndex(0); combo.setSelectedIndex(0);
restrictionsCombo.setEnabled(!useMsDiaParser); restrictionsCombo.setEnabled(!useMsDiaParser);
combo.addActionListener(e -> { combo.addActionListener(e -> {
@ -73,8 +75,8 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
} }
else { else {
useMsDiaParser = false; useMsDiaParser = false;
JLabel label = new JLabel("PDB Universal (Prototype)"); JLabel label = new JLabel("PDB Universal");
label.setForeground(Color.red); // set color to emphasize prototype status //label.setForeground(Color.red); // set color to emphasize prototype status
optionsPanel.add(label); optionsPanel.add(label);
} }
} }

View file

@ -47,7 +47,7 @@ class LoadPdbTask extends Task {
LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser, LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser,
PdbApplicatorRestrictions restrictions, DataTypeManagerService service) { PdbApplicatorRestrictions restrictions, DataTypeManagerService service) {
super("Loading PDB...", true, false, false); super("Load PDB", true, false, false);
this.program = program; this.program = program;
this.pdbFile = pdbFile; this.pdbFile = pdbFile;
this.useMsDiaParser = useMsDiaParser; this.useMsDiaParser = useMsDiaParser;