1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Fixed dbg evaluation issue with chained sret calls

This commit is contained in:
Brian Fiete 2020-10-17 10:52:54 -07:00
parent 79d13a3626
commit 95c603ada5
2 changed files with 90 additions and 15 deletions

View file

@ -765,6 +765,7 @@ DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModul
mReceivingValue = NULL; mReceivingValue = NULL;
mCallResults = NULL; mCallResults = NULL;
mCallResultIdx = 0; mCallResultIdx = 0;
mCallStackPreservePos = 0;
mPropGet = NULL; mPropGet = NULL;
mPropSet = NULL; mPropSet = NULL;
mPropSrc = NULL; mPropSrc = NULL;
@ -6684,7 +6685,7 @@ bool DbgExprEvaluator::ResolveArgValues(const BfSizedArray<ASTREF(BfExpression*)
return true; return true;
} }
DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue thisVal, bool bypassVirtual, CPURegisters* registers) DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue thisVal, DbgTypedValue structRetVal, bool bypassVirtual, CPURegisters* registers)
{ {
// Why did we have the Not Runing thing for Exception? It means that when we crash we can't execute functions anymore. // Why did we have the Not Runing thing for Exception? It means that when we crash we can't execute functions anymore.
// That doesn't seem good // That doesn't seem good
@ -6694,9 +6695,32 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue
return DbgTypedValue(); return DbgTypedValue();
}*/ }*/
#ifdef BF_WANTS_LOG_DBGEXPR
auto _GetResultString = [&](DbgTypedValue val)
{
String result;
if (val.mSrcAddress != 0)
{
result += StrFormat("0x%p ", val.mSrcAddress);
int64 vals[4] = { 0 };
mDebugger->ReadMemory(val.mSrcAddress, 4 * 8, vals);
result += StrFormat("%lld %lld %lld %lld", vals[0], vals[1], vals[2], vals[3]);
}
else
{
result += StrFormat("%lld", val.mInt64);
}
return result;
};
#endif
int curCallResultIdx = mCallResultIdx++; int curCallResultIdx = mCallResultIdx++;
if (((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) == 0) || (mCreatedPendingCall)) if (((mExpressionFlags & DwEvalExpressionFlag_AllowCalls) == 0) || (mCreatedPendingCall))
{ {
BfLogDbgExpr(" BlockedSideEffects\n");
mBlockedSideEffects = true; mBlockedSideEffects = true;
return GetDefaultTypedValue(method->mReturnType); return GetDefaultTypedValue(method->mReturnType);
} }
@ -6706,16 +6730,32 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue
// entire expression using the actual returned results for each of those calls until we can finally evaluate it as a whole // entire expression using the actual returned results for each of those calls until we can finally evaluate it as a whole
if (curCallResultIdx < (int)mCallResults->size() - 1) if (curCallResultIdx < (int)mCallResults->size() - 1)
{ {
return (*mCallResults)[curCallResultIdx].mResult; auto callResult = (*mCallResults)[curCallResultIdx];
auto result = callResult.mResult;
if (!callResult.mSRetData.IsEmpty())
{
result = structRetVal;
mDebugger->WriteMemory(result.mSrcAddress, &callResult.mSRetData[0], (int)callResult.mSRetData.size());
}
BfLogDbgExpr(" using cached results %s\n", _GetResultString(result).c_str());
return result;
} }
else if (curCallResultIdx == (int)mCallResults->size() - 1) else if (curCallResultIdx == (int)mCallResults->size() - 1)
{ {
auto& callResult = (*mCallResults)[curCallResultIdx];
CPURegisters newPhysRegisters; CPURegisters newPhysRegisters;
mDebugger->PopulateRegisters(&newPhysRegisters); mDebugger->PopulateRegisters(&newPhysRegisters);
DbgTypedValue returnVal; DbgTypedValue returnVal;
if (method->mReturnType != 0) if (method->mReturnType != 0)
{ {
if (callResult.mStructRetVal)
returnVal = callResult.mStructRetVal;
else
returnVal = mDebugger->ReadReturnValue(&newPhysRegisters, method->mReturnType); returnVal = mDebugger->ReadReturnValue(&newPhysRegisters, method->mReturnType);
bool hadRef = false; bool hadRef = false;
auto returnType = method->mReturnType->RemoveModifiers(&hadRef); auto returnType = method->mReturnType->RemoveModifiers(&hadRef);
@ -6730,10 +6770,23 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue
returnVal.mType = mDbgModule->GetPrimitiveType(DbgType_Void, GetLanguage()); returnVal.mType = mDbgModule->GetPrimitiveType(DbgType_Void, GetLanguage());
} }
BfLogDbgExpr(" using new results %s\n", _GetResultString(returnVal).c_str());
mDebugger->RestoreAllRegisters(); mDebugger->RestoreAllRegisters();
(*mCallResults)[curCallResultIdx].mResult = returnVal;
if ((method->mReturnType->IsCompositeType()) && (mDebugger->CheckNeedsSRetArgument(method->mReturnType)))
{
callResult.mSRetData.Resize(method->mReturnType->GetByteCount());
mDebugger->ReadMemory(returnVal.mSrcAddress, method->mReturnType->GetByteCount(), &callResult.mSRetData[0]);
}
callResult.mResult = returnVal;
return returnVal; return returnVal;
} }
else
{
BfLogDbgExpr(" new call\n");
}
// It's a new call // It's a new call
@ -6831,6 +6884,7 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, DbgTypedValue
DbgCallResult callResult; DbgCallResult callResult;
callResult.mSubProgram = method; callResult.mSubProgram = method;
callResult.mStructRetVal = structRetVal;
mCallResults->push_back(callResult); mCallResults->push_back(callResult);
mCreatedPendingCall = true; mCreatedPendingCall = true;
@ -7160,6 +7214,8 @@ DbgTypedValue DbgExprEvaluator::CreateCall(BfAstNode* targetSrc, DbgTypedValue t
DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl<DbgMethodArgument>& argPushQueue, bool bypassVirtual) DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl<DbgMethodArgument>& argPushQueue, bool bypassVirtual)
{ {
BfLogDbgExpr("CreateCall #%d %s", mCallResultIdx, method->mName);
if (mDebugger->IsMiniDumpDebugger()) if (mDebugger->IsMiniDumpDebugger())
{ {
Fail("Cannot call functions in a minidump", NULL); Fail("Cannot call functions in a minidump", NULL);
@ -7178,6 +7234,11 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl
bool canSetRegisters = mDebugger->PopulateRegisters(&registers); bool canSetRegisters = mDebugger->PopulateRegisters(&registers);
auto* regSP = registers.GetSPRegisterRef(); auto* regSP = registers.GetSPRegisterRef();
if (mCallStackPreservePos != 0)
{
if (mCallStackPreservePos <= *regSP)
*regSP = mCallStackPreservePos;
}
int paramIdx = argPushQueue.size() - 1; int paramIdx = argPushQueue.size() - 1;
if (method->mHasThis) if (method->mHasThis)
@ -7191,13 +7252,16 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl
thisByValue = true; thisByValue = true;
} }
DbgTypedValue compositeRetVal; DbgTypedValue structRetVal;
if (mDebugger->CheckNeedsSRetArgument(method->mReturnType)) if (mDebugger->CheckNeedsSRetArgument(method->mReturnType))
{ {
int retSize = BF_ALIGN(method->mReturnType->GetByteCount(), 16); int retSize = BF_ALIGN(method->mReturnType->GetByteCount(), 16);
*regSP -= retSize; *regSP -= retSize;
compositeRetVal.mType = method->mReturnType; structRetVal.mType = method->mReturnType;
compositeRetVal.mSrcAddress = *regSP; structRetVal.mSrcAddress = *regSP;
// For chained calls we need to leave the sret form the previous calls intact
mCallStackPreservePos = *regSP;
} }
for (int i = (int)argPushQueue.size() - 1; i >= 0; i--) for (int i = (int)argPushQueue.size() - 1; i >= 0; i--)
@ -7227,9 +7291,10 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl
} }
} }
if (compositeRetVal.mSrcAddress != 0) if (structRetVal.mSrcAddress != 0)
{ {
mDebugger->AddParamValue(0, method->mHasThis && !thisByValue, &registers, compositeRetVal); BfLogDbgExpr(" SRet:0x%p", structRetVal.mSrcAddress);
mDebugger->AddParamValue(0, method->mHasThis && !thisByValue, &registers, structRetVal);
paramIdx++; paramIdx++;
} }
@ -7253,6 +7318,9 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl
else else
thisAddr = thisVal.mPtr; thisAddr = thisVal.mPtr;
mDebugger->SetThisRegister(&registers, thisAddr); mDebugger->SetThisRegister(&registers, thisAddr);
if (padCount == 0)
BfLogDbgExpr(" This:0x%p", thisAddr);
} }
else else
{ {
@ -7275,7 +7343,7 @@ DbgTypedValue DbgExprEvaluator::CreateCall(DbgSubprogram* method, SizedArrayImpl
BF_ASSERT(padCount < 3); BF_ASSERT(padCount < 3);
} }
return CreateCall(method, thisVal, bypassVirtual, &registers); return CreateCall(method, thisVal, structRetVal, bypassVirtual, &registers);
} }
DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName, DbgTypedValue DbgExprEvaluator::MatchMethod(BfAstNode* targetSrc, DbgTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName,
@ -8106,8 +8174,12 @@ void DbgExprEvaluator::Visit(BfTupleExpression* tupleExpr)
DbgTypedValue DbgExprEvaluator::Resolve(BfExpression* expr, DbgType* wantType) DbgTypedValue DbgExprEvaluator::Resolve(BfExpression* expr, DbgType* wantType)
{ {
//BfLogDbgExpr("Dbg Evaluate %s\n", expr->ToString().c_str());
BF_ASSERT(!HasPropResult()); BF_ASSERT(!HasPropResult());
mCallStackPreservePos = 0;
SetAndRestoreValue<DbgType*> prevType(mExpectingType, wantType); SetAndRestoreValue<DbgType*> prevType(mExpectingType, wantType);
SetAndRestoreValue<DbgTypedValue> prevResult(mResult, DbgTypedValue()); SetAndRestoreValue<DbgTypedValue> prevResult(mResult, DbgTypedValue());

View file

@ -234,6 +234,8 @@ class DbgCallResult
public: public:
DbgSubprogram* mSubProgram; DbgSubprogram* mSubProgram;
DbgTypedValue mResult; DbgTypedValue mResult;
DbgTypedValue mStructRetVal;
Array<uint8> mSRetData;
}; };
class DbgExprEvaluator : public BfStructuralVisitor class DbgExprEvaluator : public BfStructuralVisitor
@ -285,6 +287,7 @@ public:
DbgTypedValue mExplicitThis; DbgTypedValue mExplicitThis;
BfExpression* mExplicitThisExpr; BfExpression* mExplicitThisExpr;
Array<DbgCallResult>* mCallResults; Array<DbgCallResult>* mCallResults;
addr_target mCallStackPreservePos;
int mCallResultIdx; int mCallResultIdx;
String mNamespaceSearchStr; String mNamespaceSearchStr;
Array<DbgType*> mNamespaceSearch; Array<DbgType*> mNamespaceSearch;
@ -322,7 +325,7 @@ public:
DbgTypedValue CheckEnumCreation(BfAstNode* targetSrc, DbgType* enumType, const StringImpl& caseName, const BfSizedArray<BfExpression*>& argValues); DbgTypedValue CheckEnumCreation(BfAstNode* targetSrc, DbgType* enumType, const StringImpl& caseName, const BfSizedArray<BfExpression*>& argValues);
void DoInvocation(BfAstNode* target, BfSizedArray<ASTREF(BfExpression*)>& args, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments); void DoInvocation(BfAstNode* target, BfSizedArray<ASTREF(BfExpression*)>& args, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments);
bool ResolveArgValues(const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& outArgValues); bool ResolveArgValues(const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& outArgValues);
DbgTypedValue CreateCall(DbgSubprogram* method, DbgTypedValue thisVal, bool bypassVirtual, CPURegisters* registers); DbgTypedValue CreateCall(DbgSubprogram* method, DbgTypedValue thisVal, DbgTypedValue structRetVal, bool bypassVirtual, CPURegisters* registers);
DbgTypedValue CreateCall(DbgSubprogram* method, SizedArrayImpl<DbgMethodArgument>& argPushQueue, bool bypassVirtual); DbgTypedValue CreateCall(DbgSubprogram* method, SizedArrayImpl<DbgMethodArgument>& argPushQueue, bool bypassVirtual);
DbgTypedValue CreateCall(BfAstNode* targetSrc, DbgTypedValue target, DbgSubprogram* methodDef, bool bypassVirtual, const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& argValues); DbgTypedValue CreateCall(BfAstNode* targetSrc, DbgTypedValue target, DbgSubprogram* methodDef, bool bypassVirtual, const BfSizedArray<ASTREF(BfExpression*)>& arguments, SizedArrayImpl<DbgTypedValue>& argValues);
DbgTypedValue MatchMethod(BfAstNode* targetSrc, DbgTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName, DbgTypedValue MatchMethod(BfAstNode* targetSrc, DbgTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName,