@@ -531,6 +531,75 @@ bool DbgEngTTDAdapter::SetTTDPosition(const TTDPosition& position)
531531 return success;
532532}
533533
534+
535+ std::pair<bool , TTDMemoryEvent> DbgEngTTDAdapter::GetTTDNextMemoryAccess (uint64_t address, uint64_t size, TTDMemoryAccessType accessType)
536+ {
537+ if (!m_debugControl)
538+ {
539+ LogError (" Debug control interface not available" );
540+ return {false , TTDMemoryEvent ()};
541+ }
542+
543+ try
544+ {
545+ std::string accessTypeStr;
546+ if (accessType & TTDMemoryRead) accessTypeStr += " r" ;
547+ if (accessType & TTDMemoryWrite) accessTypeStr += " w" ;
548+ if (accessType & TTDMemoryExecute) accessTypeStr += " e" ;
549+
550+ if (accessTypeStr.empty ())
551+ {
552+ LogError (" Invalid access type specified" );
553+ return {false , TTDMemoryEvent ()};
554+ }
555+
556+ std::string expression = fmt::format (" @$curprocess.TTD.NextMemoryAccess(\" {}\" ,0x{:x},0x{:x})" , accessTypeStr, address, size);
557+ LogInfo (" Executing TTD NextMemoryAccess query: %s" , expression.c_str ());
558+
559+ return ParseSingleTTDMemoryObject (expression, accessType);
560+ }
561+ catch (const std::exception& e)
562+ {
563+ LogError (" Exception in GetTTDNextMemoryAccess: %s" , e.what ());
564+ return {false , TTDMemoryEvent ()};
565+ }
566+ }
567+
568+
569+ std::pair<bool , TTDMemoryEvent> DbgEngTTDAdapter::GetTTDPrevMemoryAccess (uint64_t address, uint64_t size, TTDMemoryAccessType accessType)
570+ {
571+ if (!m_debugControl)
572+ {
573+ LogError (" Debug control interface not available" );
574+ return {false , TTDMemoryEvent ()};
575+ }
576+
577+ try
578+ {
579+ std::string accessTypeStr;
580+ if (accessType & TTDMemoryRead) accessTypeStr += " r" ;
581+ if (accessType & TTDMemoryWrite) accessTypeStr += " w" ;
582+ if (accessType & TTDMemoryExecute) accessTypeStr += " e" ;
583+
584+ if (accessTypeStr.empty ())
585+ {
586+ LogError (" Invalid access type specified" );
587+ return {false , TTDMemoryEvent ()};
588+ }
589+
590+ std::string expression = fmt::format (" @$curprocess.TTD.PrevMemoryAccess(\" {}\" ,0x{:x},0x{:x})" , accessTypeStr, address, size);
591+ LogInfo (" Executing TTD PrevMemoryAccess query: %s" , expression.c_str ());
592+
593+ return ParseSingleTTDMemoryObject (expression, accessType);
594+ }
595+ catch (const std::exception& e)
596+ {
597+ LogError (" Exception in GetTTDPrevMemoryAccess: %s" , e.what ());
598+ return {false , TTDMemoryEvent ()};
599+ }
600+ }
601+
602+
534603bool DbgEngTTDAdapter::QueryMemoryAccessByAddress (uint64_t startAddress, uint64_t endAddress, TTDMemoryAccessType accessType, std::vector<TTDMemoryEvent>& events)
535604{
536605 if (!m_debugControl)
@@ -1272,6 +1341,146 @@ bool DbgEngTTDAdapter::ParseTTDPositionRangeIndexedMemoryObjects(const std::stri
12721341}
12731342
12741343
1344+ std::pair<bool , TTDMemoryEvent> DbgEngTTDAdapter::ParseSingleTTDMemoryObject (const std::string& expression, TTDMemoryAccessType accessType)
1345+ {
1346+ TTDMemoryEvent event;
1347+
1348+ if (!m_hostEvaluator)
1349+ {
1350+ LogError (" Data model evaluator not available" );
1351+ return {false , event};
1352+ }
1353+
1354+ try
1355+ {
1356+ std::wstring wExpression (expression.begin (), expression.end ());
1357+
1358+ ComPtr<IDebugHostContext> hostContext;
1359+ if (FAILED (m_debugHost->GetCurrentContext (hostContext.GetAddressOf ())))
1360+ {
1361+ LogError (" Failed to get current debug host context" );
1362+ return {false , event};
1363+ }
1364+
1365+ ComPtr<IModelObject> result;
1366+ ComPtr<IKeyStore> metadata;
1367+ HRESULT hr = m_hostEvaluator->EvaluateExtendedExpression (
1368+ hostContext.Get (),
1369+ wExpression.c_str (),
1370+ nullptr ,
1371+ result.GetAddressOf (),
1372+ metadata.GetAddressOf ()
1373+ );
1374+
1375+ if (FAILED (hr))
1376+ {
1377+ LogError (" Failed to evaluate expression '%s': 0x%08x" , expression.c_str (), hr);
1378+ return {false , event};
1379+ }
1380+
1381+ if (!result)
1382+ {
1383+ LogError (" Null result from expression '%s'" , expression.c_str ());
1384+ return {false , event};
1385+ }
1386+
1387+ // The result is a single memory access object (not a collection).
1388+ // Parse Position
1389+ ComPtr<IModelObject> positionObj;
1390+ if (SUCCEEDED (result->GetKeyValue (L" Position" , &positionObj, nullptr )))
1391+ {
1392+ ParseTTDPosition (positionObj.Get (), event.timeStart );
1393+ }
1394+
1395+ // Parse OriginalPosition into timeEnd (represents the position from which the query was made)
1396+ ComPtr<IModelObject> origPositionObj;
1397+ if (SUCCEEDED (result->GetKeyValue (L" OriginalPosition" , &origPositionObj, nullptr )))
1398+ {
1399+ ParseTTDPosition (origPositionObj.Get (), event.timeEnd );
1400+ }
1401+
1402+ // Get UniqueThreadId
1403+ ComPtr<IModelObject> uniqueThreadIdObj;
1404+ if (SUCCEEDED (result->GetKeyValue (L" UniqueThreadId" , &uniqueThreadIdObj, nullptr )))
1405+ {
1406+ VARIANT vtUniqueThreadId;
1407+ VariantInit (&vtUniqueThreadId);
1408+ if (SUCCEEDED (uniqueThreadIdObj->GetIntrinsicValueAs (VT_UI4, &vtUniqueThreadId)))
1409+ {
1410+ event.uniqueThreadId = vtUniqueThreadId.ulVal ;
1411+ }
1412+ VariantClear (&vtUniqueThreadId);
1413+ }
1414+
1415+ // Get Address
1416+ ComPtr<IModelObject> addressObj;
1417+ if (SUCCEEDED (result->GetKeyValue (L" Address" , &addressObj, nullptr )))
1418+ {
1419+ VARIANT vtAddress;
1420+ VariantInit (&vtAddress);
1421+ if (SUCCEEDED (addressObj->GetIntrinsicValueAs (VT_UI8, &vtAddress)))
1422+ {
1423+ event.address = vtAddress.ullVal ;
1424+ }
1425+ VariantClear (&vtAddress);
1426+ }
1427+
1428+ // Get Size
1429+ ComPtr<IModelObject> sizeObj;
1430+ if (SUCCEEDED (result->GetKeyValue (L" Size" , &sizeObj, nullptr )))
1431+ {
1432+ VARIANT vtSize;
1433+ VariantInit (&vtSize);
1434+ if (SUCCEEDED (sizeObj->GetIntrinsicValueAs (VT_UI8, &vtSize)))
1435+ {
1436+ event.size = vtSize.ullVal ;
1437+ }
1438+ VariantClear (&vtSize);
1439+ }
1440+
1441+ // Get AccessType
1442+ ComPtr<IModelObject> accessTypeObj;
1443+ if (SUCCEEDED (result->GetKeyValue (L" AccessType" , &accessTypeObj, nullptr )))
1444+ {
1445+ VARIANT vtAccessType;
1446+ VariantInit (&vtAccessType);
1447+ if (SUCCEEDED (accessTypeObj->GetIntrinsicValueAs (VT_BSTR, &vtAccessType)))
1448+ {
1449+ _bstr_t bstr (vtAccessType.bstrVal );
1450+ std::string accessTypeStr = std::string (bstr);
1451+
1452+ TTDMemoryAccessType parsedAccessType = static_cast <TTDMemoryAccessType>(0 );
1453+ if (accessTypeStr.find (" Read" ) != std::string::npos)
1454+ parsedAccessType = static_cast <TTDMemoryAccessType>(parsedAccessType | TTDMemoryRead);
1455+ if (accessTypeStr.find (" Write" ) != std::string::npos)
1456+ parsedAccessType = static_cast <TTDMemoryAccessType>(parsedAccessType | TTDMemoryWrite);
1457+ if (accessTypeStr.find (" Execute" ) != std::string::npos)
1458+ parsedAccessType = static_cast <TTDMemoryAccessType>(parsedAccessType | TTDMemoryExecute);
1459+
1460+ event.accessType = parsedAccessType;
1461+ }
1462+ else
1463+ {
1464+ event.accessType = accessType;
1465+ }
1466+ VariantClear (&vtAccessType);
1467+ }
1468+ else
1469+ {
1470+ event.accessType = accessType;
1471+ }
1472+
1473+ LogInfo (" Successfully parsed single TTD memory access at position %llx:%llx" , event.timeStart .sequence , event.timeStart .step );
1474+ return {true , event};
1475+ }
1476+ catch (const std::exception& e)
1477+ {
1478+ LogError (" Exception in ParseSingleTTDMemoryObject: %s" , e.what ());
1479+ return {false , event};
1480+ }
1481+ }
1482+
1483+
12751484std::vector<TTDCallEvent> DbgEngTTDAdapter::GetTTDCallsForSymbols (const std::string& symbols, uint64_t startReturnAddress, uint64_t endReturnAddress)
12761485{
12771486 std::vector<TTDCallEvent> events;
0 commit comments