VirtualBox

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

Last change on this file since 100651 was 99739, checked in by vboxsync, 19 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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