mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 00:20:10 +00:00
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:
parent
10702d0569
commit
b2eb2aaa65
@ -15,16 +15,18 @@
|
||||
*/
|
||||
package ghidra.app.util.datatype.microsoft;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class GuidUtil {
|
||||
|
||||
public enum GuidType {
|
||||
@ -63,8 +65,8 @@ public class GuidUtil {
|
||||
return;
|
||||
}
|
||||
idTables = new Hashtable<GuidType, Hashtable<String, GuidInfo>>();
|
||||
for (int i = 0; i < guidTypes.length; i++) {
|
||||
idTables.put(guidTypes[i], new Hashtable<String, GuidInfo>());
|
||||
for (GuidType guidType : guidTypes) {
|
||||
idTables.put(guidType, new Hashtable<String, GuidInfo>());
|
||||
}
|
||||
buildGuidMap();
|
||||
initialized = true;
|
||||
@ -81,11 +83,11 @@ public class GuidUtil {
|
||||
}
|
||||
initialize();
|
||||
guidString = guidString.toUpperCase();
|
||||
for (int i = 0; i < guidTypes.length; i++) {
|
||||
if (guidTypes[i].equals(GuidType.SYNTAX)) {
|
||||
for (GuidType guidType : guidTypes) {
|
||||
if (guidType.equals(GuidType.SYNTAX)) {
|
||||
continue;
|
||||
}
|
||||
Hashtable<String, GuidInfo> table = idTables.get(guidTypes[i]);
|
||||
Hashtable<String, GuidInfo> table = idTables.get(guidType);
|
||||
GuidInfo guidInfo = table.get(guidString);
|
||||
if (guidInfo != null) {
|
||||
return guidInfo;
|
||||
@ -106,11 +108,11 @@ public class GuidUtil {
|
||||
}
|
||||
|
||||
private static void buildGuidMap() {
|
||||
for (int i = 0; i < guidTypes.length; i++) {
|
||||
Hashtable<String, GuidInfo> table = idTables.get(guidTypes[i]);
|
||||
for (GuidType guidType : guidTypes) {
|
||||
Hashtable<String, GuidInfo> table = idTables.get(guidType);
|
||||
|
||||
String filename = guidTypes[i].getFilename();
|
||||
readGuidFile(guidTypes[i], filename, table);
|
||||
String filename = guidType.getFilename();
|
||||
readGuidFile(guidType, filename, table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,8 +197,8 @@ public class GuidUtil {
|
||||
}
|
||||
|
||||
private static boolean isOK(long[] data) {
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if ((data[i] != 0) || (data[i] != 0xFFFFFFFFL)) {
|
||||
for (long element : data) {
|
||||
if ((element != 0) || (element != 0xFFFFFFFFL)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -229,8 +231,9 @@ public class GuidUtil {
|
||||
guidString += Conv.toHexString((short) (data[1] >> 16)) + delim;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
guidString += Conv.toHexString((byte) (data[2] >> i * 8));
|
||||
if (i == 1)
|
||||
if (i == 1) {
|
||||
guidString += delim;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
guidString += Conv.toHexString((byte) (data[3] >> i * 8));
|
||||
@ -270,8 +273,9 @@ public class GuidUtil {
|
||||
guidString += Conv.toHexString((short) (data[1] >> 16)) + delim;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
guidString += Conv.toHexString((byte) (data[2] >> i * 8));
|
||||
if (i == 1)
|
||||
if (i == 1) {
|
||||
guidString += delim;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
guidString += Conv.toHexString((byte) (data[3] >> i * 8));
|
||||
@ -291,4 +295,32 @@ public class GuidUtil {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* Finds and applies PDB debug information to the given Windows executable.
|
||||
*/
|
||||
public class PdbAnalyzer extends AbstractAnalyzer {
|
||||
static final String NAME = "PDB";
|
||||
static final String NAME = "PDB MSDIA";
|
||||
static final boolean DEFAULT_ENABLEMENT = !PdbUniversalAnalyzer.DEFAULT_ENABLEMENT;
|
||||
private static final String DESCRIPTION =
|
||||
"PDB Analyzer.\n" + "Requires MS DIA-SDK for raw PDB processing (Windows only).\n" +
|
||||
|
@ -61,9 +61,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
//==============================================================================================
|
||||
static final String NAME = "PDB Universal";
|
||||
// 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 =
|
||||
"[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.";
|
||||
|
||||
//==============================================================================================
|
||||
@ -203,7 +203,7 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
||||
//==============================================================================================
|
||||
public PdbUniversalAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
|
||||
setPrototype();
|
||||
//setPrototype();
|
||||
setDefaultEnablement(DEFAULT_ENABLEMENT);
|
||||
setPriority(AnalysisPriority.FORMAT_ANALYSIS.after());
|
||||
setSupportsOneTimeAnalysis();
|
||||
|
@ -20,14 +20,12 @@ import java.util.Set;
|
||||
|
||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||
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.GuidUtil;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
@ -37,11 +35,9 @@ import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
class ApplySymbols {
|
||||
private static final String MS_VF_TABLE_PREFIX = "??_7";
|
||||
private static final String MS_VB_TABLE_PREFIX = "??_8";
|
||||
private static final String MS_STRING_PREFIX = "??_C@_";
|
||||
|
||||
private static final String MS_GUID_PREFIX = "_GUID_";
|
||||
// private static final String MS_VF_TABLE_PREFIX = "??_7";
|
||||
// private static final String MS_VB_TABLE_PREFIX = "??_8";
|
||||
// private static final String MS_STRING_PREFIX = "??_C@_";
|
||||
|
||||
private ApplySymbols() {
|
||||
// static use only
|
||||
@ -146,11 +142,11 @@ class ApplySymbols {
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
if (name.startsWith(MS_STRING_PREFIX)) {
|
||||
// if (name.startsWith(MS_STRING_PREFIX)) {
|
||||
// TODO: Should this be handled by the demangler instead of here?
|
||||
boolean isUnicode = isUnicode(name);
|
||||
pdbParser.createString(isUnicode, address, log);
|
||||
}
|
||||
// boolean isUnicode = isUnicode(name);
|
||||
// pdbParser.createString(isUnicode, address, log);
|
||||
// }
|
||||
////////////
|
||||
// Commented out the following for now, because it appears to be doing things it
|
||||
// shouldn't. Many of the things are very loosely speculative.
|
||||
@ -170,7 +166,7 @@ class ApplySymbols {
|
||||
// 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);
|
||||
}
|
||||
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) {
|
||||
Symbol primarySymbol = program.getSymbolTable().getPrimarySymbol(address);
|
||||
if (primarySymbol != null) {
|
||||
@ -222,13 +201,13 @@ class ApplySymbols {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isUnicode(String name) {
|
||||
if (name.startsWith(MS_STRING_PREFIX)) {
|
||||
if (name.charAt(MS_STRING_PREFIX.length()) == '1') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// private static boolean isUnicode(String name) {
|
||||
// if (name.startsWith(MS_STRING_PREFIX)) {
|
||||
// if (name.charAt(MS_STRING_PREFIX.length()) == '1') {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
}
|
||||
|
@ -67,9 +67,10 @@ public class DebugData {
|
||||
private List<Integer> debugStreams = new ArrayList<>();
|
||||
|
||||
private List<FramePointerOmissionRecord> framePointerOmissionData;
|
||||
private Map<Long, Long> omapToSource;
|
||||
private Map<Long, Long> omapFromSource;
|
||||
// private SortedMap<Long, Long> omapToSource;
|
||||
private SortedMap<Long, Long> omapFromSource;
|
||||
private List<ImageSectionHeader> imageSectionHeaders;
|
||||
private List<ImageSectionHeader> imageSectionHeadersOrig;
|
||||
|
||||
private List<ImageFunctionEntry> pData;
|
||||
|
||||
@ -96,19 +97,19 @@ public class DebugData {
|
||||
return framePointerOmissionData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OMAP_TO_SOURCE mapping of RVA to RVA
|
||||
* @return the omapToSource or null if does not exist.
|
||||
*/
|
||||
public Map<Long, Long> getOmapToSource() {
|
||||
return omapToSource;
|
||||
}
|
||||
// /**
|
||||
// * Returns the OMAP_TO_SOURCE mapping of RVA to RVA
|
||||
// * @return the omapToSource or null if does not exist.
|
||||
// */
|
||||
// public SortedMap<Long, Long> getOmapToSource() {
|
||||
// return omapToSource;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the OMAP_FROM_SOURCE mapping of RVA to RVA
|
||||
* @return the omapFromSource or null if does not exist.
|
||||
*/
|
||||
public Map<Long, Long> getOmapFromSource() {
|
||||
public SortedMap<Long, Long> getOmapFromSource() {
|
||||
return omapFromSource;
|
||||
}
|
||||
|
||||
@ -120,6 +121,16 @@ public class DebugData {
|
||||
return imageSectionHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link List}<{@link ImageSectionHeader}>.
|
||||
* 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
|
||||
* stream numbers for varying Debug Types--the order/location of the stream number is for
|
||||
@ -178,13 +189,13 @@ public class DebugData {
|
||||
// TODO: implement.
|
||||
break;
|
||||
case OMAP_TO_SOURCE:
|
||||
deserializeOMapToSource(streamNum, monitor);
|
||||
// omapToSource = deserializeOMap(streamNum, monitor);
|
||||
break;
|
||||
case OMAP_FROM_SOURCE:
|
||||
deserializeOMapFromSource(streamNum, monitor);
|
||||
omapFromSource = deserializeOMap(streamNum, monitor);
|
||||
break;
|
||||
case SECTION_HEADER:
|
||||
deserializeSectionHeader(streamNum, monitor);
|
||||
imageSectionHeaders = deserializeSectionHeaders(streamNum, monitor);
|
||||
break;
|
||||
case TOKEN_RID_MAP:
|
||||
// TODO: implement.
|
||||
@ -199,7 +210,7 @@ public class DebugData {
|
||||
// TODO: implement.
|
||||
break;
|
||||
case SECTION_HEADER_ORIG:
|
||||
// TODO: implement.
|
||||
imageSectionHeadersOrig = deserializeSectionHeaders(streamNum, monitor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -219,58 +230,30 @@ public class DebugData {
|
||||
}
|
||||
}
|
||||
|
||||
private void deserializeOMapToSource(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)
|
||||
private SortedMap<Long, Long> deserializeOMap(int streamNum, TaskMonitor monitor)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
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()) {
|
||||
monitor.checkCanceled();
|
||||
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
|
||||
imageSectionHeader.parse(reader);
|
||||
imageSectionHeaders.add(imageSectionHeader);
|
||||
sectionHeaders.add(imageSectionHeader);
|
||||
}
|
||||
return sectionHeaders;
|
||||
}
|
||||
|
||||
// TODO: This is incomplete.
|
||||
@ -372,15 +355,15 @@ public class DebugData {
|
||||
}
|
||||
writer.write("End FramePointerOmissionData--------------------------------\n");
|
||||
|
||||
writer.write("OmapToSource------------------------------------------------\n");
|
||||
if (omapToSource != null) {
|
||||
int num = 0;
|
||||
for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) {
|
||||
writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(),
|
||||
entry.getValue()));
|
||||
}
|
||||
}
|
||||
writer.write("End OmapToSource--------------------------------------------\n");
|
||||
// writer.write("OmapToSource------------------------------------------------\n");
|
||||
// if (omapToSource != null) {
|
||||
// int num = 0;
|
||||
// for (Map.Entry<Long, Long> entry : omapToSource.entrySet()) {
|
||||
// writer.write(String.format("0X%08X: 0X%012X, 0X%012X\n", num++, entry.getKey(),
|
||||
// entry.getValue()));
|
||||
// }
|
||||
// }
|
||||
// writer.write("End OmapToSource--------------------------------------------\n");
|
||||
|
||||
writer.write("OmapFromSource----------------------------------------------\n");
|
||||
if (omapFromSource != null) {
|
||||
@ -401,6 +384,15 @@ public class DebugData {
|
||||
}
|
||||
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");
|
||||
if (pData != null) {
|
||||
for (ImageFunctionEntry entry : pData) {
|
||||
|
@ -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
|
||||
// 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.
|
||||
static final Address EXTERNAL_ADDRESS = AddressSpace.EXTERNAL_SPACE.getAddress(0);
|
||||
static final Address BAD_ADDRESS = Address.NO_ADDRESS; // using NO_ADDRESS as a marker
|
||||
// to test for it being an external address. These marker addresses should never be used
|
||||
// for symbol creation.
|
||||
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 List<SegmentMapDescription> segmentMapList;
|
||||
private List<ImageSectionHeader> imageSectionHeaders;
|
||||
private Map<Long, Long> omapFromSource;
|
||||
private SortedMap<Long, Long> omapFromSource;
|
||||
private List<PeCoffGroupMsSymbol> memoryGroupRefinement;
|
||||
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
|
||||
// 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<>();
|
||||
memorySectionRefinement = new ArrayList<>();
|
||||
// TODO allSegmentInfo might go away if we use ImageSectionHeader. Under investigation.
|
||||
allSegmentsInfo = new ArrayList<>();
|
||||
// allSegmentsInfo = new ArrayList<>();
|
||||
addressByPreExistingSymbolName = new HashMap<>();
|
||||
primarySymbolByAddress = new HashMap<>();
|
||||
determineMemoryBlocks();
|
||||
determineMemoryBlocks_orig();
|
||||
// determineMemoryBlocks_orig();
|
||||
mapPreExistingSymbols();
|
||||
createAddressRemap();
|
||||
}
|
||||
@ -144,16 +146,10 @@ public class PdbAddressManager {
|
||||
* {@code Address.EXTERNAL_ADDRESS} if the address is external to the program.
|
||||
*/
|
||||
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) {
|
||||
return BAD_ADDRESS;
|
||||
}
|
||||
Long relativeVirtualAddress;
|
||||
Long relativeVirtualAddress = null;
|
||||
if (imageSectionHeaders != null) {
|
||||
if (segment > imageSectionHeaders.size() + 1) {
|
||||
return BAD_ADDRESS;
|
||||
@ -164,8 +160,16 @@ public class PdbAddressManager {
|
||||
}
|
||||
relativeVirtualAddress =
|
||||
imageSectionHeaders.get(segment - 1).getVirtualAddress() + offset;
|
||||
relativeVirtualAddress = applyOMap(relativeVirtualAddress);
|
||||
if (relativeVirtualAddress == null) {
|
||||
return BAD_ADDRESS;
|
||||
}
|
||||
if (relativeVirtualAddress == 0) {
|
||||
return ZERO_ADDRESS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: need to verify use of segments here!
|
||||
if (segment > segmentMapList.size() + 1) {
|
||||
return BAD_ADDRESS;
|
||||
}
|
||||
@ -176,32 +180,25 @@ public class PdbAddressManager {
|
||||
// TODO: Need to verify. Guessing at the moment
|
||||
relativeVirtualAddress = segmentMapList.get(segment - 1).getSegmentOffset();
|
||||
}
|
||||
if (omapFromSource != null) {
|
||||
relativeVirtualAddress = omapFromSource.get(relativeVirtualAddress);
|
||||
if (relativeVirtualAddress == null) {
|
||||
return BAD_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
return imageBase.add(relativeVirtualAddress);
|
||||
}
|
||||
|
||||
private Address getRawAddress_orig(int segment, long offset) {
|
||||
if (segment < 0 || segment > allSegmentsInfo.size()) {
|
||||
return BAD_ADDRESS;
|
||||
private Long applyOMap(Long relativeVirtualAddress) {
|
||||
if (omapFromSource == null) {
|
||||
return relativeVirtualAddress;
|
||||
}
|
||||
// We are lumping 0 and size as EXTERNAL... one or other could be image base... but not
|
||||
// necessarily consistent... but that's OK... it is still "EXTERNAL" from the program.
|
||||
else if (segment == 0 || segment == allSegmentsInfo.size()) {
|
||||
// External address.
|
||||
// Was getting issues of _IMAGE_DOSHEADER showing up with a segment index one
|
||||
// beyond the end.
|
||||
return EXTERNAL_ADDRESS;
|
||||
// NOTE: Original map entries are 32-bit values zero-extended to a java long (64-bits)
|
||||
SortedMap<Long, Long> headMap = omapFromSource.headMap(relativeVirtualAddress + 1);
|
||||
if (headMap.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
SegmentInfo segmentInfo = allSegmentsInfo.get(segment);
|
||||
if (offset >= segmentInfo.getLength()) {
|
||||
return BAD_ADDRESS;
|
||||
long from = headMap.lastKey();
|
||||
long to = headMap.get(from);
|
||||
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() {
|
||||
// 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.
|
||||
// For now, the method that reads this information might report EXTERNAL instead of
|
||||
// trying to use this.
|
||||
long segmentZeroLength = 0x7fffffff;
|
||||
allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength));
|
||||
PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
|
||||
if (dbi instanceof PdbNewDebugInfo) {
|
||||
DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
|
||||
List<ImageSectionHeader> imageSectionHeaders = debugData.getImageSectionHeaders();
|
||||
for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
|
||||
long virtualAddress = imageSectionHeader.getVirtualAddress();
|
||||
// TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps
|
||||
// it keys off whether virtualAddress is not some special value such as
|
||||
// 0x00000000 or 0xffffffff.
|
||||
long size = imageSectionHeader.getUnionPAVS();
|
||||
allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size));
|
||||
}
|
||||
}
|
||||
// else instance of PdbDebugInfo; TODO: what can we do here?
|
||||
// Maybe get information from the program itself.
|
||||
|
||||
// TODO: what should we do with these? Not doing anything at the moment
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList();
|
||||
for (SegmentMapDescription segmentMapDescription : segmentMapList) {
|
||||
segmentMapDescription.getSegmentOffset();
|
||||
segmentMapDescription.getLength();
|
||||
}
|
||||
}
|
||||
// private void determineMemoryBlocks_orig() {
|
||||
// // 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.
|
||||
// // For now, the method that reads this information might report EXTERNAL instead of
|
||||
// // trying to use this.
|
||||
// long segmentZeroLength = 0x7fffffff;
|
||||
// allSegmentsInfo.add(new SegmentInfo(imageBase, segmentZeroLength));
|
||||
// PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
|
||||
// if (dbi instanceof PdbNewDebugInfo) {
|
||||
// DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
|
||||
// List<ImageSectionHeader> imageSectionHeaders = debugData.getImageSectionHeaders();
|
||||
// for (ImageSectionHeader imageSectionHeader : imageSectionHeaders) {
|
||||
// long virtualAddress = imageSectionHeader.getVirtualAddress();
|
||||
// // TODO: not sure when unionPAVS is physical address vs. virtual size. Perhaps
|
||||
// // it keys off whether virtualAddress is not some special value such as
|
||||
// // 0x00000000 or 0xffffffff.
|
||||
// long size = imageSectionHeader.getUnionPAVS();
|
||||
// allSegmentsInfo.add(new SegmentInfo(imageBase.add(virtualAddress), size));
|
||||
// }
|
||||
// }
|
||||
// // else instance of PdbDebugInfo; TODO: what can we do here?
|
||||
// // Maybe get information from the program itself.
|
||||
//
|
||||
// // TODO: what should we do with these? Not doing anything at the moment
|
||||
// AbstractPdb pdb = applicator.getPdb();
|
||||
// List<SegmentMapDescription> segmentMapList = pdb.getDebugInfo().getSegmentMapList();
|
||||
// for (SegmentMapDescription segmentMapDescription : segmentMapList) {
|
||||
// segmentMapDescription.getSegmentOffset();
|
||||
// segmentMapDescription.getLength();
|
||||
// }
|
||||
// }
|
||||
|
||||
private void determineMemoryBlocks() {
|
||||
PdbDebugInfo dbi = applicator.getPdb().getDebugInfo();
|
||||
segmentMapList = dbi.getSegmentMapList();
|
||||
if (dbi instanceof PdbNewDebugInfo) {
|
||||
DebugData debugData = ((PdbNewDebugInfo) dbi).getDebugData();
|
||||
omapFromSource = debugData.getOmapFromSource();
|
||||
imageSectionHeaders = debugData.getImageSectionHeaders();
|
||||
imageSectionHeaders = debugData.getImageSectionHeadersOrig();
|
||||
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
|
||||
// up values in the table.
|
||||
remapAddressByAddress.put(BAD_ADDRESS, BAD_ADDRESS);
|
||||
remapAddressByAddress.put(ZERO_ADDRESS, ZERO_ADDRESS);
|
||||
remapAddressByAddress.put(EXTERNAL_ADDRESS, EXTERNAL_ADDRESS);
|
||||
}
|
||||
|
||||
|
@ -200,9 +200,8 @@ public class PdbApplicator {
|
||||
|
||||
pdbAddressManager.logReport();
|
||||
|
||||
String applicatorMetrics = pdbApplicatorMetrics.getPostProcessingReport();
|
||||
Msg.info(this, applicatorMetrics);
|
||||
PdbLog.message(applicatorMetrics);
|
||||
pdbApplicatorMetrics.logReport();
|
||||
|
||||
Msg.info(this, "PDB Terminated Normally");
|
||||
}
|
||||
|
||||
@ -800,6 +799,10 @@ public class PdbApplicator {
|
||||
appendLogMsg("Invalid address encountered for: " + name);
|
||||
return true;
|
||||
}
|
||||
if (address == PdbAddressManager.ZERO_ADDRESS) {
|
||||
// Symbol OMAP resulted in 0 RVA - Discard silently
|
||||
return true;
|
||||
}
|
||||
if (address == PdbAddressManager.EXTERNAL_ADDRESS) {
|
||||
//Msg.info(this, "External address not known for: " + name);
|
||||
return true;
|
||||
|
@ -18,10 +18,12 @@ package ghidra.app.util.pdb.pdbapplicator;
|
||||
import java.util.HashSet;
|
||||
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.type.AbstractMsType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
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
|
||||
@ -200,12 +202,12 @@ public class PdbApplicatorMetrics {
|
||||
//==============================================================================================
|
||||
|
||||
/**
|
||||
* Return some post-processing metrics for applying the PDB
|
||||
* @return {@link String} of pretty output.
|
||||
* Generate some post-processing metrics and write to log
|
||||
*/
|
||||
String getPostProcessingReport() {
|
||||
void logReport() {
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("===Begin PdbApplicatorMetrics Report===\n");
|
||||
|
||||
builder.append(reportNonappliableTypes());
|
||||
builder.append(reportUnunsualThisPointerTypes());
|
||||
builder.append(reportUnunsualThisPointerUnderlyingTypes());
|
||||
@ -214,8 +216,17 @@ public class PdbApplicatorMetrics {
|
||||
builder.append(reportUnexpectedPublicSymbols());
|
||||
builder.append(reportUnexpectedGlobalSymbols());
|
||||
builder.append(reportEnumerateNarrowing());
|
||||
|
||||
if (builder.length() == 0) {
|
||||
return; // nothing reported
|
||||
}
|
||||
|
||||
builder.insert(0, "===Begin 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() {
|
||||
|
@ -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.symbol.AbstractMsSymbol;
|
||||
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.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.CancelledException;
|
||||
|
||||
@ -56,9 +62,12 @@ public class PublicSymbolApplier extends MsSymbolApplier {
|
||||
void apply() throws CancelledException, PdbException {
|
||||
|
||||
symbolAddress = applicator.getAddress(symbol);
|
||||
if (applicator.isInvalidAddress(symbolAddress, symbol.getName())) {
|
||||
|
||||
String name = symbol.getName();
|
||||
if (applicator.isInvalidAddress(symbolAddress, name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
existingSymbolAddress = applicator.witnessSymbolNameAtAddress(getName(), symbolAddress);
|
||||
// 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
|
||||
@ -67,7 +76,18 @@ public class PublicSymbolApplier extends MsSymbolApplier {
|
||||
// Note: there might be issues of thunk functions getting the same mangled name
|
||||
// as thunked functions, which violates the thesis of their being unique.
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package pdb;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@ -30,7 +31,7 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
|
||||
|
||||
private boolean isCanceled;
|
||||
|
||||
private boolean useMsDiaParser = true;
|
||||
private boolean useMsDiaParser;
|
||||
private PdbApplicatorRestrictions restrictions = PdbApplicatorRestrictions.NONE;
|
||||
|
||||
/**
|
||||
@ -57,9 +58,10 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
|
||||
optionsPanel.add(new JLabel("PDB Parser:"));
|
||||
|
||||
if (isPdbFile) {
|
||||
useMsDiaParser = false; // Use PDB Universal by default
|
||||
if (PdbParser.onWindows) {
|
||||
final GComboBox<String> combo =
|
||||
new GComboBox<>(new String[] { "PDB MSDIA", "PDB Universal (Prototype)" });
|
||||
new GComboBox<>(new String[] { "PDB Universal", "PDB MSDIA" });
|
||||
combo.setSelectedIndex(0);
|
||||
restrictionsCombo.setEnabled(!useMsDiaParser);
|
||||
combo.addActionListener(e -> {
|
||||
@ -73,8 +75,8 @@ class AskPdbOptionsDialog extends DialogComponentProvider {
|
||||
}
|
||||
else {
|
||||
useMsDiaParser = false;
|
||||
JLabel label = new JLabel("PDB Universal (Prototype)");
|
||||
label.setForeground(Color.red); // set color to emphasize prototype status
|
||||
JLabel label = new JLabel("PDB Universal");
|
||||
//label.setForeground(Color.red); // set color to emphasize prototype status
|
||||
optionsPanel.add(label);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class LoadPdbTask extends Task {
|
||||
|
||||
LoadPdbTask(Program program, File pdbFile, boolean useMsDiaParser,
|
||||
PdbApplicatorRestrictions restrictions, DataTypeManagerService service) {
|
||||
super("Loading PDB...", true, false, false);
|
||||
super("Load PDB", true, false, false);
|
||||
this.program = program;
|
||||
this.pdbFile = pdbFile;
|
||||
this.useMsDiaParser = useMsDiaParser;
|
||||
|
Loading…
Reference in New Issue
Block a user