diff --git a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html
index c8e56b3a57..98bad04149 100644
--- a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html
+++ b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html
@@ -27,6 +27,9 @@
Data Types. Corrected segmented 32-bit pointer datatype address generation for 16:16 x86 far pointers. (GP-534, Issue #2548)
Decompiler. Fixed Decompiler issue where, when a function name extends beyond the line limit, an end-of-line comment could wrap around to additional lines without including additional // comment indicators. (GP-473)
Decompiler. Corrected an exception that could occur when attempting to edit function signature from the Decompiler. (GP-597, Issue #2601)
+ Demangler. Changed return type applied to constructors by Demangler from void to Undefined, allowing the Decompiler to determine the type. (GP-790)
+ DWARF. Improved handling of empty DWARF compile units. (GP-743)
+ DWARF. Improved handling of DWARF function signatures when parameter info contains unsupported location opcodes or failed to resolve datatypes. (GP-794)
Eclipse Integration. When installing the SleighEditor into Eclipse, the plugin will now show up under the Ghidra category. Previously the Group Items by Category option had to be turned off before the SleighEditor would appear as a visible entry. (GP-564)
Eclipse Integration. Fixed an issue with Eclipse PyDev breakpoints not catching. (GP-668, Issue #2713)
Eclipse Integration. Fixed an Eclipse GhidraDev exception that occurred when creating a new Ghidra scripting project if a ~/ghidra_scripts directory did not exist. (GP-669)
@@ -44,6 +47,7 @@
Importer:Mach-O. Fixed an exception that occurred when importing Mach-O files that define zero LC_BUILD_VERSION tool entries. (GP-702, Issue #2192)
PDB. Fixed createPdbXmlFiles.bat to permit spaces in the path name of Ghidra installation folder and the batch argument name. (GP-575, Issue #2167)
PDB. Fixed PDB Universal analyzer to set the run-once flag when finished. (GP-724)
+ PDB. Changed return type applied to constructors by PDB Universal from void to Undefined, allowing the Decompiler to determine the type. (GP-791)
Processors. Added missing RFE instruction in MIPS up to version R3000. (GP-33, Issue #1766)
Processors. ARM instruction VMUL now decodes correctly. (GP-627, Issue #2677)
Processors. Added missing CFINV instruction to AARCH64 processor specification and added definitions for locals in neon instructions. (GP-655, Issue #2710)
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
index 786da2b95c..5cdfc55a1c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
@@ -15,10 +15,11 @@
*/
package ghidra.app.util.bin.format.dwarf4.next;
-import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
+import java.io.IOException;
+
import ghidra.app.cmd.comments.AppendCommentCmd;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
import ghidra.app.util.bin.format.dwarf4.*;
@@ -202,26 +203,26 @@ public class DWARFFunctionImporter {
return;
}
- DWARFFunction function = new DWARFFunction(prog.getName(diea));
- function.namespace = function.dni.getParentNamespace(currentProgram);
+ DWARFFunction dfunc = new DWARFFunction(prog.getName(diea));
+ dfunc.namespace = dfunc.dni.getParentNamespace(currentProgram);
Number lowPC = diea.getLowPC(0);
- function.address = toAddr(lowPC);
- function.highAddress =
+ dfunc.address = toAddr(lowPC);
+ dfunc.highAddress =
diea.hasAttribute(DWARFAttribute.DW_AT_high_pc) ? toAddr(diea.getHighPC()) : null;
- String previousFunctionProcessed = functionsProcessed.get(function.address);
+ String previousFunctionProcessed = functionsProcessed.get(dfunc.address);
if (previousFunctionProcessed != null) {
// Msg.info(this, "Duplicate function defintion found for " + dni.getCategoryPath() +
// " at " + function.address + " in DIE " + diea.getHexOffset() + ", skipping");
markAllChildrenAsProcessed(diea.getHeadFragment());
return;
}
- functionsProcessed.put(function.address,
- function.dni.getNamespacePath() + " DIE: " + diea.getHexOffset());
+ functionsProcessed.put(dfunc.address,
+ dfunc.dni.getNamespacePath() + " DIE: " + diea.getHexOffset());
// Check if the function is an external function
- function.isExternal = diea.getBool(DWARFAttribute.DW_AT_external, false);
+ dfunc.isExternal = diea.getBool(DWARFAttribute.DW_AT_external, false);
// Retrieve the frame base if it exists
DWARFLocation frameLoc = null;
@@ -229,9 +230,9 @@ public class DWARFFunctionImporter {
List frameBase = diea.getAsLocation(DWARFAttribute.DW_AT_frame_base);
// get the framebase register, find where the frame is finally set
// up.
- frameLoc = getTopLocation(frameBase, function.address.getOffset());
+ frameLoc = getTopLocation(frameBase, dfunc.address.getOffset());
if (frameLoc != null) {
- function.frameBase = (int) diea.evaluateLocation(frameLoc);
+ dfunc.frameBase = (int) diea.evaluateLocation(frameLoc);
}
}
@@ -245,26 +246,134 @@ public class DWARFFunctionImporter {
// function passing a pointer to the callee function where the object is
// then operated on.
DIEAggregate typeRef = diea.getTypeRef();
- if (typeRef != null) {
- function.retval = new DWARFVariable();
- function.retval.type = dwarfDTM.getDataType(typeRef, dwarfDTM.getVoidType());
- }
+ DataType formalReturnType = (typeRef != null)
+ ? dwarfDTM.getDataType(typeRef, DataType.DEFAULT)
+ : dwarfDTM.getVoidType();
+ dfunc.retval = new DWARFVariable();
+ dfunc.retval.type = formalReturnType;
+
+ boolean formalParamsOnly = false;
+ boolean skipFuncSignature = false;
+ List formalParams = new ArrayList<>();
for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren(
DWARFTag.DW_TAG_formal_parameter)) {
DIEAggregate childDIEA = prog.getAggregate(childEntry);
- DWARFVariable var = processVariable(childDIEA, function, null, -1);
- if (var != null) {
- function.params.add(var);
+ Parameter formalParam = createFormalParameter(childDIEA);
+ if (formalParam == null) {
+ skipFuncSignature = true;
+ break;
+ }
+ formalParams.add(formalParam);
+
+ if (!formalParamsOnly) {
+ DWARFVariable var = processVariable(childDIEA, dfunc, null, -1);
+ if (var == null) {
+ // we had an error, can't rely on detailed param data, fallback to
+ // formal params
+ formalParamsOnly = true;
+ dfunc.params.clear();
+ }
+ else {
+ dfunc.params.add(var);
+ }
}
}
- function.varArg =
+ dfunc.varArg =
!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty();
- processFuncChildren(diea, function);
- outputFunction(function, diea);
+ processFuncChildren(diea, dfunc);
+ Function gfunc = createFunction(dfunc, diea);
+ if (gfunc != null) {
+
+ if (formalParams.isEmpty() && dfunc.localVarErrors) {
+ // if there were no defined parameters and we had problems decoding local variables,
+ // don't force the method to have an empty param signature because there are other
+ // issues afoot.
+ skipFuncSignature = true;
+ }
+
+ if (skipFuncSignature) {
+ Msg.error(this,
+ "Failed to get function signature information, leaving undefined: " +
+ gfunc.getName() + "@" + gfunc.getEntryPoint());
+ Msg.debug(this, "DIE info: " + diea.toString());
+ return;
+ }
+
+ if (formalParamsOnly) {
+ updateFunctionSignatureWithFormalParams(gfunc, formalParams,
+ formalReturnType, dfunc.varArg, diea);
+ }
+ else {
+ updateFunctionSignatureWithDetailParams(gfunc, dfunc, diea);
+ }
+ }
+
+ }
+
+ private void updateFunctionSignatureWithFormalParams(Function gfunc, List params,
+ DataType returnType, boolean varArgs, DIEAggregate diea) {
+ try {
+ ReturnParameterImpl returnVar = new ReturnParameterImpl(returnType, currentProgram);
+ try {
+ gfunc.setVarArgs(varArgs);
+ gfunc.updateFunction(null, returnVar, params,
+ FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.IMPORTED);
+ }
+ catch (DuplicateNameException e) {
+ // try again after adjusting param names
+ setUniqueParameterNames(gfunc, params);
+ gfunc.updateFunction(null, returnVar, params,
+ FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.IMPORTED);
+ }
+ }
+ catch (InvalidInputException | DuplicateNameException e) {
+ Msg.error(this,
+ "Error updating function " + gfunc.getName() + " with formal params at " +
+ gfunc.getEntryPoint().toString() + ": " + e.getMessage());
+ Msg.error(this, "DIE info: " + diea.toString());
+ }
+ }
+
+ private void updateFunctionSignatureWithDetailParams(Function gfunc, DWARFFunction dfunc,
+ DIEAggregate diea) {
+ try {
+ CompilerSpec compilerSpec = currentProgram.getCompilerSpec();
+ PrototypeModel convention = null;
+ Variable returnVariable;
+ List params = new ArrayList<>();
+
+ returnVariable = buildReturnVariable(dfunc.retval);
+ for (int i = 0; i < dfunc.params.size(); ++i) {
+ Parameter curparam = buildParameter(gfunc, i, dfunc.params.get(i), diea);
+ params.add(curparam);
+ if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) {
+ convention = compilerSpec.matchConvention(GenericCallingConvention.thiscall);
+ }
+ }
+
+ for (int i = 0; i < dfunc.local.size(); ++i) {
+ commitLocal(gfunc, dfunc.local.get(i));
+ }
+
+ if (dfunc.retval != null || params.size() > 0) {
+ // Add the function signature definition into the data type manager
+// TODO: createFunctionDefinition(dfunc, infopath);
+
+ // NOTE: Storage is computed above for the purpose of identifying
+ // a best fit calling convention. The commitPrototype method currently
+ // always employs dynamic storage.
+ commitPrototype(gfunc, returnVariable, params, convention);
+ gfunc.setVarArgs(dfunc.varArg);
+ }
+ }
+ catch (InvalidInputException | DuplicateNameException iie) {
+ Msg.error(this, "Error updating function " + dfunc.dni.getName() + " at " +
+ dfunc.address.toString() + ": " + iie.getMessage());
+ }
}
private void processFuncChildren(DIEAggregate diea, DWARFFunction dfunc)
@@ -305,6 +414,19 @@ public class DWARFFunctionImporter {
}
}
+ private Parameter createFormalParameter(DIEAggregate diea) {
+ String name = diea.getString(DWARFAttribute.DW_AT_name, null);
+ DataType dt = dwarfDTM.getDataType(diea.getTypeRef(), dwarfDTM.getVoidType());
+
+ try {
+ return new ParameterImpl(name, dt, currentProgram);
+ }
+ catch (InvalidInputException e) {
+ Msg.debug(this, "Failed to create parameter for " + diea.toString());
+ }
+ return null;
+ }
+
/**
* Creates a new {@link DWARFVariable} from the specified {@link DIEAggregate DIEA} and
* as a child of the specified function (if not null).
@@ -349,6 +471,9 @@ public class DWARFFunctionImporter {
DWARFLocation topLocation = getTopLocation(locList, funcAddr);
if (topLocation == null) {
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
@@ -368,12 +493,18 @@ public class DWARFFunctionImporter {
catch (DWARFExpressionException | UnsupportedOperationException
| IndexOutOfBoundsException ex) {
importSummary.exprReadError++;
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
if (exprEvaluator.isDwarfStackValue()) {
importSummary.varDWARFExpressionValue++;
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
else if (exprEvaluator.useUnknownRegister() && exprEvaluator.isRegisterLocation()) {
@@ -386,6 +517,9 @@ public class DWARFFunctionImporter {
}
else if (exprEvaluator.useUnknownRegister()) {
importSummary.varDynamicRegisterError++;
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
else if (exprEvaluator.isStackRelative()) {
@@ -420,6 +554,9 @@ public class DWARFFunctionImporter {
" can not fit into specified register " + dvar.reg.getName() +
", size=" + dvar.reg.getMinimumByteSize() +
", skipping. DWARF DIE: " + diea.getHexOffset());
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
@@ -430,6 +567,9 @@ public class DWARFFunctionImporter {
// The DWARF register did not have a mapping to a Ghidra register, so
// log it to be displayed in an error summary at end of import phase.
importSummary.unknownRegistersEncountered.add(exprEvaluator.getRawLastRegister());
+ if (dfunc != null) {
+ dfunc.localVarErrors = true;
+ }
return null;
}
}
@@ -1030,75 +1170,7 @@ public class DWARFFunctionImporter {
return false;
}
- private void outputFunction(DWARFFunction dfunc, DIEAggregate diea) {
- try {
- Function function = createFunction(dfunc);
- if (function == null) {
- Msg.error(this, "DWARF DIE: " + diea.getHexOffset());
- return;
- }
-
- DWARFSourceInfo sourceInfo = DWARFSourceInfo.create(diea);
- if (sourceInfo != null) {
- // Move the function into the program tree of the file
- moveIntoFragment(function.getName(), dfunc.address,
- dfunc.highAddress != null ? dfunc.highAddress : dfunc.address.add(1),
- sourceInfo.getFilename());
-
- if (importOptions.isOutputSourceLocationInfo()) {
- appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
- sourceInfo.getDescriptionStr(), "\n");
- }
- }
- if (importOptions.isOutputDIEInfo()) {
- appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
- "DWARF DIE: " + diea.getHexOffset(), "\n");
- }
-
- DWARFNameInfo dni = prog.getName(diea);
- if (dni.isNameModified()) {
- appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
- "Original name: " + dni.getOriginalName(), "\n");
- }
-
- CompilerSpec compilerSpec = currentProgram.getCompilerSpec();
- PrototypeModel convention = null;
- Variable returnVariable;
- ArrayList params = new ArrayList<>();
-
- // boolean specifyStorage = evaluateParameterStorage(dfunc);
-
- returnVariable = buildReturnVariable(dfunc.retval);
- for (int i = 0; i < dfunc.params.size(); ++i) {
- Parameter curparam = buildParameter(function, i, dfunc.params.get(i), diea);
- params.add(curparam);
- if (i == 0 && checkThisParameter(dfunc.params.get(0), diea)) {
- convention = compilerSpec.matchConvention(GenericCallingConvention.thiscall);
- }
- }
-
- for (int i = 0; i < dfunc.local.size(); ++i) {
- commitLocal(function, dfunc.local.get(i));
- }
-
- if (dfunc.retval != null || params.size() > 0) {
- // Add the function signature definition into the data type manager
-// TODO: createFunctionDefinition(dfunc, infopath);
-
- // NOTE: Storage is computed above for the purpose of identifying
- // a best fit calling convention. The commitPrototype method currently
- // always employs dynamic storage.
- commitPrototype(function, returnVariable, params, convention);
- function.setVarArgs(dfunc.varArg);
- }
- }
- catch (InvalidInputException | DuplicateNameException iie) {
- Msg.error(this, "Error updating function " + dfunc.dni.getName() + " at " +
- dfunc.address.toString() + ": " + iie.getMessage());
- }
- }
-
- private Function createFunction(DWARFFunction dfunc) {
+ private Function createFunction(DWARFFunction dfunc, DIEAggregate diea) {
try {
// create a new symbol if one does not exist (symbol table will figure this out)
SymbolTable symbolTable = currentProgram.getSymbolTable();
@@ -1129,6 +1201,30 @@ public class DWARFFunctionImporter {
function = currentProgram.getFunctionManager().createFunction(null, dfunc.address,
new AddressSet(dfunc.address), SourceType.IMPORTED);
}
+
+ DWARFSourceInfo sourceInfo = DWARFSourceInfo.create(diea);
+ if (sourceInfo != null) {
+ // Move the function into the program tree of the file
+ moveIntoFragment(function.getName(), dfunc.address,
+ dfunc.highAddress != null ? dfunc.highAddress : dfunc.address.add(1),
+ sourceInfo.getFilename());
+
+ if (importOptions.isOutputSourceLocationInfo()) {
+ appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
+ sourceInfo.getDescriptionStr(), "\n");
+ }
+ }
+ if (importOptions.isOutputDIEInfo()) {
+ appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
+ "DWARF DIE: " + diea.getHexOffset(), "\n");
+ }
+
+ DWARFNameInfo dni = prog.getName(diea);
+ if (dni.isNameModified()) {
+ appendComment(dfunc.address, CodeUnit.PLATE_COMMENT,
+ "Original name: " + dni.getOriginalName(), "\n");
+ }
+
return function;
}
catch (OverlappingFunctionException e) {
@@ -1152,14 +1248,14 @@ public class DWARFFunctionImporter {
* @throws InvalidInputException invalid parameter name
* @throws DuplicateNameException (should not occur on non-DB parameter)
*/
- private void setUniqueParameterNames(Function function, Parameter[] parameters)
+ private void setUniqueParameterNames(Function function, List parameters)
throws DuplicateNameException, InvalidInputException {
SymbolTable symbolTable = currentProgram.getSymbolTable();
// Create a set containing all the unique parameter names determined so far so they can
// be avoided as additional parameter names are determined.
Set namesSoFar = new HashSet<>();
- for (int ordinal = 0; ordinal < parameters.length; ordinal++) {
- Parameter parameter = parameters[ordinal];
+ for (int ordinal = 0; ordinal < parameters.size(); ordinal++) {
+ Parameter parameter = parameters.get(ordinal);
String baseName = parameter.getName();
if (ordinal == 0 && Function.THIS_PARAM_NAME.equals(baseName)) {
continue;
@@ -1233,14 +1329,13 @@ public class DWARFFunctionImporter {
}
private void commitPrototype(Function function, Variable returnVariable,
- ArrayList params, PrototypeModel protoModel)
+ List params, PrototypeModel protoModel)
throws InvalidInputException, DuplicateNameException {
- Parameter[] paramarray = new Parameter[params.size()];
- params.toArray(paramarray);
CompilerSpec compilerSpec = currentProgram.getCompilerSpec();
if (protoModel == null) {
+ Parameter[] paramarray = params.toArray(Parameter[]::new);
protoModel = compilerSpec.findBestCallingConvention(paramarray);
}
@@ -1249,7 +1344,7 @@ public class DWARFFunctionImporter {
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.IMPORTED);
}
catch (DuplicateNameException e) {
- setUniqueParameterNames(function, paramarray);
+ setUniqueParameterNames(function, params);
function.updateFunction(protoModel.getName(), returnVariable, params,
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.IMPORTED);
}
@@ -1361,9 +1456,10 @@ public class DWARFFunctionImporter {
public DWARFVariable retval;
public boolean isExternal;
public long frameBase;
- public ArrayList params = new ArrayList<>();
- public ArrayList local = new ArrayList<>();
+ public List params = new ArrayList<>();
+ public List local = new ArrayList<>();
public boolean varArg;
+ public boolean localVarErrors; // set to true if problem w/local var decoding
public DWARFFunction(DWARFNameInfo dni) {
this.dni = dni;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java
index 23af6041e9..cc0e591505 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java
@@ -461,8 +461,12 @@ public class DemangledFunction extends DemangledObject {
// If returnType is null check for constructor or destructor names
if (THIS_CALL.equals(function.getCallingConventionName())) {
String n = getName();
- if (n.equals("~" + namespace.getName()) || n.equals(namespace.getName())) {
- // constructor && destructor
+ if (n.equals(namespace.getName())) {
+ // constructor
+ return DataType.DEFAULT;
+ }
+ if (n.equals("~" + namespace.getName())) {
+ // destructor
return VoidDataType.dataType;
}
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractMemberFunctionMsType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractMemberFunctionMsType.java
index ea8ff4a9ad..662cb70cc6 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractMemberFunctionMsType.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/AbstractMemberFunctionMsType.java
@@ -90,6 +90,14 @@ public abstract class AbstractMemberFunctionMsType extends AbstractMsType {
return functionAttributes;
}
+ /**
+ * Returns if known to be a constructor.
+ * @return true if constructor.
+ */
+ public boolean isConstructor() {
+ return functionAttributes.isConstructor();
+ }
+
/**
* Returns the number of parameters to the function.
* @return The number of parameters.
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/FunctionMsAttributes.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/FunctionMsAttributes.java
index a558494c34..6343728650 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/FunctionMsAttributes.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/type/FunctionMsAttributes.java
@@ -58,4 +58,8 @@ public class FunctionMsAttributes extends AbstractParsableItem {
isInstanceConstructorOfClassWithVirtualBases = ((attributes & 0x0001) == 0x0001);
}
+ boolean isConstructor() {
+ return isInstanceConstructor || isInstanceConstructorOfClassWithVirtualBases;
+ }
+
}
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
index 7c2af2d121..3dbb8dca93 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java
@@ -121,6 +121,14 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
*/
protected abstract RecordNumber getArgListRecordNumber();
+ /**
+ * Returns if known to be a constructor.
+ * @return true if constructor.
+ */
+ protected boolean isConstructor() {
+ return false;
+ }
+
/**
* Method to create the {@link DataType} based upon the type indices of the calling
* convention, return type, and arguments list.
@@ -203,6 +211,10 @@ public abstract class AbstractFunctionTypeApplier extends MsTypeApplier {
private boolean setReturnType() {
+ if (isConstructor()) {
+ return false;
+ }
+
DataType returnDataType = returnApplier.getDataType();
if (returnDataType == null) {
applicator.appendLogMsg("Return type is null in " + functionDefinition.getName());
diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java
index 681d628987..d659b94cf9 100644
--- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java
+++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MemberFunctionTypeApplier.java
@@ -75,6 +75,11 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
return ((AbstractMemberFunctionMsType) msType).getArgListRecordNumber();
}
+ @Override
+ protected boolean isConstructor() {
+ return ((AbstractMemberFunctionMsType) msType).isConstructor();
+ }
+
@Override
void apply() throws PdbException, CancelledException {
predefineClasses();
@@ -175,8 +180,7 @@ public class MemberFunctionTypeApplier extends AbstractFunctionTypeApplier {
// }
private MsTypeApplier getThisPointerApplier(AbstractMemberFunctionMsType procType) {
- MsTypeApplier applier =
- applicator.getTypeApplier(procType.getThisPointerRecordNumber());
+ MsTypeApplier applier = applicator.getTypeApplier(procType.getThisPointerRecordNumber());
// if ((applier instanceof PrimitiveTypeApplier &&
// ((PrimitiveTypeApplier) applier).isNoType())) {