VirtualBox

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

Last change on this file since 98045 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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