VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3FlowTrace.cpp@ 94249

Last change on this file since 94249 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.6 KB
Line 
1/* $Id: DBGFR3FlowTrace.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Guest Execution Flow Tracing.
4 */
5
6/*
7 * Copyright (C) 2016-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_dbgf_flow DBGFR3FlowTrace - Flow Trace Interface
20 *
21 * @todo
22 */
23
24
25/*********************************************************************************************************************************
26* Header Files *
27*********************************************************************************************************************************/
28#define LOG_GROUP LOG_GROUP_DBGF
29#include <VBox/vmm/dbgfflowtrace.h>
30#include "DBGFInternal.h"
31#include <VBox/vmm/mm.h>
32#include <VBox/vmm/uvm.h>
33#include <VBox/vmm/vm.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36
37#include <iprt/assert.h>
38#include <iprt/semaphore.h>
39#include <iprt/list.h>
40#include <iprt/time.h>
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52
53/** Pointer to the internal trace module instance data. */
54typedef struct DBGFFLOWTRACEMODINT *PDBGFFLOWTRACEMODINT;
55/** Pointer to a trace module probe location. */
56typedef struct DBGFFLOWTRACEMODPROBELOC *PDBGFFLOWTRACEMODPROBELOC;
57
58/**
59 * Internal probe instance data.
60 */
61typedef struct DBGFFLOWTRACEPROBEINT
62{
63 /** External and internal references hold. */
64 volatile uint32_t cRefs;
65 /** Trace modules referencing this probe. */
66 volatile uint32_t cRefsMod;
67 /** The user mode VM handle. */
68 PUVM pUVM;
69 /** Description of this probe. */
70 char *pszDescr;
71 /** Overall memory consumed for this probe for each invocation. */
72 size_t cbProbe;
73 /** Number of entries for this probe. */
74 uint32_t cEntries;
75 /** Maximum number of entries the array can hold. */
76 uint32_t cEntriesMax;
77 /** Pointer to the probe entry array. */
78 PDBGFFLOWTRACEPROBEENTRY paEntries;
79} DBGFFLOWTRACEPROBEINT;
80/** Pointer to the internal probe instance data. */
81typedef DBGFFLOWTRACEPROBEINT *PDBGFFLOWTRACEPROBEINT;
82/** Pointer to a constant internal probe instance data. */
83typedef const DBGFFLOWTRACEPROBEINT *PCDBGFFLOWTRACEPROBEINT;
84
85/**
86 * Record collected for one probe hit.
87 */
88typedef struct DBGFFLOWTRACERECORDINT
89{
90 /** Data list node. */
91 RTLISTNODE NdRecord;
92 /** The probe instance the record was created for. */
93 PDBGFFLOWTRACEPROBEINT pProbe;
94 /** The common probe instance data was collected for. */
95 PDBGFFLOWTRACEPROBEINT pProbeCmn;
96 /** Address of the probe location. */
97 DBGFADDRESS AddrProbe;
98 /** Reference counter. */
99 volatile uint32_t cRefs;
100 /** CPU ID this data was collected on. */
101 VMCPUID idCpu;
102 /** Sequence number for this data. */
103 uint64_t u64SeqNo;
104 /** Timestamp in nanoseconds when the data was collected. */
105 uint64_t u64TsCollected;
106 /** Pointer to the values for the common probe if available. */
107 PDBGFFLOWTRACEPROBEVAL paValCmn;
108 /** The probe values collected - size defined
109 * by the number of entries in the probe. */
110 DBGFFLOWTRACEPROBEVAL aVal[1];
111} DBGFFLOWTRACERECORDINT;
112/** Pointer to one collected probe data. */
113typedef DBGFFLOWTRACERECORDINT *PDBGFFLOWTRACERECORDINT;
114
115/**
116 * Trace module state.
117 */
118typedef enum DBGFFLOWTRACEMODSTATE
119{
120 /** Invalid state. */
121 DBGFFLOWTRACEMODSTATE_INVALID = 0,
122 /** The module was created. */
123 DBGFFLOWTRACEMODSTATE_CREATED,
124 /** The module is active, no probes can be added. */
125 DBGFFLOWTRACEMODSTATE_ENABLED,
126 /** The VM is destroyed but there are still references to the module,
127 * functionality is limited (query records only). */
128 DBGFFLOWTRACEMODSTATE_VM_DESTROYED,
129 /** The trace module is destroyed. */
130 DBGFFLOWTRACEMODSTATE_DESTROYED,
131 /** 32bit hack. */
132 DBGFFLOWTRACEMODSTATE_32BIT_HACK = 0x7fffffff
133} DBGFFLOWTRACEMODSTATE;
134
135/**
136 * Internal trace module instance data.
137 */
138typedef struct DBGFFLOWTRACEMODINT
139{
140 /** References hold for this trace module. */
141 volatile uint32_t cRefs;
142 /** The user mode VM handle. */
143 PUVM pUVM;
144 /** CPU ID the module is for. */
145 VMCPUID idCpu;
146 /** The DBGF owner handle. */
147 DBGFBPOWNER hBpOwner;
148 /** State of the trace module. */
149 volatile DBGFFLOWTRACEMODSTATE enmState;
150 /** Next free sequence number. */
151 volatile uint64_t u64SeqNoNext;
152 /** Optional ocmmon probe describing data to collect. */
153 PDBGFFLOWTRACEPROBEINT pProbeCmn;
154 /** Flags whether to record only a limited amount of data as indicated
155 * by cHitsLeft. */
156 bool fLimit;
157 /** Number of hits left until the module is disabled automatically. */
158 volatile uint32_t cHitsLeft;
159 /** Number of records to keep before evicting the oldest one. */
160 uint32_t cRecordsMax;
161 /** Number of records collected in this module. */
162 volatile uint32_t cRecords;
163 /** Number of probes in this trace module. */
164 uint32_t cProbes;
165 /** List of probes active for this module - DBGFFLOWTRACEMODPROBELOC. */
166 RTLISTANCHOR LstProbes;
167 /** List of collected data for this module. */
168 RTLISTANCHOR LstRecords;
169 /** Semaphore protecting access to the probe and record list. */
170 RTSEMFASTMUTEX hMtx;
171} DBGFFLOWTRACEMODINT;
172/** Pointer to a const internal trace module instance data. */
173typedef const DBGFFLOWTRACEMODINT *PCDBGFFLOWTRACEMODINT;
174
175/**
176 * Trace module probe location data.
177 */
178typedef struct DBGFFLOWTRACEMODPROBELOC
179{
180 /** List node for the list of probes. */
181 RTLISTNODE NdProbes;
182 /** The owning trace module. */
183 PDBGFFLOWTRACEMODINT pTraceMod;
184 /** The probe instance. */
185 PDBGFFLOWTRACEPROBEINT pProbe;
186 /** Address of the probe location. */
187 DBGFADDRESS AddrProbe;
188 /** The DBGF breakpoint handle. */
189 DBGFBP hBp;
190 /** Flags controlling the collection behavior for the probe. */
191 uint32_t fFlags;
192} DBGFFLOWTRACEMODPROBELOC;
193
194
195/**
196 * Flow trace report state.
197 */
198typedef struct DBGFFLOWTRACEREPORTINT
199{
200 /** The user mode VM handle. */
201 PUVM pUVM;
202 /** Reference count. */
203 volatile uint32_t cRefs;
204 /** Number of records. */
205 uint32_t cRecords;
206 /** Array with handle of records - variable in size. */
207 PDBGFFLOWTRACERECORDINT apRec[1];
208} DBGFFLOWTRACEMODREPORTINT;
209/** Pointer to the internal flow trace report state. */
210typedef DBGFFLOWTRACEREPORTINT *PDBGFFLOWTRACEREPORTINT;
211
212
213/*********************************************************************************************************************************
214* Internal Functions *
215*********************************************************************************************************************************/
216
217/**
218 * Creates a new trace record.
219 *
220 * @returns Pointer to the create flow trace record or NULL if out of memory.
221 * @param pProbeLoc The probe location to allocate the record for.
222 * @param idCpu The CPU ID this record was created for.
223 * @param ppbBuf Where to store the pointer to the data buffer for this probe.
224 * @param ppbBufCmn Where to store the pointer to the data buffer for the common probe
225 * if available.
226 */
227static PDBGFFLOWTRACERECORDINT dbgfR3FlowTraceRecordCreate(PDBGFFLOWTRACEMODPROBELOC pProbeLoc, VMCPUID idCpu,
228 uint8_t **ppbBuf, uint8_t **ppbBufCmn)
229{
230 PDBGFFLOWTRACEMODINT pTraceMod = pProbeLoc->pTraceMod;
231 PCDBGFFLOWTRACEPROBEINT pProbe = pProbeLoc->pProbe;
232 PCDBGFFLOWTRACEPROBEINT pProbeCmn = pTraceMod->pProbeCmn;
233 size_t cbProbeBuf = pProbe->cbProbe;
234 if (pProbeCmn)
235 cbProbeBuf += pProbeCmn->cbProbe;
236
237 *ppbBuf = NULL;
238 *ppbBufCmn = NULL;
239
240 PDBGFFLOWTRACERECORDINT pRecord = (PDBGFFLOWTRACERECORDINT)MMR3HeapAllocZU(pTraceMod->pUVM, MM_TAG_DBGF_FLOWTRACE,
241 sizeof(DBGFFLOWTRACERECORDINT) + cbProbeBuf);
242 if (RT_LIKELY(pRecord))
243 {
244 DBGFR3FlowTraceProbeRetain(pProbeLoc->pProbe);
245 if (pProbeLoc->pTraceMod->pProbeCmn)
246 DBGFR3FlowTraceProbeRetain(pProbeLoc->pTraceMod->pProbeCmn);
247
248 pRecord->pProbe = pProbeLoc->pProbe;
249 pRecord->pProbeCmn = pProbeLoc->pTraceMod->pProbeCmn;
250 pRecord->AddrProbe = pProbeLoc->AddrProbe;
251 pRecord->cRefs = 1;
252 pRecord->idCpu = idCpu;
253 pRecord->u64SeqNo = ASMAtomicIncU64(&pTraceMod->u64SeqNoNext);
254 pRecord->u64TsCollected = RTTimeNanoTS();
255 pRecord->paValCmn = NULL;
256
257 *ppbBuf = (uint8_t *)&pRecord->aVal[pProbe->cEntries];
258
259 if (pProbeCmn)
260 {
261 size_t offValCmn = pProbe->cbProbe - pProbe->cEntries * sizeof(DBGFFLOWTRACEPROBEVAL);
262 pRecord->paValCmn = (PDBGFFLOWTRACEPROBEVAL)(*ppbBuf + offValCmn);
263 *ppbBufCmn = (uint8_t *)&pRecord->paValCmn[pProbeCmn->cEntries];
264 }
265 }
266
267 return pRecord;
268}
269
270
271/**
272 * Destroys the given record.
273 *
274 * @returns nothing.
275 * @param pRecord The record to destroy.
276 */
277static void dbgfR3FlowTraceRecordDestroy(PDBGFFLOWTRACERECORDINT pRecord)
278{
279 DBGFR3FlowTraceProbeRelease(pRecord->pProbe);
280 pRecord->pProbe = NULL;
281 MMR3HeapFree(pRecord);
282}
283
284
285/**
286 * Creates a new flow trace report which can hold the given amount o records.
287 *
288 * @returns Pointer to the newly created report state or NULL if out of memory.
289 * @param pUVM The usermode VM handle.
290 * @param cRecords Number of records the report shoudld be able to hold.
291 */
292static PDBGFFLOWTRACEREPORTINT dbgfR3FlowTraceReportCreate(PUVM pUVM, uint32_t cRecords)
293{
294 PDBGFFLOWTRACEREPORTINT pReport = (PDBGFFLOWTRACEREPORTINT)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_FLOWTRACE,
295 RT_UOFFSETOF_DYN(DBGFFLOWTRACEREPORTINT, apRec[cRecords]));
296 if (RT_LIKELY(pReport))
297 {
298 pReport->pUVM = pUVM;
299 pReport->cRefs = 1;
300 pReport->cRecords = cRecords;
301 }
302
303 return pReport;
304}
305
306
307/**
308 * Destroys the given report releasing all references hold to the containing records.
309 *
310 * @returns nothing.
311 * @param pReport The report to destroy.
312 */
313static void dbgfR3FlowTraceReportDestroy(PDBGFFLOWTRACEREPORTINT pReport)
314{
315 for (uint32_t i = 0; i < pReport->cRecords; i++)
316 DBGFR3FlowTraceRecordRelease(pReport->apRec[i]);
317 MMR3HeapFree(pReport);
318}
319
320
321/**
322 * Queries the given register and returns the value as a guest pointer.
323 *
324 * @returns VBox status code.
325 * @param pUVM The usermode VM handle.
326 * @param idCpu VM CPU identifier.
327 * @param pszReg The register name to query.
328 * @param pGCPtr Where to store the register value on success.
329 */
330static int dbgfR3FlowTraceModProbeQueryRegAsGCPtr(PUVM pUVM, VMCPUID idCpu, const char *pszReg,
331 PRTGCPTR pGCPtr)
332{
333 DBGFREGVAL Val;
334 DBGFREGVALTYPE enmValType;
335 int rc = DBGFR3RegNmQuery(pUVM, idCpu, pszReg, &Val, &enmValType);
336 if (RT_SUCCESS(rc))
337 {
338 switch (enmValType)
339 {
340 case DBGFREGVALTYPE_U8:
341 *pGCPtr = Val.u8;
342 break;
343 case DBGFREGVALTYPE_U16:
344 *pGCPtr = Val.u16;
345 break;
346 case DBGFREGVALTYPE_U32:
347 *pGCPtr = Val.u32;
348 break;
349 case DBGFREGVALTYPE_U64:
350 *pGCPtr = Val.u64;
351 break;
352 case DBGFREGVALTYPE_U128:
353 case DBGFREGVALTYPE_R80:
354 case DBGFREGVALTYPE_DTR:
355 default:
356 rc = VERR_INVALID_PARAMETER;
357 }
358 }
359
360 return rc;
361}
362
363
364/**
365 * Resolves the guest address from an indirect memory probe entry.
366 *
367 * @returns VBox status code.
368 * @param pUVM The usermode VM handle.
369 * @param idCpu VM CPU identifier.
370 * @param pEntry The probe entry.
371 * @param pAddr Where to store the address on success.
372 */
373static int dbgfR3FlowTraceModProbeResolveIndirectAddr(PUVM pUVM, VMCPUID idCpu, PDBGFFLOWTRACEPROBEENTRY pEntry,
374 PDBGFADDRESS pAddr)
375{
376 Assert(pEntry->enmType == DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM);
377
378 RTGCPTR GCPtrBase = 0;
379 RTGCPTR GCPtrIndex = 0;
380 int rc = dbgfR3FlowTraceModProbeQueryRegAsGCPtr(pUVM, idCpu, pEntry->Type.IndirectMem.RegBase.pszName,
381 &GCPtrBase);
382 if ( RT_SUCCESS(rc)
383 && pEntry->Type.IndirectMem.RegIndex.pszName)
384 rc = dbgfR3FlowTraceModProbeQueryRegAsGCPtr(pUVM, idCpu, pEntry->Type.IndirectMem.RegIndex.pszName,
385 &GCPtrIndex);
386 if (RT_SUCCESS(rc))
387 {
388 RTGCPTR GCPtr = GCPtrBase + GCPtrIndex * pEntry->Type.IndirectMem.uScale;
389 DBGFR3AddrFromFlat(pUVM, pAddr, GCPtr);
390 if (pEntry->Type.IndirectMem.iOffset > 0)
391 DBGFR3AddrAdd(pAddr, pEntry->Type.IndirectMem.iOffset);
392 else if (pEntry->Type.IndirectMem.iOffset < 0)
393 DBGFR3AddrSub(pAddr, -pEntry->Type.IndirectMem.iOffset);
394 }
395
396 return rc;
397}
398
399
400/**
401 * Destroys the given flow trace module freeing all allocated resources.
402 *
403 * @returns nothing.
404 * @param pThis The flow trace module instance data.
405 */
406static void dbgfR3FlowTraceModDestroy(PDBGFFLOWTRACEMODINT pThis)
407{
408 if (ASMAtomicReadU32((volatile uint32_t *)&pThis->enmState) == DBGFFLOWTRACEMODSTATE_ENABLED)
409 {
410 int rc = DBGFR3FlowTraceModDisable(pThis);
411 AssertRC(rc);
412 }
413
414 Assert( pThis->enmState == DBGFFLOWTRACEMODSTATE_CREATED
415 || pThis->enmState == DBGFFLOWTRACEMODSTATE_VM_DESTROYED);
416
417 /* Do the cleanup under the semaphore. */
418 RTSemFastMutexRequest(pThis->hMtx);
419 if (pThis->pProbeCmn)
420 DBGFR3FlowTraceProbeRelease(pThis->pProbeCmn);
421
422 PDBGFFLOWTRACEMODPROBELOC pIt, pItNext;
423 RTListForEachSafe(&pThis->LstProbes, pIt, pItNext, DBGFFLOWTRACEMODPROBELOC, NdProbes)
424 {
425 RTListNodeRemove(&pIt->NdProbes);
426 ASMAtomicDecU32(&pIt->pProbe->cRefsMod);
427 DBGFR3FlowTraceProbeRelease(pIt->pProbe);
428 MMR3HeapFree(pIt);
429 }
430
431 PDBGFFLOWTRACERECORDINT pRecIt, pRecItNext;
432 RTListForEachSafe(&pThis->LstRecords, pRecIt, pRecItNext, DBGFFLOWTRACERECORDINT, NdRecord)
433 {
434 RTListNodeRemove(&pRecIt->NdRecord);
435 DBGFR3FlowTraceRecordRelease(pRecIt);
436 }
437
438 DBGFR3BpOwnerDestroy(pThis->pUVM, pThis->hBpOwner);
439 RTSemFastMutexRelease(pThis->hMtx);
440 RTSemFastMutexDestroy(pThis->hMtx);
441 MMR3HeapFree(pThis);
442}
443
444
445/**
446 * Checks whether the given basic block and address intersect.
447 *
448 * @returns true if they intersect, false otherwise.
449 * @param pAddr The address to check for.
450 * @param pAddrStart The start address.
451 * @param pAddrLast The last address.
452 */
453static bool dbgfR3FlowTraceAddrIntersect(PDBGFADDRESS pAddr, PDBGFADDRESS pAddrStart,
454 PDBGFADDRESS pAddrLast)
455{
456 return (pAddrStart->Sel == pAddr->Sel)
457 && (pAddrStart->off <= pAddr->off)
458 && (pAddrLast->off >= pAddr->off);
459}
460
461
462/**
463 * Matches a single value against a given filter value.
464 *
465 * @returns Flag whether the value matches against the single value.
466 * @param pVal The value to match.
467 * @param pValFilter The value filter to match against.
468 */
469static bool dbgfR3FlowTraceRecordMatchSingleValue(PCDBGFFLOWTRACEPROBEVAL pVal,
470 PCDBGFFLOWTRACEPROBEVAL pValFilter)
471{
472 if (pVal->pProbeEntry->enmType != pValFilter->pProbeEntry->enmType)
473 return false;
474
475 switch (pVal->pProbeEntry->enmType)
476 {
477 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
478 {
479 if (pVal->Type.Reg.enmType != pValFilter->Type.Reg.enmType)
480 return false;
481
482 if (strcmp(pVal->Type.Reg.pszName, pValFilter->Type.Reg.pszName))
483 return false;
484
485 switch (pVal->Type.Reg.enmType)
486 {
487 case DBGFREGVALTYPE_U8:
488 if (pVal->Type.Reg.Val.u8 != pValFilter->Type.Reg.Val.u8)
489 return false;
490 break;
491 case DBGFREGVALTYPE_U16:
492 if (pVal->Type.Reg.Val.u16 != pValFilter->Type.Reg.Val.u16)
493 return false;
494 break;
495 case DBGFREGVALTYPE_U32:
496 if (pVal->Type.Reg.Val.u32 != pValFilter->Type.Reg.Val.u32)
497 return false;
498 break;
499 case DBGFREGVALTYPE_U64:
500 if (pVal->Type.Reg.Val.u64 != pValFilter->Type.Reg.Val.u64)
501 return false;
502 break;
503 case DBGFREGVALTYPE_U128:
504 if (memcmp(&pVal->Type.Reg.Val.u128, &pValFilter->Type.Reg.Val.u128,
505 sizeof(RTUINT128U)))
506 return false;
507 break;
508 case DBGFREGVALTYPE_R80:
509 if (memcmp(&pVal->Type.Reg.Val.r80Ex, &pValFilter->Type.Reg.Val.r80Ex,
510 sizeof(RTFLOAT80U2)))
511 return false;
512 break;
513 case DBGFREGVALTYPE_DTR:
514 if ( pVal->Type.Reg.Val.dtr.u64Base != pValFilter->Type.Reg.Val.dtr.u64Base
515 || pVal->Type.Reg.Val.dtr.u32Limit != pValFilter->Type.Reg.Val.dtr.u32Limit)
516 return false;
517 break;
518 default:
519 AssertFailed();
520 return false;
521 }
522 break;
523 }
524 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
525 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
526 if ( memcmp(&pVal->Type.Mem.Addr, &pValFilter->Type.Mem.Addr,
527 sizeof(DBGFADDRESS))
528 || pVal->Type.Mem.cbBuf != pValFilter->Type.Mem.cbBuf
529 || memcmp(pVal->Type.Mem.pvBuf, pValFilter->Type.Mem.pvBuf,
530 pValFilter->Type.Mem.cbBuf))
531 return false;
532 break;
533 default:
534 AssertFailed();
535 return false;
536 }
537
538 return true;
539}
540
541
542/**
543 * Matches the given values against the filter values returning a flag whether they match.
544 *
545 * @returns Flag whether the given values match the filter.
546 * @param paVal Pointer to the array of values.
547 * @param cVals Number of values in the array.
548 * @param paValFilter Pointer to the filter values.
549 * @param cValsFilter Number of entries in the filter values.
550 */
551static bool dbgfR3FlowTraceRecordMatchValues(PCDBGFFLOWTRACEPROBEVAL paVal, uint32_t cVals,
552 PCDBGFFLOWTRACEPROBEVAL paValFilter, uint32_t cValsFilter)
553{
554 bool fMatch = false;
555
556 /*
557 * The order in which the filters and values are doesn't need to match but for every filter
558 * there should be at least one entry matching.
559 */
560 while ( cValsFilter-- > 0
561 && fMatch)
562 {
563 for (uint32_t i = 0; i < cVals; i++)
564 {
565 fMatch = dbgfR3FlowTraceRecordMatchSingleValue(&paVal[i], paValFilter);
566 if (fMatch)
567 break;
568 }
569 paValFilter++;
570 }
571
572 return fMatch;
573}
574
575
576/**
577 * Checks the given record against the given filter, returning whether the filter
578 * matches.
579 *
580 * @returns Flag whether the record matches the given filter.
581 * @param pRecord The record to check.
582 * @param pFilter The filter to check against.
583 */
584static bool dbgfR3FlowTraceRecordMatchSingleFilter(PDBGFFLOWTRACERECORDINT pRecord,
585 PDBGFFLOWTRACEREPORTFILTER pFilter)
586{
587 bool fMatch = false;
588
589 switch (pFilter->enmType)
590 {
591 case DBGFFLOWTRACEREPORTFILTERTYPE_SEQ_NUM:
592 {
593 if ( pRecord->u64SeqNo >= pFilter->Type.SeqNo.u64SeqNoFirst
594 && pRecord->u64SeqNo <= pFilter->Type.SeqNo.u64SeqNoLast)
595 fMatch = true;
596 break;
597 }
598 case DBGFFLOWTRACEREPORTFILTERTYPE_TIMESTAMP:
599 {
600 if ( pRecord->u64TsCollected >= pFilter->Type.Timestamp.u64TsFirst
601 && pRecord->u64TsCollected <= pFilter->Type.Timestamp.u64TsLast)
602 fMatch = true;
603 break;
604 }
605 case DBGFFLOWTRACEREPORTFILTERTYPE_ADDR:
606 {
607 if (dbgfR3FlowTraceAddrIntersect(&pRecord->AddrProbe,
608 &pFilter->Type.Addr.AddrStart,
609 &pFilter->Type.Addr.AddrLast))
610 fMatch = true;
611 break;
612 }
613 case DBGFFLOWTRACEREPORTFILTERTYPE_VMCPU_ID:
614 {
615 if ( pRecord->idCpu >= pFilter->Type.VCpuId.idCpuStart
616 && pRecord->idCpu <= pFilter->Type.VCpuId.idCpuLast)
617 fMatch = true;
618 break;
619 }
620 case DBGFFLOWTRACEREPORTFILTERTYPE_PROBE_DATA:
621 {
622 if (pFilter->Type.ProbeData.fValCmn)
623 {
624 if (pRecord->paValCmn)
625 {
626 PCDBGFFLOWTRACEPROBEINT pProbeCmn = pRecord->pProbeCmn;
627 AssertPtr(pProbeCmn);
628
629 fMatch = dbgfR3FlowTraceRecordMatchValues(pRecord->paValCmn, pProbeCmn->cEntries,
630 pFilter->Type.ProbeData.paVal,
631 pFilter->Type.ProbeData.cVals);
632 }
633 }
634 else
635 fMatch = dbgfR3FlowTraceRecordMatchValues(&pRecord->aVal[0], pRecord->pProbe->cEntries,
636 pFilter->Type.ProbeData.paVal, pFilter->Type.ProbeData.cVals);
637 break;
638 }
639 default:
640 AssertMsgFailed(("Invalid filter type %u!\n", pFilter->enmType));
641 }
642
643 return fMatch;
644}
645
646
647/**
648 * Checks the given record against the given filters.
649 *
650 * @returns Flag whether the record matches the filters.
651 * @param pRecord The record to check.
652 * @param paFilters Array of filters to check.
653 * @param cFilters Number of filters in the array.
654 * @param enmOp How the record should match against the filters.
655 */
656static bool dbgfR3FlowTraceDoesRecordMatchFilter(PDBGFFLOWTRACERECORDINT pRecord,
657 PDBGFFLOWTRACEREPORTFILTER paFilters,
658 uint32_t cFilters, DBGFFLOWTRACEREPORTFILTEROP enmOp)
659{
660 bool fMatch = false;
661
662 if (enmOp == DBGFFLOWTRACEREPORTFILTEROP_AND)
663 {
664 fMatch = true;
665 while (cFilters-- > 0)
666 {
667 if (!dbgfR3FlowTraceRecordMatchSingleFilter(pRecord, &paFilters[cFilters]))
668 {
669 fMatch = false;
670 break;
671 }
672 }
673 }
674 else if (enmOp == DBGFFLOWTRACEREPORTFILTEROP_OR)
675 {
676 while (cFilters-- > 0)
677 {
678 if (dbgfR3FlowTraceRecordMatchSingleFilter(pRecord, &paFilters[cFilters]))
679 {
680 fMatch = true;
681 break;
682 }
683 }
684 }
685 else
686 AssertMsgFailed(("Invalid filter operation %u!\n", enmOp));
687
688 return fMatch;
689}
690
691
692/**
693 * Collects all the data specified in the given probe.
694 *
695 * @returns Flag whether to enter the debugger.
696 * @param pUVM The user mode VM handle.
697 * @param idCpu The virtual CPU ID.
698 * @param pTraceMod The trace module instance.
699 * @param pAddrProbe Location of the probe, NULL if a common probe.
700 * @param pProbe The probe instance.
701 * @param pVal Pointer to the array of values to fill.
702 * @param pbBuf Poitner to the memory buffer holding additional data.
703 */
704static bool dbgfR3FlowTraceModProbeCollectData(PUVM pUVM, VMCPUID idCpu,
705 PDBGFFLOWTRACEMODINT pTraceMod,
706 PCDBGFADDRESS pAddrProbe,
707 PDBGFFLOWTRACEPROBEINT pProbe,
708 PDBGFFLOWTRACEPROBEVAL pVal, uint8_t *pbBuf)
709{
710 bool fDbgDefer = false;
711
712 for (uint32_t i = 0; i < pProbe->cEntries; i++)
713 {
714 int rc;
715 PDBGFFLOWTRACEPROBEENTRY pEntry = &pProbe->paEntries[i];
716
717 pVal->pProbeEntry = pEntry;
718
719 switch (pEntry->enmType)
720 {
721 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
722 rc = DBGFR3RegNmQuery(pUVM, idCpu, pEntry->Type.Reg.pszName,
723 &pVal->Type.Reg.Val, &pVal->Type.Reg.enmType);
724 AssertRC(rc);
725 pVal->Type.Reg.pszName = pEntry->Type.Reg.pszName;
726 break;
727 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
728 {
729 DBGFADDRESS Addr;
730 rc = dbgfR3FlowTraceModProbeResolveIndirectAddr(pUVM, idCpu, pEntry, &Addr);
731 if (RT_SUCCESS(rc))
732 {
733 pVal->Type.Mem.pvBuf = pbBuf;
734 pVal->Type.Mem.cbBuf = pEntry->Type.IndirectMem.cbMem;
735 pVal->Type.Mem.Addr = Addr;
736 rc = DBGFR3MemRead(pUVM, idCpu, &pVal->Type.Mem.Addr, pbBuf,
737 pVal->Type.Mem.cbBuf);
738 AssertRC(rc);
739 pbBuf += pVal->Type.Mem.cbBuf;
740 }
741 break;
742 }
743 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
744 pVal->Type.Mem.pvBuf = pbBuf;
745 pVal->Type.Mem.cbBuf = pEntry->Type.ConstMem.cbMem;
746 pVal->Type.Mem.Addr = pEntry->Type.ConstMem.AddrMem;
747 rc = DBGFR3MemRead(pUVM, idCpu, &pVal->Type.Mem.Addr, pbBuf,
748 pVal->Type.Mem.cbBuf);
749 AssertRC(rc);
750 pbBuf += pVal->Type.Mem.cbBuf;
751 break;
752 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
753 rc = pEntry->Type.Callback.pfnCallback(pUVM, idCpu, pTraceMod,
754 pAddrProbe, pProbe, pEntry,
755 pEntry->Type.Callback.pvUser);
756 break;
757 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
758 fDbgDefer = true;
759 break;
760 default:
761 AssertFailed();
762 }
763
764 pVal++;
765 }
766
767 return fDbgDefer;
768}
769
770
771/**
772 * @callback_method_impl{FNDBGFBPHIT}
773 */
774static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModProbeFiredWorker(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, uint16_t fFlags)
775{
776 RT_NOREF(pVM, hBp, pBpPub, fFlags);
777 LogFlowFunc(("pVM=%#p idCpu=%u pvUserBp=%#p hBp=%#x pBpPub=%p\n",
778 pVM, idCpu, pvUserBp, hBp, pBpPub));
779
780 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = (PDBGFFLOWTRACEMODPROBELOC)pvUserBp;
781 PDBGFFLOWTRACEPROBEINT pProbe = pProbeLoc->pProbe;
782 PDBGFFLOWTRACEMODINT pTraceMod = pProbeLoc->pTraceMod;
783 bool fDisabledModule = false;
784 bool fDbgDefer = false;
785
786 /* Check whether the trace module is still active and we are tracing the correct VCPU. */
787 if (ASMAtomicReadU32((volatile uint32_t *)&pTraceMod->enmState) != DBGFFLOWTRACEMODSTATE_ENABLED
788 || ( idCpu != pTraceMod->idCpu
789 && pTraceMod->idCpu != VMCPUID_ANY))
790 return VINF_SUCCESS;
791
792 if ( pTraceMod->fLimit
793 && ASMAtomicReadU32(&pTraceMod->cHitsLeft))
794 {
795 uint32_t cHitsLeftNew = ASMAtomicDecU32(&pTraceMod->cHitsLeft);
796 if (cHitsLeftNew > cHitsLeftNew + 1) /* Underflow => reached the limit. */
797 {
798 ASMAtomicIncU32(&pTraceMod->cHitsLeft);
799 return VINF_SUCCESS;
800 }
801
802 if (!cHitsLeftNew)
803 {
804 /* We got the last record, disable the trace module. */
805 fDisabledModule = ASMAtomicCmpXchgU32((volatile uint32_t *)&pTraceMod->enmState, DBGFFLOWTRACEMODSTATE_CREATED,
806 DBGFFLOWTRACEMODSTATE_ENABLED);
807 }
808 }
809
810 uint8_t *pbBuf = NULL;
811 uint8_t *pbBufCmn = NULL;
812 PDBGFFLOWTRACERECORDINT pRecord = dbgfR3FlowTraceRecordCreate(pProbeLoc, idCpu, &pbBuf, &pbBufCmn);
813 if (pRecord)
814 {
815 fDbgDefer = dbgfR3FlowTraceModProbeCollectData(pTraceMod->pUVM, idCpu, pTraceMod, &pProbeLoc->AddrProbe, pProbe,
816 &pRecord->aVal[0], pbBuf);
817 if (pTraceMod->pProbeCmn)
818 fDbgDefer = dbgfR3FlowTraceModProbeCollectData(pTraceMod->pUVM, idCpu, pTraceMod, NULL, pTraceMod->pProbeCmn,
819 pRecord->paValCmn, pbBufCmn);
820
821 RTSemFastMutexRequest(pTraceMod->hMtx);
822 uint32_t cRecordsNew = ASMAtomicIncU32(&pTraceMod->cRecords);
823 RTListAppend(&pTraceMod->LstRecords, &pRecord->NdRecord);
824 if ( (cRecordsNew > pTraceMod->cRecordsMax)
825 && pTraceMod->cRecordsMax > 0)
826 {
827 /* Get the first record and destroy it. */
828 pRecord = RTListRemoveFirst(&pTraceMod->LstRecords, DBGFFLOWTRACERECORDINT, NdRecord);
829 AssertPtr(pRecord);
830 DBGFR3FlowTraceRecordRelease(pRecord);
831 ASMAtomicDecU32(&pTraceMod->cRecords);
832 }
833 RTSemFastMutexRelease(pTraceMod->hMtx);
834 }
835
836 if (fDisabledModule)
837 {
838 int rc = DBGFR3FlowTraceModDisable(pTraceMod);
839 AssertRC(rc);
840 }
841
842 return fDbgDefer ? VINF_DBGF_BP_HALT : VINF_SUCCESS;
843}
844
845
846/**
847 * Worker for DBGFR3FlowTraceModEnable(), doing the work in an EMT rendezvous point to
848 * ensure no probe is hit in an inconsistent state.
849 *
850 * @returns Strict VBox status code.
851 * @param pVM The VM instance data.
852 * @param pVCpu The virtual CPU we execute on.
853 * @param pvUser Opaque user data.
854 */
855static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModEnableWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
856{
857 RT_NOREF2(pVM, pVCpu);
858 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)pvUser;
859 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = NULL;
860 int rc = VINF_SUCCESS;
861
862 pThis->enmState = DBGFFLOWTRACEMODSTATE_ENABLED;
863
864 RTListForEach(&pThis->LstProbes, pProbeLoc, DBGFFLOWTRACEMODPROBELOC, NdProbes)
865 {
866 uint16_t fBpFlags = DBGF_BP_F_ENABLED;
867
868 if (pProbeLoc->fFlags & DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC)
869 fBpFlags |= DBGF_BP_F_HIT_EXEC_BEFORE;
870 if (pProbeLoc->fFlags & DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC)
871 fBpFlags |= DBGF_BP_F_HIT_EXEC_AFTER;
872
873 rc = DBGFR3BpSetInt3Ex(pThis->pUVM, pThis->hBpOwner, pProbeLoc,
874 0 /*idSrcCpu*/, &pProbeLoc->AddrProbe, fBpFlags,
875 0 /*iHitTrigger*/, ~0ULL /*iHitDisable*/, &pProbeLoc->hBp);
876 if (RT_FAILURE(rc))
877 break;
878 }
879
880 if (RT_FAILURE(rc))
881 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
882
883 return rc;
884}
885
886
887/**
888 * Worker for DBGFR3FlowTraceModDisable(), doing the work in an EMT rendezvous point to
889 * ensure no probe is hit in an inconsistent state.
890 *
891 * @returns Struct VBox status code.
892 * @param pVM The VM instance data.
893 * @param pVCpu The virtual CPU we execute on.
894 * @param pvUser Opaque user data.
895 */
896static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModDisableWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
897{
898 RT_NOREF2(pVM, pVCpu);
899 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)pvUser;
900 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = NULL;
901 int rc = VINF_SUCCESS;
902
903 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
904
905 RTListForEach(&pThis->LstProbes, pProbeLoc, DBGFFLOWTRACEMODPROBELOC, NdProbes)
906 {
907 rc = DBGFR3BpClear(pThis->pUVM, pProbeLoc->hBp);
908 AssertRC(rc);
909 }
910
911 return rc;
912}
913
914
915/**
916 * Checks whether both addresses are equal.
917 *
918 * @returns true if both addresses point to the same location, false otherwise.
919 * @param pAddr1 First address.
920 * @param pAddr2 Second address.
921 */
922static bool dbgfR3FlowTraceAddrEqual(PCDBGFADDRESS pAddr1, PCDBGFADDRESS pAddr2)
923{
924 return pAddr1->Sel == pAddr2->Sel
925 && pAddr1->off == pAddr2->off;
926}
927
928
929/**
930 * Returns the probe location pointer at the given address for the given trace module.
931 *
932 * @returns Pointer to the probe location or NULL if there is no probe at the given location.
933 * @param pThis The flow trace module instance data.
934 * @param pAddrProbe Address of the probe to check.
935 */
936static PDBGFFLOWTRACEMODPROBELOC dbgfR3TraceModGetProbeLocAtAddr(PDBGFFLOWTRACEMODINT pThis, PCDBGFADDRESS pAddrProbe)
937{
938 RTSemFastMutexRequest(pThis->hMtx);
939
940 PDBGFFLOWTRACEMODPROBELOC pIt;
941 RTListForEach(&pThis->LstProbes, pIt, DBGFFLOWTRACEMODPROBELOC, NdProbes)
942 {
943 if (dbgfR3FlowTraceAddrEqual(&pIt->AddrProbe, pAddrProbe))
944 {
945 RTSemFastMutexRelease(pThis->hMtx);
946 return pIt;
947 }
948 }
949 RTSemFastMutexRelease(pThis->hMtx);
950 return NULL;
951}
952
953
954/**
955 * Cleans up any allocated resources for each entry in the given probe for the given range.
956 *
957 * @returns nothing.
958 * @param pProbe The probe instance.
959 * @param idxStart Start index to clean up.
960 * @param cEntries How many entries to clean up.
961 */
962static void dbgfR3ProbeEntryCleanup(PDBGFFLOWTRACEPROBEINT pProbe, uint32_t idxStart, uint32_t cEntries)
963{
964 AssertReturnVoid(pProbe->cEntriesMax >= idxStart + cEntries);
965
966 for (uint32_t i = idxStart; i < idxStart + cEntries; i++)
967 {
968 PDBGFFLOWTRACEPROBEENTRY pEntry = &pProbe->paEntries[i];
969
970 switch (pEntry->enmType)
971 {
972 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
973 if (pEntry->Type.Reg.pszName)
974 MMR3HeapFree((void *)pEntry->Type.Reg.pszName);
975 pEntry->Type.Reg.pszName = NULL;
976 break;
977 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
978 pEntry->Type.ConstMem.cbMem = 0;
979 break;
980 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
981 pEntry->Type.IndirectMem.uScale = 0;
982 pEntry->Type.IndirectMem.cbMem = 0;
983 if (pEntry->Type.IndirectMem.RegBase.pszName)
984 MMR3HeapFree((void *)pEntry->Type.IndirectMem.RegBase.pszName);
985 if (pEntry->Type.IndirectMem.RegIndex.pszName)
986 MMR3HeapFree((void *)pEntry->Type.IndirectMem.RegIndex.pszName);
987 pEntry->Type.IndirectMem.RegBase.pszName = NULL;
988 pEntry->Type.IndirectMem.RegIndex.pszName = NULL;
989 break;
990 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
991 pEntry->Type.Callback.pfnCallback = NULL;
992 pEntry->Type.Callback.pvUser = NULL;
993 break;
994 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
995 break;
996 default:
997 AssertFailed();
998 }
999 }
1000}
1001
1002
1003/**
1004 * Destroys the given flow trace probe freeing all allocated resources.
1005 *
1006 * @returns nothing.
1007 * @param pProbe The flow trace probe instance data.
1008 */
1009static void dbgfR3FlowTraceProbeDestroy(PDBGFFLOWTRACEPROBEINT pProbe)
1010{
1011 dbgfR3ProbeEntryCleanup(pProbe, 0, pProbe->cEntries);
1012 MMR3HeapFree(pProbe->paEntries);
1013 MMR3HeapFree(pProbe);
1014}
1015
1016
1017/**
1018 * Ensures that the given probe has the given amount of additional entries available,
1019 * increasing the size if necessary.
1020 *
1021 * @returns VBox status code.
1022 * @retval VERR_NO_MEMORY if increasing the size failed due to an out of memory condition.
1023 * @param pProbe The probe insatnce.
1024 * @param cEntriesAdd Number of additional entries required.
1025 */
1026static int dbgfR3ProbeEnsureSize(PDBGFFLOWTRACEPROBEINT pProbe, uint32_t cEntriesAdd)
1027{
1028 uint32_t cEntriesNew = pProbe->cEntries + cEntriesAdd;
1029 int rc = VINF_SUCCESS;
1030
1031 if (pProbe->cEntriesMax < cEntriesNew)
1032 {
1033 PDBGFFLOWTRACEPROBEENTRY paEntriesNew;
1034 if (!pProbe->cEntriesMax)
1035 paEntriesNew = (PDBGFFLOWTRACEPROBEENTRY)MMR3HeapAllocZU(pProbe->pUVM, MM_TAG_DBGF_FLOWTRACE,
1036 cEntriesNew * sizeof(DBGFFLOWTRACEPROBEENTRY));
1037 else
1038 paEntriesNew = (PDBGFFLOWTRACEPROBEENTRY)MMR3HeapRealloc(pProbe->paEntries,
1039 cEntriesNew * sizeof(DBGFFLOWTRACEPROBEENTRY));
1040 if (RT_LIKELY(paEntriesNew))
1041 {
1042 pProbe->paEntries = paEntriesNew;
1043 pProbe->cEntriesMax = cEntriesNew;
1044 }
1045 else
1046 rc = VERR_NO_MEMORY;
1047 }
1048
1049 return rc;
1050}
1051
1052
1053/**
1054 * Duplicates a probe registry entry.
1055 * @returns VBox status code.
1056 * @param pUVM The usermode VM handle.
1057 * @param pDst Where to copy the entry to.
1058 * @param pSrc What to copy.
1059 */
1060static int dbgfR3ProbeEntryRegDup(PUVM pUVM, PDBGFFLOWTRACEPROBEENTRYREG pDst, PCDBGFFLOWTRACEPROBEENTRYREG pSrc)
1061{
1062 int rc = VINF_SUCCESS;
1063
1064 pDst->enmType = pSrc->enmType;
1065 pDst->pszName = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_FLOWTRACE, pSrc->pszName);
1066 if (!pDst->pszName)
1067 rc = VERR_NO_MEMORY;
1068
1069 return rc;
1070}
1071
1072
1073/**
1074 * Duplicates a given probe entry in the given destination doing a deep copy (strings are duplicated).
1075 *
1076 * @returns VBox status code.
1077 * @param pUVM The usermode VM handle.
1078 * @param pDst Where to copy the entry to.
1079 * @param pSrc What to copy.
1080 */
1081static int dbgfR3ProbeEntryDup(PUVM pUVM, PDBGFFLOWTRACEPROBEENTRY pDst, PCDBGFFLOWTRACEPROBEENTRY pSrc)
1082{
1083 int rc = VINF_SUCCESS;
1084
1085 pDst->enmType = pSrc->enmType;
1086 pDst->pszDesc = NULL;
1087 if (pSrc->pszDesc)
1088 {
1089 pDst->pszDesc = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_FLOWTRACE, pSrc->pszDesc);
1090 if (!pDst->pszDesc)
1091 rc = VERR_NO_MEMORY;
1092 }
1093
1094 if (RT_SUCCESS(rc))
1095 {
1096 switch (pDst->enmType)
1097 {
1098 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
1099 rc = dbgfR3ProbeEntryRegDup(pUVM, &pDst->Type.Reg, &pSrc->Type.Reg);
1100 break;
1101 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
1102 pDst->Type.ConstMem.AddrMem = pSrc->Type.ConstMem.AddrMem;
1103 pDst->Type.ConstMem.cbMem = pSrc->Type.ConstMem.cbMem;
1104 break;
1105 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
1106 pDst->Type.IndirectMem.uScale = pSrc->Type.IndirectMem.uScale;
1107 pDst->Type.IndirectMem.cbMem = pSrc->Type.IndirectMem.cbMem;
1108 pDst->Type.IndirectMem.iOffset = pSrc->Type.IndirectMem.iOffset;
1109 rc = dbgfR3ProbeEntryRegDup(pUVM, &pDst->Type.IndirectMem.RegBase, &pSrc->Type.IndirectMem.RegBase);
1110 if ( RT_SUCCESS(rc)
1111 && pDst->Type.IndirectMem.RegIndex.pszName)
1112 {
1113 rc = dbgfR3ProbeEntryRegDup(pUVM, &pDst->Type.IndirectMem.RegIndex, &pSrc->Type.IndirectMem.RegIndex);
1114 if (RT_FAILURE(rc))
1115 MMR3HeapFree((void *)pDst->Type.IndirectMem.RegBase.pszName);
1116 }
1117 break;
1118 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
1119 pDst->Type.Callback.pfnCallback = pSrc->Type.Callback.pfnCallback;
1120 pDst->Type.Callback.pvUser = pSrc->Type.Callback.pvUser;
1121 break;
1122 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
1123 break;
1124 default:
1125 rc = VERR_INVALID_PARAMETER;
1126 }
1127 }
1128
1129 if ( RT_FAILURE(rc)
1130 && pDst->pszDesc)
1131 {
1132 MMR3HeapFree((void *)pDst->pszDesc);
1133 pDst->pszDesc = NULL;
1134 }
1135
1136 return rc;
1137}
1138
1139
1140/**
1141 * Recalculates the size occupied by the data of this probe for each invocation.
1142 *
1143 * @returns nothing.
1144 * @param pProbe The probe instance.
1145 */
1146static void dbgfR3ProbeRecalcSize(PDBGFFLOWTRACEPROBEINT pProbe)
1147{
1148 size_t cbProbe = 0;
1149
1150 for (uint32_t i = 0; i < pProbe->cEntries; i++)
1151 {
1152 PDBGFFLOWTRACEPROBEENTRY pEntry = &pProbe->paEntries[i];
1153
1154 cbProbe += sizeof(DBGFFLOWTRACEPROBEVAL);
1155
1156 switch (pEntry->enmType)
1157 {
1158 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
1159 cbProbe += pEntry->Type.ConstMem.cbMem;
1160 break;
1161 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
1162 cbProbe += pEntry->Type.IndirectMem.cbMem;
1163 break;
1164 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
1165 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
1166 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
1167 break;
1168 default:
1169 AssertFailed();
1170 }
1171 }
1172
1173 pProbe->cbProbe = cbProbe;
1174}
1175
1176
1177/**
1178 * Creates a new empty flow trace module.
1179 *
1180 * @returns VBox status code.
1181 * @param pUVM The usermode VM handle.
1182 * @param idCpu CPU ID the module is for, use VMCPUID_ANY for any CPU.
1183 * @param hFlowTraceProbeCommon Optional probe handle of data to capture regardless of the actual
1184 * probe.
1185 * @param phFlowTraceMod Where to store the handle to the created module on success.
1186 */
1187VMMR3DECL(int) DBGFR3FlowTraceModCreate(PUVM pUVM, VMCPUID idCpu,
1188 DBGFFLOWTRACEPROBE hFlowTraceProbeCommon,
1189 PDBGFFLOWTRACEMOD phFlowTraceMod)
1190{
1191 int rc = VINF_SUCCESS;
1192 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_FLOWTRACE,
1193 sizeof(DBGFFLOWTRACEMODINT));
1194 if (RT_LIKELY(pThis))
1195 {
1196 pThis->cRefs = 1;
1197 pThis->pUVM = pUVM;
1198 pThis->idCpu = idCpu;
1199 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
1200 pThis->u64SeqNoNext = 0;
1201 pThis->cHitsLeft = 0;
1202 pThis->cRecordsMax = 0;
1203 pThis->cRecords = 0;
1204 pThis->cProbes = 0;
1205 RTListInit(&pThis->LstProbes);
1206 RTListInit(&pThis->LstRecords);
1207
1208 rc = RTSemFastMutexCreate(&pThis->hMtx);
1209 if (RT_SUCCESS(rc))
1210 {
1211 rc = DBGFR3BpOwnerCreate(pUVM, dbgfR3FlowTraceModProbeFiredWorker, NULL /*pfnBpIoHit*/, &pThis->hBpOwner);
1212 if (RT_SUCCESS(rc))
1213 {
1214 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbeCommon;
1215 if (pProbe)
1216 {
1217 DBGFR3FlowTraceProbeRetain(pProbe);
1218 pThis->pProbeCmn = pProbe;
1219 }
1220 }
1221
1222 *phFlowTraceMod = pThis;
1223 }
1224
1225 if (RT_FAILURE(rc))
1226 MMR3HeapFree(pThis);
1227 }
1228 else
1229 rc = VERR_NO_MEMORY;
1230
1231 return rc;
1232}
1233
1234
1235/**
1236 * Create a new flow trace module from the given control flow graph adding the given probes
1237 * at the entries, exits and branches.
1238 *
1239 * @returns VBox status code.
1240 * @param pUVM The usermode VM handle.
1241 * @param idCpu CPU ID the module is for, use VMCPUID_ANY for any CPU.
1242 * @param hFlow Control flow graph handle to use.
1243 * @param hFlowTraceProbeCommon Optional probe handle of data to capture regardless of the actual
1244 * probe.
1245 * @param hFlowTraceProbeEntry Probe handle to use for all entry blocks.
1246 * @param hFlowTraceProbeRegular Probe handle to use for all branches.
1247 * @param hFlowTraceProbeExit Probe handle to use for all exits.
1248 * @param phFlowTraceMod Where to store the handle to the created module on success.
1249 */
1250VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow,
1251 DBGFFLOWTRACEPROBE hFlowTraceProbeCommon,
1252 DBGFFLOWTRACEPROBE hFlowTraceProbeEntry,
1253 DBGFFLOWTRACEPROBE hFlowTraceProbeRegular,
1254 DBGFFLOWTRACEPROBE hFlowTraceProbeExit,
1255 PDBGFFLOWTRACEMOD phFlowTraceMod)
1256{
1257 DBGFFLOWIT hFlowIt;
1258 int rc = DBGFR3FlowItCreate(hFlow, DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST, &hFlowIt);
1259 if (RT_SUCCESS(rc))
1260 {
1261 DBGFFLOWTRACEMOD hFlowTraceMod;
1262 rc = DBGFR3FlowTraceModCreate(pUVM, idCpu, hFlowTraceProbeCommon, &hFlowTraceMod);
1263 if (RT_SUCCESS(rc))
1264 {
1265 DBGFFLOWBB hFlowBb = DBGFR3FlowItNext(hFlowIt);
1266 while (hFlowBb && RT_SUCCESS(rc))
1267 {
1268 uint32_t fFlags = DBGFR3FlowBbGetFlags(hFlowBb);
1269
1270 if (!(fFlags & (DBGF_FLOW_BB_F_EMPTY | DBGF_FLOW_BB_F_INCOMPLETE_ERR)))
1271 {
1272 DBGFADDRESS AddrInstr;
1273
1274 if (fFlags & DBGF_FLOW_BB_F_ENTRY)
1275 {
1276 rc = DBGFR3FlowBbQueryInstr(hFlowBb, 0, &AddrInstr, NULL, NULL);
1277 AssertRC(rc);
1278
1279 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeEntry,
1280 DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC);
1281 }
1282 else
1283 {
1284 DBGFFLOWBBENDTYPE enmType = DBGFR3FlowBbGetType(hFlowBb);
1285 uint32_t cInstr = enmType == DBGFFLOWBBENDTYPE_EXIT ? DBGFR3FlowBbGetInstrCount(hFlowBb) - 1 : 0;
1286 rc = DBGFR3FlowBbQueryInstr(hFlowBb, cInstr, &AddrInstr, NULL, NULL);
1287 if (RT_SUCCESS(rc))
1288 {
1289 if (enmType == DBGFFLOWBBENDTYPE_EXIT)
1290 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeExit,
1291 DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC);
1292 else
1293 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeRegular,
1294 DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC);
1295 }
1296 }
1297 }
1298
1299 hFlowBb = DBGFR3FlowItNext(hFlowIt);
1300 }
1301
1302 if (RT_FAILURE(rc))
1303 DBGFR3FlowTraceModRelease(hFlowTraceMod);
1304 else
1305 *phFlowTraceMod = hFlowTraceMod;
1306 }
1307
1308 DBGFR3FlowItDestroy(hFlowIt);
1309 }
1310
1311 return rc;
1312}
1313
1314
1315/**
1316 * Retain a reference to the given flow trace module.
1317 *
1318 * @returns New reference count.
1319 * @param hFlowTraceMod Flow trace module handle.
1320 */
1321VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod)
1322{
1323 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1324 AssertPtrReturn(pThis, UINT32_MAX);
1325
1326 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1327 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1328 return cRefs;
1329}
1330
1331
1332/**
1333 * Release a reference of the given flow trace module.
1334 *
1335 * @returns New reference count, on 0 the module is destroyed and all containing records
1336 * are deleted.
1337 * @param hFlowTraceMod Flow trace module handle.
1338 */
1339VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod)
1340{
1341 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1342 if (!pThis)
1343 return 0;
1344 AssertPtrReturn(pThis, UINT32_MAX);
1345
1346 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1347 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1348 if (cRefs == 0)
1349 dbgfR3FlowTraceModDestroy(pThis);
1350 return cRefs;
1351}
1352
1353
1354/**
1355 * Enables and arms all probes in the given flow trace module.
1356 *
1357 * @returns VBox status code.
1358 * @param hFlowTraceMod Flow trace module handle.
1359 * @param cHits Number of hits inside this module until the module is disabled
1360 * automatically, 0 if not to disable automatically.
1361 * @param cRecordsMax Maximum number of records to keep until the oldest is evicted.
1362 */
1363VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax)
1364{
1365 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1366 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1367 AssertReturn(pThis->cProbes > 0, VERR_INVALID_STATE);
1368 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_CREATED, VERR_INVALID_STATE);
1369
1370 pThis->cHitsLeft = cHits;
1371 pThis->cRecordsMax = cRecordsMax;
1372
1373 return VMMR3EmtRendezvous(pThis->pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
1374 dbgfR3FlowTraceModEnableWorker, pThis);
1375}
1376
1377
1378/**
1379 * Disables all probes in the given flow trace module.
1380 *
1381 * @returns VBox status code.
1382 * @param hFlowTraceMod Flow trace module handle.
1383 */
1384VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod)
1385{
1386 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1387 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1388 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_ENABLED, VERR_INVALID_STATE);
1389
1390 return VMMR3EmtRendezvous(pThis->pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
1391 dbgfR3FlowTraceModDisableWorker, pThis);
1392}
1393
1394
1395/**
1396 * Returns a report containing all existing records in the given flow trace module.
1397 *
1398 * @returns VBox status code.
1399 * @param hFlowTraceMod Flow trace module handle.
1400 * @param phFlowTraceReport Where to store the flow trace report handle on success.
1401 */
1402VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod,
1403 PDBGFFLOWTRACEREPORT phFlowTraceReport)
1404{
1405 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1406 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1407 AssertPtrReturn(phFlowTraceReport, VERR_INVALID_POINTER);
1408
1409 /** @todo Locking. */
1410 int rc = VINF_SUCCESS;
1411 PDBGFFLOWTRACEREPORTINT pReport = dbgfR3FlowTraceReportCreate(pThis->pUVM, pThis->cRecords);
1412 if (RT_LIKELY(pReport))
1413 {
1414 PDBGFFLOWTRACERECORDINT pIt;
1415 uint32_t idx = 0;
1416
1417 RTSemFastMutexRequest(pThis->hMtx);
1418 RTListForEach(&pThis->LstRecords, pIt, DBGFFLOWTRACERECORDINT, NdRecord)
1419 {
1420 DBGFR3FlowTraceRecordRetain(pIt);
1421 pReport->apRec[idx++] = pIt;
1422 }
1423 RTSemFastMutexRelease(pThis->hMtx);
1424
1425 *phFlowTraceReport = pReport;
1426 }
1427 else
1428 rc = VERR_NO_MEMORY;
1429
1430 return rc;
1431}
1432
1433
1434/**
1435 * Clears all records contained in the flow trace module.
1436 *
1437 * @returns VBox status code.
1438 * @param hFlowTraceMod Flow trace module handle.
1439 */
1440VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod)
1441{
1442 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1443 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1444
1445 RTSemFastMutexRequest(pThis->hMtx);
1446 RTLISTANCHOR LstTmp;
1447 RTListMove(&LstTmp, &pThis->LstRecords);
1448 ASMAtomicWriteU32(&pThis->cRecords, 0);
1449 RTSemFastMutexRelease(pThis->hMtx);
1450
1451 PDBGFFLOWTRACERECORDINT pIt, pItNext;
1452 RTListForEachSafe(&LstTmp, pIt, pItNext, DBGFFLOWTRACERECORDINT, NdRecord)
1453 {
1454 RTListNodeRemove(&pIt->NdRecord);
1455 DBGFR3FlowTraceRecordRelease(pIt);
1456 }
1457
1458 return VINF_SUCCESS;
1459}
1460
1461
1462/**
1463 * Adds a new probe to the given flow trace module.
1464 *
1465 * @returns VBox status code
1466 * @retval VERR_INVALID_STATE if the probe is active or was destroyed already.
1467 * @retval VERR_ALREADY_EXISTS if there is already a probe at the specified location.
1468 * @param hFlowTraceMod Flow trace module handle.
1469 * @param pAddrProbe Guest address to insert the probe at.
1470 * @param hFlowTraceProbe The handle of the probe to insert.
1471 * @param fFlags Combination of DBGF_FLOW_TRACE_PROBE_ADD_F_*.
1472 */
1473VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe,
1474 DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags)
1475{
1476 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1477 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1478 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1479 AssertPtrReturn(pProbe, VERR_INVALID_HANDLE);
1480 AssertPtrReturn(pAddrProbe, VERR_INVALID_POINTER);
1481 AssertReturn(!(fFlags & ~DBGF_FLOW_TRACE_PROBE_ADD_F_VALID_MASK), VERR_INVALID_PARAMETER);
1482 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_CREATED, VERR_INVALID_STATE);
1483
1484 int rc = VINF_SUCCESS;
1485 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = dbgfR3TraceModGetProbeLocAtAddr(pThis, pAddrProbe);
1486 if (!pProbeLoc)
1487 {
1488 pProbeLoc = (PDBGFFLOWTRACEMODPROBELOC)MMR3HeapAllocZU(pThis->pUVM, MM_TAG_DBGF_FLOWTRACE,
1489 sizeof(DBGFFLOWTRACEMODPROBELOC));
1490 if (RT_LIKELY(pProbeLoc))
1491 {
1492 pProbeLoc->pTraceMod = pThis;
1493 pProbeLoc->pProbe = pProbe;
1494 pProbeLoc->AddrProbe = *pAddrProbe;
1495 pProbeLoc->fFlags = fFlags;
1496 ASMAtomicIncU32(&pProbe->cRefs);
1497 ASMAtomicIncU32(&pProbe->cRefsMod);
1498 RTSemFastMutexRequest(pThis->hMtx);
1499 RTListAppend(&pThis->LstProbes, &pProbeLoc->NdProbes);
1500 pThis->cProbes++;
1501 RTSemFastMutexRelease(pThis->hMtx);
1502 }
1503 else
1504 rc = VERR_NO_MEMORY;
1505 }
1506 else
1507 rc = VERR_ALREADY_EXISTS;
1508
1509 return rc;
1510}
1511
1512
1513/**
1514 * Creates a new empty probe.
1515 *
1516 * @returns VBox status code.
1517 * @param pUVM The usermode VM handle.
1518 * @param pszDescr Description of the probe, optional.
1519 * @param phFlowTraceProbe Where to store the probe handle on success.
1520 */
1521VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe)
1522{
1523 int rc = VINF_SUCCESS;
1524 PDBGFFLOWTRACEPROBEINT pProbe = (PDBGFFLOWTRACEPROBEINT)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_FLOWTRACE,
1525 sizeof(DBGFFLOWTRACEPROBEINT));
1526 if (RT_LIKELY(pProbe))
1527 {
1528 pProbe->cRefs = 1;
1529 pProbe->cRefsMod = 0;
1530 pProbe->pUVM = pUVM;
1531 pProbe->cbProbe = 0;
1532 pProbe->cEntries = 0;
1533 pProbe->cEntriesMax = 0;
1534 pProbe->paEntries = NULL;
1535 pProbe->pszDescr = NULL;
1536 if (pszDescr)
1537 {
1538 pProbe->pszDescr = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_FLOWTRACE, pszDescr);
1539 if (!pProbe->pszDescr)
1540 {
1541 MMR3HeapFree(pProbe);
1542 rc = VERR_NO_MEMORY;
1543 }
1544 }
1545
1546 if (RT_SUCCESS(rc))
1547 *phFlowTraceProbe = pProbe;
1548 }
1549 else
1550 rc = VERR_NO_MEMORY;
1551
1552 return rc;
1553}
1554
1555
1556/**
1557 * Retains a reference to the probe.
1558 *
1559 * @returns New reference count.
1560 * @param hFlowTraceProbe Flow trace probe handle.
1561 */
1562VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe)
1563{
1564 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1565 AssertPtrReturn(pProbe, UINT32_MAX);
1566
1567 uint32_t cRefs = ASMAtomicIncU32(&pProbe->cRefs);
1568 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pProbe));
1569 return cRefs;
1570}
1571
1572
1573/**
1574 * Release a probe reference.
1575 *
1576 * @returns New reference count, on 0 the probe is destroyed.
1577 * @param hFlowTraceProbe Flow trace probe handle.
1578 */
1579VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe)
1580{
1581 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1582 if (!pProbe)
1583 return 0;
1584 AssertPtrReturn(pProbe, UINT32_MAX);
1585
1586 uint32_t cRefs = ASMAtomicDecU32(&pProbe->cRefs);
1587 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pProbe));
1588 if (cRefs == 0)
1589 dbgfR3FlowTraceProbeDestroy(pProbe);
1590 return cRefs;
1591}
1592
1593
1594/**
1595 * Adds new data to log in the given probe.
1596 *
1597 * @returns VBox status code.
1598 * @retval VERR_INVALID_STATE if the probe is already part of a trace module and it is not
1599 * possible to add new entries at this point.
1600 * @param hFlowTraceProbe Flow trace probe handle.
1601 * @param paEntries Pointer to the array of entry descriptors.
1602 * @param cEntries Number of entries in the array.
1603 */
1604VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe,
1605 PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries)
1606{
1607 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1608 AssertPtrReturn(pProbe, VERR_INVALID_HANDLE);
1609 AssertPtrReturn(paEntries, VERR_INVALID_POINTER);
1610 AssertReturn(cEntries > 0, VERR_INVALID_PARAMETER);
1611 AssertReturn(!pProbe->cRefsMod, VERR_INVALID_STATE);
1612
1613 int rc = dbgfR3ProbeEnsureSize(pProbe, cEntries);
1614 if (RT_SUCCESS(rc))
1615 {
1616 uint32_t idxEntry;
1617
1618 for (idxEntry = 0; idxEntry < cEntries && RT_SUCCESS(rc); idxEntry++)
1619 {
1620 PCDBGFFLOWTRACEPROBEENTRY pEntry = &paEntries[idxEntry];
1621 PDBGFFLOWTRACEPROBEENTRY pProbeEntry = &pProbe->paEntries[pProbe->cEntries + idxEntry];
1622
1623 rc = dbgfR3ProbeEntryDup(pProbe->pUVM, pProbeEntry, pEntry);
1624 }
1625
1626 if (RT_FAILURE(rc))
1627 dbgfR3ProbeEntryCleanup(pProbe, pProbe->cEntries, idxEntry + 1);
1628 else
1629 {
1630 pProbe->cEntries += cEntries;
1631 dbgfR3ProbeRecalcSize(pProbe);
1632 }
1633 }
1634
1635 return rc;
1636}
1637
1638
1639/**
1640 * Retains a reference to the given flow trace report.
1641 *
1642 * @returns New reference count.
1643 * @param hFlowTraceReport Flow trace report handle.
1644 */
1645VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport)
1646{
1647 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1648 AssertPtrReturn(pReport, UINT32_MAX);
1649
1650 uint32_t cRefs = ASMAtomicIncU32(&pReport->cRefs);
1651 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pReport));
1652 return cRefs;
1653}
1654
1655
1656/**
1657 * Releases a reference of the given flow trace report.
1658 *
1659 * @returns New reference count, on 0 the report is destroyed.
1660 * @param hFlowTraceReport Flow trace report handle.
1661 */
1662VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport)
1663{
1664 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1665 if (!pReport)
1666 return 0;
1667 AssertPtrReturn(pReport, UINT32_MAX);
1668
1669 uint32_t cRefs = ASMAtomicDecU32(&pReport->cRefs);
1670 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pReport));
1671 if (cRefs == 0)
1672 dbgfR3FlowTraceReportDestroy(pReport);
1673 return cRefs;
1674}
1675
1676
1677/**
1678 * Returns the number of records in the given report.
1679 *
1680 * @returns Number of records.
1681 * @param hFlowTraceReport Flow trace report handle.
1682 */
1683VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport)
1684{
1685 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1686 AssertPtrReturn(pReport, 0);
1687
1688 return pReport->cRecords;
1689}
1690
1691
1692/**
1693 * Queries the specified record contained in the given report.
1694 *
1695 * @returns VBox status code.
1696 * @param hFlowTraceReport Flow trace report handle.
1697 * @param idxRec The record index to query.
1698 * @param phFlowTraceRec Where to store the retained handle of the record on success.
1699 */
1700VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec)
1701{
1702 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1703 AssertPtrReturn(pReport, 0);
1704 AssertPtrReturn(phFlowTraceRec, VERR_INVALID_POINTER);
1705 AssertReturn(idxRec < pReport->cRecords, VERR_INVALID_PARAMETER);
1706
1707 DBGFR3FlowTraceRecordRetain(pReport->apRec[idxRec]);
1708 *phFlowTraceRec = pReport->apRec[idxRec];
1709 return VINF_SUCCESS;
1710}
1711
1712
1713/**
1714 * Filters the given flow trace report by the given criterias and returns a filtered report.
1715 *
1716 * @returns VBox status code.
1717 * @param hFlowTraceReport Flow trace report handle.
1718 * @param fFlags Combination of DBGF_FLOW_TRACE_REPORT_FILTER_F_*.
1719 * @param paFilters Pointer to the array of filters.
1720 * @param cFilters Number of entries in the filter array.
1721 * @param enmOp How the filters are connected to each other.
1722 * @param phFlowTraceReportFiltered Where to return the handle to the report containing the
1723 * filtered records on success.
1724 */
1725VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags,
1726 PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters,
1727 DBGFFLOWTRACEREPORTFILTEROP enmOp,
1728 PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered)
1729{
1730 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1731 AssertPtrReturn(pReport, VERR_INVALID_HANDLE);
1732 AssertReturn(!(fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_VALID), VERR_INVALID_PARAMETER);
1733 AssertPtrReturn(paFilters, VERR_INVALID_POINTER);
1734 AssertReturn(cFilters > 0, VERR_INVALID_PARAMETER);
1735 AssertReturn(enmOp > DBGFFLOWTRACEREPORTFILTEROP_INVALID && enmOp <= DBGFFLOWTRACEREPORTFILTEROP_OR,
1736 VERR_INVALID_PARAMETER);
1737 AssertPtrReturn(phFlowTraceReportFiltered, VERR_INVALID_POINTER);
1738
1739 int rc = VINF_SUCCESS;
1740 PDBGFFLOWTRACEREPORTINT pReportFiltered = dbgfR3FlowTraceReportCreate(pReport->pUVM, pReport->cRecords);
1741 if (RT_LIKELY(pReport))
1742 {
1743 uint32_t idxFiltered = 0;
1744
1745 for (uint32_t i = 0; i < pReport->cRecords; i++)
1746 {
1747 PDBGFFLOWTRACERECORDINT pCur = pReport->apRec[i];
1748 bool fRecFilterMatch = dbgfR3FlowTraceDoesRecordMatchFilter(pCur, paFilters, cFilters, enmOp);
1749
1750 if ( ( fRecFilterMatch
1751 && !(fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE))
1752 || ( !fRecFilterMatch
1753 && (fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE)))
1754 {
1755 DBGFR3FlowTraceRecordRetain(pCur);
1756 pReportFiltered->apRec[idxFiltered++] = pCur;
1757 }
1758 }
1759
1760 pReportFiltered->cRecords = idxFiltered;
1761 *phFlowTraceReportFiltered = pReportFiltered;
1762 }
1763 else
1764 rc = VERR_NO_MEMORY;
1765
1766 return rc;
1767}
1768
1769
1770/**
1771 * Enumerates all records in the given flow trace report calling the supplied
1772 * enumeration callback.
1773 *
1774 * @returns VBox status code, return value of pfnEnum on error.
1775 * @param hFlowTraceReport Flow trace report handle.
1776 * @param pfnEnum The callback to call for every record.
1777 * @param pvUser Opaque user data to pass to the callback.
1778 */
1779VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport,
1780 PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum,
1781 void *pvUser)
1782{
1783 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1784 AssertPtrReturn(pReport, VERR_INVALID_HANDLE);
1785
1786 int rc = VINF_SUCCESS;
1787 for (uint32_t i = 0; i < pReport->cRecords && RT_SUCCESS(rc); i++)
1788 rc = pfnEnum(pReport, pReport->apRec[i], pvUser);
1789
1790 return rc;
1791}
1792
1793
1794/**
1795 * Retains a reference to the given flow trace record handle.
1796 *
1797 * @returns New reference count.
1798 * @param hFlowTraceRecord The record handle to retain.
1799 */
1800VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord)
1801{
1802 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1803 AssertPtrReturn(pRecord, UINT32_MAX);
1804
1805 uint32_t cRefs = ASMAtomicIncU32(&pRecord->cRefs);
1806 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pRecord));
1807 return cRefs;
1808}
1809
1810
1811/**
1812 * Releases a reference of the given flow trace record.
1813 *
1814 * @returns New reference count, on 0 the record is destroyed.
1815 * @param hFlowTraceRecord Flow trace record handle.
1816 */
1817VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord)
1818{
1819 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1820 if (!pRecord)
1821 return 0;
1822 AssertPtrReturn(pRecord, UINT32_MAX);
1823
1824 uint32_t cRefs = ASMAtomicDecU32(&pRecord->cRefs);
1825 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pRecord));
1826 if (cRefs == 0)
1827 dbgfR3FlowTraceRecordDestroy(pRecord);
1828 return cRefs;
1829}
1830
1831
1832/**
1833 * Gets the sequence number of the given record handle.
1834 *
1835 * @returns Sequence number.
1836 * @param hFlowTraceRecord Flow trace record handle.
1837 */
1838VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord)
1839{
1840 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1841 AssertPtrReturn(pRecord, 0);
1842
1843 return pRecord->u64SeqNo;
1844}
1845
1846
1847/**
1848 * Returns the timestamp when the record was created.
1849 *
1850 * @returns Timestamp in nano seconds.
1851 * @param hFlowTraceRecord Flow trace record handle.
1852 */
1853VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord)
1854{
1855 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1856 AssertPtrReturn(pRecord, 0);
1857
1858 return pRecord->u64TsCollected;
1859}
1860
1861
1862/**
1863 * Gets the address in the guest the record was created.
1864 *
1865 * @returns Pointer to the address containing the guest location the record was created at.
1866 * @param hFlowTraceRecord Flow trace record handle.
1867 * @param pAddr Where to store the guest address.
1868 */
1869VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr)
1870{
1871 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1872 AssertPtrReturn(pRecord, NULL);
1873 AssertPtrReturn(pAddr, NULL);
1874
1875 *pAddr = pRecord->AddrProbe;
1876 return pAddr;
1877}
1878
1879
1880/**
1881 * Returns the handle to the probe for the given record.
1882 *
1883 * @returns Handle to the probe.
1884 * @param hFlowTraceRecord Flow trace record handle.
1885 */
1886VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord)
1887{
1888 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1889 AssertPtrReturn(pRecord, NULL);
1890
1891 DBGFR3FlowTraceProbeRetain(pRecord->pProbe);
1892 return pRecord->pProbe;
1893}
1894
1895
1896/**
1897 * Returns the number of values contained in the record.
1898 *
1899 * @returns Number of values in the record.
1900 * @param hFlowTraceRecord Flow trace record handle.
1901 */
1902VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord)
1903{
1904 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1905 AssertPtrReturn(pRecord, 0);
1906
1907 return pRecord->pProbe->cEntries;
1908}
1909
1910
1911/**
1912 * Returns the number of values contained in the record.
1913 *
1914 * @returns Number of values in the record.
1915 * @param hFlowTraceRecord Flow trace record handle.
1916 */
1917VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCommonCount(DBGFFLOWTRACERECORD hFlowTraceRecord)
1918{
1919 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1920 AssertPtrReturn(pRecord, 0);
1921
1922 return pRecord->pProbeCmn ? pRecord->pProbeCmn->cEntries : 0;
1923}
1924
1925
1926/**
1927 * Returns the values for the given record.
1928 *
1929 * @returns Pointer to the array of values.
1930 * @param hFlowTraceRecord Flow trace record handle.
1931 */
1932VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord)
1933{
1934 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1935 AssertPtrReturn(pRecord, NULL);
1936
1937 return &pRecord->aVal[0];
1938}
1939
1940
1941/**
1942 * Returns data collected by the common probe for the trace module this record is in if one
1943 * is active.
1944 *
1945 * @returns Pointer to the array of common probe values or NULL if no common probe was specified
1946 * for the trace module.
1947 * @param hFlowTraceRecord Flow trace record handle.
1948 */
1949VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord)
1950{
1951 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1952 AssertPtrReturn(pRecord, NULL);
1953
1954 return pRecord->paValCmn;
1955}
1956
1957
1958/**
1959 * Returns the vCPU ID the record was created on.
1960 *
1961 * @returns vCPU ID.
1962 * @param hFlowTraceRecord Flow trace record handle.
1963 */
1964VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord)
1965{
1966 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1967 AssertPtrReturn(pRecord, VMCPUID_ANY);
1968
1969 return pRecord->idCpu;
1970}
1971
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette