mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 13:42:06 +00:00
GP-4383 - PDB - Changes to MultiphaseResolver and IOException propagation; extract ClassFieldAttributes from CppCompositeType
This commit is contained in:
parent
ddfb041885
commit
0d68aab0a8
@ -80,14 +80,11 @@ public class DebugData {
|
||||
|
||||
/**
|
||||
* Returns the Frame Pointer Omission data
|
||||
* @return the framePointerOmissionData or null if does not exist
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the framePointerOmissionData or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public List<FramePointerOmissionRecord> getFramePointerOmissionData()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.FRAME_POINTER_OMISSION.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -105,14 +102,10 @@ public class DebugData {
|
||||
|
||||
/**
|
||||
* Returns the OMAP_FROM_SOURCE mapping of RVA to RVA
|
||||
* @return the omapFromSource or null if does not exist.
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the omapFromSource or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public SortedMap<Long, Long> getOmapFromSource()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
public SortedMap<Long, Long> getOmapFromSource() throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.OMAP_FROM_SOURCE.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -122,14 +115,10 @@ public class DebugData {
|
||||
|
||||
/**
|
||||
* Returns the {@link List}<{@link ImageSectionHeader}>
|
||||
* @return the imageSectionHeaders or null if does not exist
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the imageSectionHeaders or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public List<ImageSectionHeader> getImageSectionHeaders()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
public List<ImageSectionHeader> getImageSectionHeaders() throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.SECTION_HEADER.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -141,15 +130,11 @@ public class DebugData {
|
||||
* Returns XData
|
||||
* When this returns a non-null list the OMAP_FROM_SRC should be
|
||||
* used for remapping global symbols
|
||||
* @return the imageSectionHeadersOrig or null if does not exist
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the imageSectionHeadersOrig or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
// TODO: just put a return of null Integer for now until figured out.
|
||||
public Integer getXData()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
public Integer getXData() throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -161,14 +146,10 @@ public class DebugData {
|
||||
* Returns PData
|
||||
* When this returns a non-null list the OMAP_FROM_SRC should be
|
||||
* used for remapping global symbols
|
||||
* @return the imageSectionHeadersOrig or null if does not exist
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the imageSectionHeadersOrig or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public List<ImageFunctionEntry> getPData()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
public List<ImageFunctionEntry> getPData() throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -180,14 +161,10 @@ public class DebugData {
|
||||
* Returns the {@link List}<{@link ImageSectionHeader}>.
|
||||
* When this returns a non-null list the OMAP_FROM_SRC should be
|
||||
* used for remapping global symbols
|
||||
* @return the imageSectionHeadersOrig or null if does not exist
|
||||
* @throws PdbException PdbException upon error in processing components
|
||||
* @return the imageSectionHeadersOrig or null if does not exist or problem parsing
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public List<ImageSectionHeader> getImageSectionHeadersOrig()
|
||||
throws CancelledException, PdbException, IOException {
|
||||
public List<ImageSectionHeader> getImageSectionHeadersOrig() throws CancelledException {
|
||||
int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue());
|
||||
if (streamNum == MsfStream.NIL_STREAM_NUMBER) {
|
||||
return null;
|
||||
@ -208,8 +185,7 @@ public class DebugData {
|
||||
* @throws PdbException upon error in processing components
|
||||
* @throws CancelledException upon user cancellation
|
||||
*/
|
||||
public void deserializeHeader(PdbByteReader reader)
|
||||
throws PdbException, CancelledException {
|
||||
public void deserializeHeader(PdbByteReader reader) throws PdbException, CancelledException {
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
int debugStreamNumber = reader.parseUnsignedShortVal();
|
||||
@ -230,8 +206,7 @@ public class DebugData {
|
||||
* inability to read required bytes
|
||||
*/
|
||||
@Deprecated
|
||||
public void deserialize()
|
||||
throws PdbException, CancelledException, IOException {
|
||||
public void deserialize() throws PdbException, CancelledException, IOException {
|
||||
if (debugStreams.isEmpty()) {
|
||||
throw new PdbException(
|
||||
"DebugData Header had not been deserialized at the appropriate time");
|
||||
@ -281,44 +256,67 @@ public class DebugData {
|
||||
}
|
||||
|
||||
private List<FramePointerOmissionRecord> deserializeFramePointerOmissionData(int streamNum)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
throws CancelledException {
|
||||
// TODO: check implementation for completeness.
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<FramePointerOmissionRecord> fpOmissionData = new ArrayList<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
FramePointerOmissionRecord framePointerOmissionRecord =
|
||||
new FramePointerOmissionRecord();
|
||||
framePointerOmissionRecord.parse(reader);
|
||||
fpOmissionData.add(framePointerOmissionRecord);
|
||||
try {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<FramePointerOmissionRecord> fpOmissionData = new ArrayList<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
FramePointerOmissionRecord framePointerOmissionRecord =
|
||||
new FramePointerOmissionRecord();
|
||||
framePointerOmissionRecord.parse(reader);
|
||||
fpOmissionData.add(framePointerOmissionRecord);
|
||||
}
|
||||
return fpOmissionData;
|
||||
}
|
||||
return fpOmissionData;
|
||||
catch (PdbException | IOException e) {
|
||||
PdbLog.message("Returning null Debug Frame Pointer Omission Data due to" +
|
||||
" problem during deserialization from stream" + streamNum + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SortedMap<Long, Long> deserializeOMap(int streamNum)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
SortedMap<Long, Long> omap = new TreeMap<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
long v1 = reader.parseUnsignedIntVal();
|
||||
long v2 = reader.parseUnsignedIntVal();
|
||||
omap.put(v1, v2);
|
||||
throws CancelledException {
|
||||
try {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
SortedMap<Long, Long> omap = new TreeMap<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
long v1 = reader.parseUnsignedIntVal();
|
||||
long v2 = reader.parseUnsignedIntVal();
|
||||
omap.put(v1, v2);
|
||||
}
|
||||
return omap;
|
||||
}
|
||||
return omap;
|
||||
catch (PdbException | IOException e) {
|
||||
PdbLog.message("Returning null Debug OMap due to" +
|
||||
" problem during deserialization from stream" + streamNum + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private List<ImageSectionHeader> deserializeSectionHeaders(int streamNum)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<ImageSectionHeader> sectionHeaders = new ArrayList<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
|
||||
imageSectionHeader.parse(reader);
|
||||
sectionHeaders.add(imageSectionHeader);
|
||||
throws CancelledException {
|
||||
try {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<ImageSectionHeader> sectionHeaders = new ArrayList<>();
|
||||
while (reader.hasMore()) {
|
||||
pdb.checkCancelled();
|
||||
ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb);
|
||||
imageSectionHeader.parse(reader);
|
||||
sectionHeaders.add(imageSectionHeader);
|
||||
}
|
||||
return sectionHeaders;
|
||||
}
|
||||
catch (PdbException | IOException e) {
|
||||
PdbLog.message("Returning null Debug Image Section Headers due to" +
|
||||
" problem during deserialization from stream" + streamNum + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
return sectionHeaders;
|
||||
}
|
||||
|
||||
// TODO: This is incomplete.
|
||||
@ -328,55 +326,63 @@ public class DebugData {
|
||||
*/
|
||||
// TODO: just put a return of null Integer for now until figured out.
|
||||
private Integer deserializeXData(int streamNum)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
int streamLength = reader.getLimit();
|
||||
//System.out.println(reader.dump(0x20));
|
||||
RvaVaDebugHeader header = new RvaVaDebugHeader();
|
||||
throws CancelledException {
|
||||
try {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
int streamLength = reader.getLimit();
|
||||
//System.out.println(reader.dump(0x20));
|
||||
RvaVaDebugHeader header = new RvaVaDebugHeader();
|
||||
|
||||
header.deserialize(reader);
|
||||
//System.out.println(header.dump());
|
||||
if (header.getHeaderVersion() != 1) {
|
||||
return null; // Silent... TODO: add logging event.
|
||||
header.deserialize(reader);
|
||||
//System.out.println(header.dump());
|
||||
if (header.getHeaderVersion() != 1) {
|
||||
return null; // Silent... TODO: add logging event.
|
||||
}
|
||||
long headerLength = header.getHeaderLength();
|
||||
long dataLength = header.getDataLength();
|
||||
if (headerLength + dataLength > streamLength) {
|
||||
throw new PdbException("Problem parsing Debug XData");
|
||||
}
|
||||
reader.setIndex((int) headerLength);
|
||||
//System.out.println(reader.dump());
|
||||
PdbByteReader xDataReader = reader.getSubPdbByteReader(reader.numRemaining());
|
||||
// TODO: This is a partial implementation. We need to figure out more to know
|
||||
// how to deal with it. The only API information regarding the XData is with
|
||||
// regard to processing PData when the "machine" is IA64 or AMD64. The interpretation
|
||||
// for these machines is not real clear (or a bit of work), and there is no other
|
||||
// interpretation available when the machine is different.
|
||||
}
|
||||
long headerLength = header.getHeaderLength();
|
||||
long dataLength = header.getDataLength();
|
||||
if (headerLength + dataLength > streamLength) {
|
||||
throw new PdbException("Problem parsing Debug XData");
|
||||
catch (PdbException | IOException e) {
|
||||
PdbLog.message("Returning null Debug XData" +
|
||||
" problem during deserialization from stream" + streamNum + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
reader.setIndex((int) headerLength);
|
||||
//System.out.println(reader.dump());
|
||||
PdbByteReader xDataReader = reader.getSubPdbByteReader(reader.numRemaining());
|
||||
// TODO: This is a partial implementation. We need to figure out more to know
|
||||
// how to deal with it. The only API information regarding the XData is with
|
||||
// regard to processing PData when the "machine" is IA64 or AMD64. The interpretation
|
||||
// for these machines is not real clear (or a bit of work), and there is no other
|
||||
// interpretation available when the machine is different.
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: This is incomplete.
|
||||
private List<ImageFunctionEntry> deserializePData(int streamNum)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<ImageFunctionEntry> myPData = new ArrayList<>();
|
||||
int streamLength = reader.getLimit();
|
||||
RvaVaDebugHeader header = new RvaVaDebugHeader();
|
||||
header.deserialize(reader);
|
||||
//System.out.println(header.dump());
|
||||
if (header.getHeaderVersion() != 1) {
|
||||
return myPData; // Silent... TODO: add logging event.
|
||||
}
|
||||
long headerLength = header.getHeaderLength();
|
||||
long dataLength = header.getDataLength();
|
||||
if (headerLength + dataLength > streamLength) {
|
||||
throw new PdbException("Problem parsing Debug PData");
|
||||
}
|
||||
reader.setIndex((int) headerLength);
|
||||
//System.out.println(reader.dump());
|
||||
// TODO: current partial implementation does not work (throws exception)
|
||||
// for ucrtbase.dll arm64. Need to look at this closer.
|
||||
throws CancelledException {
|
||||
try {
|
||||
PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum);
|
||||
List<ImageFunctionEntry> myPData = new ArrayList<>();
|
||||
int streamLength = reader.getLimit();
|
||||
RvaVaDebugHeader header = new RvaVaDebugHeader();
|
||||
header.deserialize(reader);
|
||||
//System.out.println(header.dump());
|
||||
if (header.getHeaderVersion() != 1) {
|
||||
return myPData; // Silent... TODO: add logging event.
|
||||
}
|
||||
long headerLength = header.getHeaderLength();
|
||||
long dataLength = header.getDataLength();
|
||||
if (headerLength + dataLength > streamLength) {
|
||||
throw new PdbException("Problem parsing Debug PData");
|
||||
}
|
||||
reader.setIndex((int) headerLength);
|
||||
//System.out.println(reader.dump());
|
||||
// TODO: current partial implementation does not work (throws exception)
|
||||
// for ucrtbase.dll arm64. Need to look at this closer.
|
||||
// while (reader.hasMore()) {
|
||||
// pdb.checkCancelled();
|
||||
// ImageFunctionEntry entry = new ImageFunctionEntry();
|
||||
@ -389,23 +395,30 @@ public class DebugData {
|
||||
// xDataReader.setIndex((int) index);
|
||||
// //System.out.println(xDataReader.dumpBytes(0x20));
|
||||
// }
|
||||
// TODO: More work possible. See XData processing and notes there. This is very
|
||||
// incomplete.
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo instanceof PdbNewDebugInfo) {
|
||||
//Processor target = pdb.getTargetProcessor();
|
||||
PdbNewDebugInfo dbi = (PdbNewDebugInfo) debugInfo;
|
||||
ImageFileMachine machine = dbi.getMachineType();
|
||||
switch (machine) {
|
||||
case IA64:
|
||||
break;
|
||||
case AMD64:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// TODO: More work possible. See XData processing and notes there. This is very
|
||||
// incomplete.
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
if (debugInfo instanceof PdbNewDebugInfo) {
|
||||
//Processor target = pdb.getTargetProcessor();
|
||||
PdbNewDebugInfo dbi = (PdbNewDebugInfo) debugInfo;
|
||||
ImageFileMachine machine = dbi.getMachineType();
|
||||
switch (machine) {
|
||||
case IA64:
|
||||
break;
|
||||
case AMD64:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return myPData;
|
||||
}
|
||||
return myPData;
|
||||
catch (PdbException | IOException e) {
|
||||
PdbLog.message("Returning null Debug PData due to" +
|
||||
" problem during deserialization from stream" + streamNum + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,8 +237,8 @@ public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types
|
||||
* to ensure that the types get scheduled... and detects whether any types were not yet
|
||||
* Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(RecordNumber)}) on all underlying
|
||||
* types to ensure that the types get scheduled... and detects whether any types were not yet
|
||||
* available so that this composite type is denoted as not done.
|
||||
* @param type the MS type of the function
|
||||
* @return {@code true} if all underlying types are already available
|
||||
|
@ -0,0 +1,238 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.ClassFieldMsAttributes;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ClassFieldAttributes {
|
||||
|
||||
private static final Map<ClassFieldAttributes, ClassFieldAttributes> map = new HashMap<>();
|
||||
|
||||
// These initializations use the map above, so it must be initialized first
|
||||
public static final ClassFieldAttributes UNKNOWN = get(Access.UNKNOWN, Property.UNKNOWN);
|
||||
public static final ClassFieldAttributes BLANK = get(Access.BLANK, Property.BLANK);
|
||||
|
||||
private final Access access;
|
||||
private final Property property;
|
||||
|
||||
public static ClassFieldAttributes get(Access access, Property property) {
|
||||
ClassFieldAttributes key = new ClassFieldAttributes(access, property);
|
||||
ClassFieldAttributes cfa = map.putIfAbsent(key, key);
|
||||
return (cfa != null) ? cfa : key;
|
||||
}
|
||||
|
||||
static ClassFieldAttributes convert(ClassFieldMsAttributes msAtts, Access defaultAccess) {
|
||||
Access myAccess = switch (msAtts.getAccess()) {
|
||||
case PUBLIC -> Access.PUBLIC;
|
||||
case PROTECTED -> Access.PROTECTED;
|
||||
case PRIVATE -> Access.PRIVATE;
|
||||
case BLANK -> defaultAccess;
|
||||
default -> Access.UNKNOWN;
|
||||
};
|
||||
Property myProperty = switch (msAtts.getProperty()) {
|
||||
case VIRTUAL -> Property.VIRTUAL;
|
||||
case STATIC -> Property.STATIC;
|
||||
case FRIEND -> Property.FRIEND;
|
||||
case BLANK -> Property.BLANK;
|
||||
default -> Property.UNKNOWN;
|
||||
};
|
||||
return get(myAccess, myProperty);
|
||||
}
|
||||
|
||||
private ClassFieldAttributes(Access access, Property property) {
|
||||
this.access = access;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
Access getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
void emit(StringBuilder builder) {
|
||||
StringBuilder myBuilder = new StringBuilder();
|
||||
if (access.getValue() > Access.BLANK.getValue()) {
|
||||
myBuilder.append(access);
|
||||
myBuilder.append(' ');
|
||||
}
|
||||
if (property.getValue() > Property.BLANK.getValue()) {
|
||||
myBuilder.append(property);
|
||||
myBuilder.append(' ');
|
||||
}
|
||||
builder.append(myBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
emit(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(access, property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ClassFieldAttributes other = (ClassFieldAttributes) obj;
|
||||
return access == other.access && property == other.property;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// TODO: Consider expanding these beyond C++.
|
||||
// See https://en.wikipedia.org/wiki/Access_modifiers
|
||||
// These could then be:
|
||||
// UNKNOWN("UNKNOWN_ACCESS ", -1),
|
||||
// OPEN("open", 0),
|
||||
// PUBLIC("internal", 1),
|
||||
// INTERNAL("internal", 2),
|
||||
// PACKAGE("package", 3),
|
||||
// PROTECTED("protected", 4),
|
||||
// PROTECTED_INTERNAL("protected internal", 5),
|
||||
// PRIVATE_PROTECTED("private protected", 6),
|
||||
// FILE("file", 7),
|
||||
// FILE_PRIVATE("fileprivate", 8),
|
||||
// PRIVATE("private", 9);
|
||||
static enum Access {
|
||||
UNKNOWN("UNKNOWN_ACCESS", -1),
|
||||
BLANK("", 0), // eliminated 20230524... using defaultAccess on some methods. Could renumber
|
||||
PUBLIC("public", 1),
|
||||
PROTECTED("protected", 2),
|
||||
PRIVATE("private", 3);
|
||||
|
||||
private static final Map<Integer, Access> BY_VALUE = new HashMap<>();
|
||||
static {
|
||||
for (Access val : values()) {
|
||||
BY_VALUE.put(val.value, val);
|
||||
}
|
||||
}
|
||||
private final String label;
|
||||
private final int value;
|
||||
|
||||
public String getString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Access fromValue(int val) {
|
||||
return BY_VALUE.getOrDefault(val, UNKNOWN);
|
||||
}
|
||||
|
||||
private Access(String label, int value) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two Access values, leaning toward more restrictive. UNKNOWN is only returned
|
||||
* if both are UNKNOWN.
|
||||
* @param other value to merge
|
||||
* @return the merged value
|
||||
*/
|
||||
public Access mergeRestrictive(Access other) {
|
||||
// No need to test for UNKNOWN as its value is on the permissive end.
|
||||
if (this.value > other.value) {
|
||||
return this;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two Access values, leaning toward more permissive. UNKNOWN is only returned
|
||||
* if both are UNKNOWN.
|
||||
* @param other value to merge
|
||||
* @return the merged value
|
||||
*/
|
||||
public Access mergePermissive(Access other) {
|
||||
if (this.value < other.value) {
|
||||
// Only need special test for UNKNOWN here, as its value is on the permissive end.
|
||||
if (this == UNKNOWN) {
|
||||
return other;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static enum Property {
|
||||
UNKNOWN("INVALID_PROPERTY", -1),
|
||||
BLANK("", 0), // means non-virtual, non-static, non-friend
|
||||
VIRTUAL("virtual", 1),
|
||||
STATIC("static", 2),
|
||||
FRIEND("friend", 3);
|
||||
// Also consider <intro>, <pure>, <intro,pure>. See MSFT.
|
||||
|
||||
private static final Map<Integer, Property> BY_VALUE = new HashMap<>();
|
||||
static {
|
||||
for (Property val : values()) {
|
||||
BY_VALUE.put(val.value, val);
|
||||
}
|
||||
}
|
||||
private final String label;
|
||||
private final int value;
|
||||
|
||||
public String getString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Property fromValue(int val) {
|
||||
return BY_VALUE.getOrDefault(val, UNKNOWN);
|
||||
}
|
||||
|
||||
private Property(String label, int value) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import ghidra.app.util.SymbolPath;
|
||||
import ghidra.app.util.bin.format.pdb.DefaultCompositeMember;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.*;
|
||||
import ghidra.app.util.pdb.pdbapplicator.ClassFieldAttributes.Access;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
@ -211,6 +212,9 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
throws PdbException, CancelledException {
|
||||
|
||||
AbstractCompositeMsType cType = (AbstractCompositeMsType) type;
|
||||
ClassFieldAttributes.Access defaultAccess =
|
||||
(type instanceof AbstractClassMsType) ? ClassFieldAttributes.Access.PRIVATE
|
||||
: ClassFieldAttributes.Access.PUBLIC;
|
||||
|
||||
for (AbstractMsType baseType : msBases) {
|
||||
applicator.checkCancelled();
|
||||
@ -222,13 +226,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
}
|
||||
|
||||
if (baseType instanceof AbstractBaseClassMsType baseClassType) {
|
||||
applyDirectBaseClass(baseClassType, myClassType);
|
||||
applyDirectBaseClass(baseClassType, myClassType, defaultAccess);
|
||||
}
|
||||
else if (baseType instanceof AbstractVirtualBaseClassMsType virtualBaseClassType) {
|
||||
applyDirectVirtualBaseClass(virtualBaseClassType, myClassType);
|
||||
applyDirectVirtualBaseClass(virtualBaseClassType, myClassType, defaultAccess);
|
||||
}
|
||||
else if (baseType instanceof AbstractIndirectVirtualBaseClassMsType indirectVirtualBaseClassType) {
|
||||
applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType);
|
||||
applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType,
|
||||
defaultAccess);
|
||||
}
|
||||
else {
|
||||
throw new AssertException(
|
||||
@ -237,7 +242,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
}
|
||||
}
|
||||
|
||||
private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType)
|
||||
private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType,
|
||||
Access defaultAccess)
|
||||
throws PdbException {
|
||||
CppCompositeType underlyingClassType =
|
||||
getUnderlyingClassType(base.getBaseClassRecordNumber());
|
||||
@ -246,11 +252,12 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
}
|
||||
ClassFieldMsAttributes atts = base.getAttributes();
|
||||
int offset = applicator.bigIntegerToInt(base.getOffset());
|
||||
myClassType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset);
|
||||
myClassType.addDirectBaseClass(underlyingClassType,
|
||||
ClassFieldAttributes.convert(atts, defaultAccess), offset);
|
||||
}
|
||||
|
||||
private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base,
|
||||
CppCompositeType myClassType) throws PdbException {
|
||||
CppCompositeType myClassType, Access defaultAccess) throws PdbException {
|
||||
CppCompositeType underlyingCt =
|
||||
getUnderlyingClassType(base.getBaseClassRecordNumber());
|
||||
if (underlyingCt == null) {
|
||||
@ -261,12 +268,13 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
ClassFieldMsAttributes atts = base.getAttributes();
|
||||
int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset());
|
||||
int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt());
|
||||
myClassType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts),
|
||||
myClassType.addDirectVirtualBaseClass(underlyingCt,
|
||||
ClassFieldAttributes.convert(atts, defaultAccess),
|
||||
basePointerOffset, vbtptr, offsetFromVbt);
|
||||
}
|
||||
|
||||
private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base,
|
||||
CppCompositeType myClassType) throws PdbException {
|
||||
CppCompositeType myClassType, Access defaultAccess) throws PdbException {
|
||||
CppCompositeType underlyingCt =
|
||||
getUnderlyingClassType(base.getBaseClassRecordNumber());
|
||||
if (underlyingCt == null) {
|
||||
@ -277,7 +285,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
ClassFieldMsAttributes atts = base.getAttributes();
|
||||
int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset());
|
||||
int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt());
|
||||
myClassType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts),
|
||||
myClassType.addIndirectVirtualBaseClass(underlyingCt,
|
||||
ClassFieldAttributes.convert(atts, defaultAccess),
|
||||
basePointerOffset, vbtptr, offsetFromVbt);
|
||||
}
|
||||
|
||||
@ -313,49 +322,18 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
private static CppCompositeType.ClassFieldAttributes convertAttributes(
|
||||
ClassFieldMsAttributes atts) {
|
||||
CppCompositeType.Access myAccess;
|
||||
switch (atts.getAccess()) {
|
||||
case PUBLIC:
|
||||
myAccess = CppCompositeType.Access.PUBLIC;
|
||||
break;
|
||||
case PROTECTED:
|
||||
myAccess = CppCompositeType.Access.PROTECTED;
|
||||
break;
|
||||
case PRIVATE:
|
||||
myAccess = CppCompositeType.Access.PRIVATE;
|
||||
break;
|
||||
default:
|
||||
myAccess = CppCompositeType.Access.BLANK;
|
||||
break;
|
||||
}
|
||||
CppCompositeType.Property myProperty;
|
||||
switch (atts.getProperty()) {
|
||||
case VIRTUAL:
|
||||
myProperty = CppCompositeType.Property.VIRTUAL;
|
||||
break;
|
||||
case STATIC:
|
||||
myProperty = CppCompositeType.Property.STATIC;
|
||||
break;
|
||||
case FRIEND:
|
||||
myProperty = CppCompositeType.Property.FRIEND;
|
||||
break;
|
||||
default:
|
||||
myProperty = CppCompositeType.Property.BLANK;
|
||||
break;
|
||||
}
|
||||
return new CppCompositeType.ClassFieldAttributes(myAccess, myProperty);
|
||||
}
|
||||
|
||||
private void addMembers(Composite composite, CppCompositeType myClassType,
|
||||
List<AbstractMemberMsType> msMembers, AbstractCompositeMsType type,
|
||||
List<DefaultPdbUniversalMember> myMembers)
|
||||
throws CancelledException, PdbException {
|
||||
ClassFieldAttributes.Access defaultAccess =
|
||||
(type instanceof AbstractClassMsType) ? ClassFieldAttributes.Access.PRIVATE
|
||||
: ClassFieldAttributes.Access.PUBLIC;
|
||||
for (int index = 0; index < msMembers.size(); index++) {
|
||||
applicator.checkCancelled();
|
||||
AbstractMemberMsType memberType = msMembers.get(index);
|
||||
DefaultPdbUniversalMember member = getNonStaticMember(composite, memberType, index);
|
||||
DefaultPdbUniversalMember member =
|
||||
getNonStaticMember(composite, defaultAccess, memberType, index);
|
||||
DataType dt = member.getDataType().getDataType();
|
||||
myMembers.add(member);
|
||||
myClassType.addMember(member.getName(), dt, member.isZeroLengthArray(),
|
||||
@ -386,8 +364,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types
|
||||
* to ensure that the types get scheduled... and detects whether any types were not yet
|
||||
* Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(RecordNumber)}) on all underlying
|
||||
* types to ensure that the types get scheduled... and detects whether any types were not yet
|
||||
* available so that this composite type is denoted as not done.
|
||||
* @param lists the lists of all underlying types
|
||||
* @return {@code true} if all underlying types are already available
|
||||
@ -461,14 +439,15 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
throw new PdbException("Unhandled type: " + method.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
for (AbstractNestedTypeMsType nested : lists.nestedTypes()) {
|
||||
applicator.checkCancelled();
|
||||
RecordNumber recordNumber = nested.getNestedTypeDefinitionRecordNumber();
|
||||
DataType dt = applicator.getDataTypeOrSchedule(recordNumber);
|
||||
if (dt == null) {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
// Might cause problems, so remove until understood and possibly needed
|
||||
// for (AbstractNestedTypeMsType nested : lists.nestedTypes()) {
|
||||
// applicator.checkCancelled();
|
||||
// RecordNumber recordNumber = nested.getNestedTypeDefinitionRecordNumber();
|
||||
// DataType dt = applicator.getDataTypeOrSchedule(recordNumber);
|
||||
// if (dt == null) {
|
||||
// done = false;
|
||||
// }
|
||||
// }
|
||||
for (AbstractMemberMsType nonstaticMember : lists.nonstaticMembers()) {
|
||||
applicator.checkCancelled();
|
||||
RecordNumber recordNumber = nonstaticMember.getFieldTypeRecordNumber();
|
||||
@ -509,7 +488,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
}
|
||||
|
||||
private DefaultPdbUniversalMember getNonStaticMember(Composite container,
|
||||
AbstractMemberMsType memberMsType, int ordinal)
|
||||
Access defaultAccess, AbstractMemberMsType memberMsType, int ordinal)
|
||||
throws CancelledException, PdbException {
|
||||
|
||||
MsTypeApplier applier = applicator.getTypeApplier(memberMsType);
|
||||
@ -546,7 +525,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
||||
arrayApplier.isFlexibleArray(fieldType));
|
||||
|
||||
DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(memberName, fieldDataType,
|
||||
isZeroLengthArray, offset, convertAttributes(memberAttributes), memberComment);
|
||||
isZeroLengthArray, offset,
|
||||
ClassFieldAttributes.convert(memberAttributes, defaultAccess), memberComment);
|
||||
return member;
|
||||
}
|
||||
|
||||
|
@ -252,8 +252,7 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
public void addVirtualFunctionTablePointer(String name, DataType dataType, int offset) {
|
||||
Member newMember = new Member(name, dataType, false,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset);
|
||||
Member newMember = new Member(name, dataType, false, ClassFieldAttributes.UNKNOWN, offset);
|
||||
layoutVftPtrMembers.add(newMember);
|
||||
}
|
||||
|
||||
@ -275,14 +274,14 @@ public class CppCompositeType {
|
||||
|
||||
public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset,
|
||||
String comment) {
|
||||
addMember(memberName, dataType, isFlexibleArray,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment);
|
||||
addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset,
|
||||
comment);
|
||||
}
|
||||
|
||||
public void addMember(String memberName, DataType dataType, boolean isFlexibleArray,
|
||||
int offset) {
|
||||
addMember(memberName, dataType, isFlexibleArray,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null);
|
||||
addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset,
|
||||
null);
|
||||
}
|
||||
|
||||
public void addMember(String memberName, DataType dataType, boolean isFlexibleArray,
|
||||
@ -314,14 +313,14 @@ public class CppCompositeType {
|
||||
*/
|
||||
public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray,
|
||||
int offset, String comment) {
|
||||
insertMember(memberName, dataType, isFlexibleArray,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment);
|
||||
insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset,
|
||||
comment);
|
||||
}
|
||||
|
||||
public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray,
|
||||
int offset) {
|
||||
insertMember(memberName, dataType, isFlexibleArray,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null);
|
||||
insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset,
|
||||
null);
|
||||
}
|
||||
|
||||
public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray,
|
||||
@ -351,8 +350,7 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
public void addStaticMember(String memberName, DataType dataType) {
|
||||
addStaticMember(memberName, dataType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN));
|
||||
addStaticMember(memberName, dataType, ClassFieldAttributes.UNKNOWN);
|
||||
}
|
||||
|
||||
public void addStaticMember(String memberName, DataType dataType,
|
||||
@ -379,8 +377,7 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
public void addSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException {
|
||||
addSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN));
|
||||
addSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN);
|
||||
}
|
||||
|
||||
public void addSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -390,8 +387,7 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
public void addDirectSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException {
|
||||
addDirectSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN));
|
||||
addDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN);
|
||||
}
|
||||
|
||||
public void addDirectSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -401,8 +397,7 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException {
|
||||
addVirtualSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN));
|
||||
addVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN);
|
||||
}
|
||||
|
||||
public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -413,8 +408,7 @@ public class CppCompositeType {
|
||||
|
||||
public void insertSyntacticBaseClass(CppCompositeType baseClassType, int ordinal)
|
||||
throws PdbException {
|
||||
insertSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal);
|
||||
insertSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal);
|
||||
}
|
||||
|
||||
public void insertSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -429,8 +423,7 @@ public class CppCompositeType {
|
||||
|
||||
public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, int ordinal)
|
||||
throws PdbException {
|
||||
insertDirectSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal);
|
||||
insertDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal);
|
||||
}
|
||||
|
||||
public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -445,8 +438,7 @@ public class CppCompositeType {
|
||||
|
||||
public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, int ordinal)
|
||||
throws PdbException {
|
||||
insertVirtualSyntacticBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal);
|
||||
insertVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal);
|
||||
}
|
||||
|
||||
public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType,
|
||||
@ -461,8 +453,7 @@ public class CppCompositeType {
|
||||
|
||||
//==============================================================================================
|
||||
public void addDirectBaseClass(CppCompositeType baseClassType, int offset) throws PdbException {
|
||||
addDirectBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset);
|
||||
addDirectBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, offset);
|
||||
}
|
||||
|
||||
public void addDirectBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes,
|
||||
@ -491,9 +482,8 @@ public class CppCompositeType {
|
||||
//
|
||||
public void addDirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset,
|
||||
DataType vbptr, int offsetFromVbt) throws PdbException {
|
||||
addDirectVirtualBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr,
|
||||
offsetFromVbt);
|
||||
addDirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset,
|
||||
vbptr, offsetFromVbt);
|
||||
}
|
||||
|
||||
public void addDirectVirtualBaseClass(CppCompositeType baseClassType,
|
||||
@ -524,9 +514,8 @@ public class CppCompositeType {
|
||||
//
|
||||
public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset,
|
||||
DataType vbptr, int offsetFromVbt) throws PdbException {
|
||||
addIndirectVirtualBaseClass(baseClassType,
|
||||
new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr,
|
||||
offsetFromVbt);
|
||||
addIndirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset,
|
||||
vbptr, offsetFromVbt);
|
||||
}
|
||||
|
||||
public void addIndirectVirtualBaseClass(CppCompositeType baseClassType,
|
||||
@ -947,7 +936,8 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
boolean allVbtFound = true;
|
||||
for (Entry<Integer, PlaceholderVirtualBaseTable> tableEntry : placeholderVirtualBaseTables.entrySet()) {
|
||||
for (Entry<Integer, PlaceholderVirtualBaseTable> tableEntry : placeholderVirtualBaseTables
|
||||
.entrySet()) {
|
||||
int vbtptrOffset = tableEntry.getKey();
|
||||
PlaceholderVirtualBaseTable table = tableEntry.getValue();
|
||||
if (!table.validateOffset()) {
|
||||
@ -1736,7 +1726,8 @@ public class CppCompositeType {
|
||||
}
|
||||
|
||||
PlaceholderVirtualBaseTableEntry getEntryByName(String nameParam) {
|
||||
for (Entry<Integer, PlaceholderVirtualBaseTableEntry> entry : entriesByIndex.entrySet()) {
|
||||
for (Entry<Integer, PlaceholderVirtualBaseTableEntry> entry : entriesByIndex
|
||||
.entrySet()) {
|
||||
if (nameParam.equals(
|
||||
entry.getValue().getVirtualBaseClass().getBaseClassType().getName())) {
|
||||
return entry.getValue();
|
||||
@ -1749,36 +1740,6 @@ public class CppCompositeType {
|
||||
//----------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static class ClassFieldAttributes {
|
||||
Access access;
|
||||
Property property;
|
||||
|
||||
ClassFieldAttributes(Access access, Property property) {
|
||||
this.access = access;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
private Access getAccess() {
|
||||
return access;
|
||||
}
|
||||
|
||||
private Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (access.getValue() > Access.BLANK.getValue()) {
|
||||
builder.append(access);
|
||||
}
|
||||
if (property.equals(Property.VIRTUAL)) {
|
||||
builder.append(property);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static enum Type {
|
||||
UNKNOWN("UNKNOWN_TYPE", -1),
|
||||
@ -1822,91 +1783,4 @@ public class CppCompositeType {
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static enum Access {
|
||||
UNKNOWN("UNKNOWN_ACCESS ", -1),
|
||||
BLANK("", 0),
|
||||
PUBLIC("public", 1),
|
||||
PROTECTED("protected", 2),
|
||||
PRIVATE("private", 3);
|
||||
|
||||
private static final Map<Integer, Access> BY_VALUE = new HashMap<>();
|
||||
static {
|
||||
for (Access val : values()) {
|
||||
BY_VALUE.put(val.value, val);
|
||||
}
|
||||
}
|
||||
private final String label;
|
||||
private final int value;
|
||||
|
||||
public String getString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (label.length() != 0) {
|
||||
return label + " ";
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Access fromValue(int val) {
|
||||
return BY_VALUE.getOrDefault(val, UNKNOWN);
|
||||
}
|
||||
|
||||
private Access(String label, int value) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static enum Property {
|
||||
UNKNOWN("INVALID_PROPERTY", -1),
|
||||
BLANK("", 0),
|
||||
VIRTUAL("virtual ", 1),
|
||||
STATIC("static ", 2),
|
||||
FRIEND("friend ", 3);
|
||||
// Also consider <intro>, <pure>, <intro,pure>. See MSFT.
|
||||
|
||||
private static final Map<Integer, Property> BY_VALUE = new HashMap<>();
|
||||
static {
|
||||
for (Property val : values()) {
|
||||
BY_VALUE.put(val.value, val);
|
||||
}
|
||||
}
|
||||
private final String label;
|
||||
private final int value;
|
||||
|
||||
public String getString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (label.length() != 0) {
|
||||
return label + " ";
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Property fromValue(int val) {
|
||||
return BY_VALUE.getOrDefault(val, UNKNOWN);
|
||||
}
|
||||
|
||||
private Property(String label, int value) {
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
@ -197,12 +196,10 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||
* @param logParam the MessageLog to which to output messages
|
||||
* @throws PdbException if there was a problem processing the data
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
public void applyTo(Program programParam, DataTypeManager dataTypeManagerParam,
|
||||
Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam,
|
||||
MessageLog logParam) throws PdbException, CancelledException, IOException {
|
||||
MessageLog logParam) throws PdbException, CancelledException {
|
||||
|
||||
// FIXME: should not support use of DataTypeManager-only since it will not have the correct
|
||||
// data organization if it corresponds to a data type archive. Need to evaluate archive
|
||||
@ -420,12 +417,10 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||
* Initializes helper classes and data items used for applying the PDB
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws PdbException upon error in processing components
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
private void initializeApplyTo(Program programParam, DataTypeManager dataTypeManagerParam,
|
||||
Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam,
|
||||
MessageLog logParam) throws PdbException, CancelledException, IOException {
|
||||
MessageLog logParam) throws PdbException, CancelledException {
|
||||
|
||||
validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam,
|
||||
applicatorOptionsParam, logParam);
|
||||
@ -846,7 +841,7 @@ public class DefaultPdbApplicator implements PdbApplicator {
|
||||
if (dt != null) {
|
||||
return dt;
|
||||
}
|
||||
multiphaseResolver.scheduleTodo(recordNumber);
|
||||
multiphaseResolver.scheduleTodo(mappedNumber);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.*;
|
||||
import ghidra.app.util.pdb.pdbapplicator.CppCompositeType.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
@ -30,9 +29,6 @@ public class DefaultPdbUniversalMember extends PdbMember {
|
||||
private ClassFieldAttributes attributes;
|
||||
private boolean isZeroLengthArray;
|
||||
|
||||
private static final ClassFieldAttributes blankAtttributes =
|
||||
new ClassFieldAttributes(Access.BLANK, Property.BLANK);
|
||||
|
||||
/**
|
||||
* Default PDB member construction
|
||||
* @param name member field name. For bitfields this also conveys the bit-size
|
||||
@ -43,7 +39,7 @@ public class DefaultPdbUniversalMember extends PdbMember {
|
||||
DefaultPdbUniversalMember(String name, DataType dataType, int offset) {
|
||||
super(name, dataType.getName(), offset, null);
|
||||
this.dataType = dataType;
|
||||
this.attributes = blankAtttributes;
|
||||
this.attributes = ClassFieldAttributes.BLANK;
|
||||
this.isZeroLengthArray = false;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -16,20 +16,9 @@
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
/**
|
||||
* Abstract class representing the applier for a specific PDB_ID type. The
|
||||
* {@link #apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)} method
|
||||
* creates an associated {@link DataType}, if applicable, The latter of these forces the
|
||||
* creation of the defined type when and forward reference type is not appropriate for the
|
||||
* consumer. Note that this should only be used when sanctioned and not on a whim. Currently,
|
||||
* such situations include when ghidra needs a defined type for the underlying type of an array,
|
||||
* when used as a base class of a class or when needed as a member of another class/composite.
|
||||
* Methods associated with the {@link MsTypeApplier} or derived class will
|
||||
* make fields available to the user, first by trying to get them from the {@link DataType},
|
||||
* otherwise getting them from the {@link AbstractMsType} argument.
|
||||
* Abstract class representing the applier for a specific PDB_ID type.
|
||||
*/
|
||||
public abstract class MsTypeApplier {
|
||||
|
||||
|
@ -59,6 +59,8 @@ public class MultiphaseDataTypeResolver {
|
||||
if (applicator.getDataType(recordNumber) != null) {
|
||||
return;
|
||||
}
|
||||
// Location where one might do conditional: todoStack.setDebug(true)
|
||||
|
||||
// If not in the map, it will also not be in the todo or resolve stacks, as both
|
||||
// should be empty at this point.
|
||||
scheduleTodo(recordNumber);
|
||||
@ -81,6 +83,7 @@ public class MultiphaseDataTypeResolver {
|
||||
resolveStack.push(recordToProcess);
|
||||
}
|
||||
}
|
||||
// If set true above, location where one might do conditional: todoStack.setDebug(false)
|
||||
|
||||
// Pop top of stack and work on it.
|
||||
while ((recordToProcess = resolveStack.pop()) != null) {
|
||||
@ -134,13 +137,21 @@ public class MultiphaseDataTypeResolver {
|
||||
private RecordNode(RecordNumber recordNumber) {
|
||||
this.recordNumber = recordNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return recordNumber.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static final int TO_STRING_LIMIT = 500;
|
||||
static final RecordNumber HEAD = RecordNumber.typeRecordNumber(-1);
|
||||
static final RecordNumber TAIL = RecordNumber.typeRecordNumber(-2);
|
||||
Map<RecordNumber, RecordNode> map;
|
||||
RecordNode head;
|
||||
RecordNode tail;
|
||||
boolean debug;
|
||||
StringBuilder debugBuilder;
|
||||
|
||||
/**
|
||||
* Constructor for new record stack
|
||||
@ -156,6 +167,14 @@ public class MultiphaseDataTypeResolver {
|
||||
tail.prev = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or clear developer debug
|
||||
* @param debug {@code true} to turn on; {@code false} to turn off
|
||||
*/
|
||||
void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if number number exists on stack
|
||||
* @param recordNumber the record number to check
|
||||
@ -177,6 +196,14 @@ public class MultiphaseDataTypeResolver {
|
||||
}
|
||||
if (node == null) {
|
||||
node = new RecordNode(recordNumber);
|
||||
if (debug) {
|
||||
if (map.isEmpty()) {
|
||||
debugBuilder = new StringBuilder();
|
||||
}
|
||||
debugBuilder.append("push:");
|
||||
debugBuilder.append(recordNumber);
|
||||
debugBuilder.append("\n");
|
||||
}
|
||||
map.put(recordNumber, node);
|
||||
}
|
||||
else { // already exists in non-top-of-stack position
|
||||
@ -208,6 +235,14 @@ public class MultiphaseDataTypeResolver {
|
||||
}
|
||||
removeNodeLinkage(node);
|
||||
map.remove(node.recordNumber);
|
||||
if (debug) {
|
||||
debugBuilder.append(" pop:");
|
||||
debugBuilder.append(node.recordNumber);
|
||||
debugBuilder.append("\n");
|
||||
if (map.isEmpty()) {
|
||||
System.out.println(debugBuilder.toString());
|
||||
}
|
||||
}
|
||||
return node.recordNumber;
|
||||
}
|
||||
|
||||
@ -249,6 +284,27 @@ public class MultiphaseDataTypeResolver {
|
||||
node.next = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
int count = 0;
|
||||
RecordNode node = head.prev;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append('[');
|
||||
while (node != tail && count < TO_STRING_LIMIT) {
|
||||
if (count != 0) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append(node);
|
||||
node = node.prev;
|
||||
count++;
|
||||
}
|
||||
if (node != tail) {
|
||||
builder.append("...");
|
||||
}
|
||||
builder.append(']');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
@ -36,7 +35,7 @@ abstract class PdbAddressCalculator {
|
||||
private int maxSegment;
|
||||
|
||||
static PdbAddressCalculator chooseAddressCalculator(PdbApplicator applicator, Address imageBase)
|
||||
throws CancelledException, PdbException, IOException {
|
||||
throws CancelledException, PdbException {
|
||||
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
PdbDebugInfo dbi = pdb.getDebugInfo();
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.pdb.pdbapplicator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
@ -80,11 +79,9 @@ public class PdbAddressManager {
|
||||
* @param imageBase Address from which all other addresses are based.
|
||||
* @throws PdbException If Program is null;
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
PdbAddressManager(DefaultPdbApplicator applicator, Address imageBase)
|
||||
throws PdbException, CancelledException, IOException {
|
||||
throws PdbException, CancelledException {
|
||||
Objects.requireNonNull(applicator, "applicator may not be null");
|
||||
Objects.requireNonNull(imageBase, "imageBase may not be null");
|
||||
this.applicator = applicator;
|
||||
@ -342,11 +339,8 @@ public class PdbAddressManager {
|
||||
/**
|
||||
* Determines memory blocks
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws PdbException upon error in processing components
|
||||
* @throws IOException on file seek or read, invalid parameters, bad file configuration, or
|
||||
* inability to read required bytes
|
||||
*/
|
||||
private void determineMemoryBlocks() throws CancelledException, PdbException, IOException {
|
||||
private void determineMemoryBlocks() throws CancelledException {
|
||||
AbstractPdb pdb = applicator.getPdb();
|
||||
PdbDebugInfo debugInfo = pdb.getDebugInfo();
|
||||
segmentMapList = debugInfo.getSegmentMapList();
|
||||
|
@ -36,12 +36,12 @@ import ghidra.util.task.TaskMonitor;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest {
|
||||
public class ConflictHandler2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
private ProgramDB program;
|
||||
private DataTypeManagerDB dtm;
|
||||
private int transactionID;
|
||||
|
||||
public ConflictHandlerTest2() {
|
||||
public ConflictHandler2Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest {
|
||||
}
|
||||
try {
|
||||
if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members,
|
||||
msg -> Msg.warn(ConflictHandlerTest2.class, msg), monitor)) {
|
||||
msg -> Msg.warn(ConflictHandler2Test.class, msg), monitor)) {
|
||||
((Structure) composite).deleteAll();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user