mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-16 07:30:16 +00:00
GP-794 Fix handling of problematic DWARF function parameters.
This commit is contained in:
parent
c6de9dc493
commit
763092487b
@ -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<DWARFLocation> 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<Parameter> 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<Parameter> 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<Parameter> 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<Parameter> 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<Parameter> 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<String> 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<Parameter> params, PrototypeModel protoModel)
|
||||
List<Parameter> 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<DWARFVariable> params = new ArrayList<>();
|
||||
public ArrayList<DWARFVariable> local = new ArrayList<>();
|
||||
public List<DWARFVariable> params = new ArrayList<>();
|
||||
public List<DWARFVariable> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user