VirtualBox

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

最後變更 在這個檔案是 107740,由 vboxsync 提交於 2 月 前

VMM/VMMR3/DBGFR3FlowTrace.cpp: Enter the debugger when collecting the probe data using the callback failed, bugref:3409

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 69.9 KB
 
1/* $Id: DBGFR3FlowTrace.cpp 107740 2025-01-14 09:46:52Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Guest Execution Flow Tracing.
4 */
5
6/*
7 * Copyright (C) 2016-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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 if (RT_FAILURE(rc))
764 {
765 fDbgDefer = true;
766 break;
767 }
768 break;
769 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
770 fDbgDefer = true;
771 break;
772 default:
773 AssertFailed();
774 }
775
776 pVal++;
777 }
778
779 return fDbgDefer;
780}
781
782
783/**
784 * @callback_method_impl{FNDBGFBPHIT}
785 */
786static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModProbeFiredWorker(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, uint16_t fFlags)
787{
788 RT_NOREF(pVM, hBp, pBpPub, fFlags);
789 LogFlowFunc(("pVM=%#p idCpu=%u pvUserBp=%#p hBp=%#x pBpPub=%p\n",
790 pVM, idCpu, pvUserBp, hBp, pBpPub));
791
792 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = (PDBGFFLOWTRACEMODPROBELOC)pvUserBp;
793 PDBGFFLOWTRACEPROBEINT pProbe = pProbeLoc->pProbe;
794 PDBGFFLOWTRACEMODINT pTraceMod = pProbeLoc->pTraceMod;
795 bool fDisabledModule = false;
796 bool fDbgDefer = false;
797
798 /* Check whether the trace module is still active and we are tracing the correct VCPU. */
799 if (ASMAtomicReadU32((volatile uint32_t *)&pTraceMod->enmState) != DBGFFLOWTRACEMODSTATE_ENABLED
800 || ( idCpu != pTraceMod->idCpu
801 && pTraceMod->idCpu != VMCPUID_ANY))
802 return VINF_SUCCESS;
803
804 if ( pTraceMod->fLimit
805 && ASMAtomicReadU32(&pTraceMod->cHitsLeft))
806 {
807 uint32_t cHitsLeftNew = ASMAtomicDecU32(&pTraceMod->cHitsLeft);
808 if (cHitsLeftNew > cHitsLeftNew + 1) /* Underflow => reached the limit. */
809 {
810 ASMAtomicIncU32(&pTraceMod->cHitsLeft);
811 return VINF_SUCCESS;
812 }
813
814 if (!cHitsLeftNew)
815 {
816 /* We got the last record, disable the trace module. */
817 fDisabledModule = ASMAtomicCmpXchgU32((volatile uint32_t *)&pTraceMod->enmState, DBGFFLOWTRACEMODSTATE_CREATED,
818 DBGFFLOWTRACEMODSTATE_ENABLED);
819 }
820 }
821
822 uint8_t *pbBuf = NULL;
823 uint8_t *pbBufCmn = NULL;
824 PDBGFFLOWTRACERECORDINT pRecord = dbgfR3FlowTraceRecordCreate(pProbeLoc, idCpu, &pbBuf, &pbBufCmn);
825 if (pRecord)
826 {
827 fDbgDefer = dbgfR3FlowTraceModProbeCollectData(pTraceMod->pUVM, idCpu, pTraceMod, &pProbeLoc->AddrProbe, pProbe,
828 &pRecord->aVal[0], pbBuf);
829 if (pTraceMod->pProbeCmn)
830 fDbgDefer = dbgfR3FlowTraceModProbeCollectData(pTraceMod->pUVM, idCpu, pTraceMod, NULL, pTraceMod->pProbeCmn,
831 pRecord->paValCmn, pbBufCmn);
832
833 RTSemFastMutexRequest(pTraceMod->hMtx);
834 uint32_t cRecordsNew = ASMAtomicIncU32(&pTraceMod->cRecords);
835 RTListAppend(&pTraceMod->LstRecords, &pRecord->NdRecord);
836 if ( (cRecordsNew > pTraceMod->cRecordsMax)
837 && pTraceMod->cRecordsMax > 0)
838 {
839 /* Get the first record and destroy it. */
840 pRecord = RTListRemoveFirst(&pTraceMod->LstRecords, DBGFFLOWTRACERECORDINT, NdRecord);
841 AssertPtr(pRecord);
842 DBGFR3FlowTraceRecordRelease(pRecord);
843 ASMAtomicDecU32(&pTraceMod->cRecords);
844 }
845 RTSemFastMutexRelease(pTraceMod->hMtx);
846 }
847
848 if (fDisabledModule)
849 {
850 int rc = DBGFR3FlowTraceModDisable(pTraceMod);
851 AssertRC(rc);
852 }
853
854 return fDbgDefer ? VINF_DBGF_BP_HALT : VINF_SUCCESS;
855}
856
857
858/**
859 * Worker for DBGFR3FlowTraceModEnable(), doing the work in an EMT rendezvous point to
860 * ensure no probe is hit in an inconsistent state.
861 *
862 * @returns Strict VBox status code.
863 * @param pVM The VM instance data.
864 * @param pVCpu The virtual CPU we execute on.
865 * @param pvUser Opaque user data.
866 */
867static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModEnableWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
868{
869 RT_NOREF2(pVM, pVCpu);
870 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)pvUser;
871 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = NULL;
872 int rc = VINF_SUCCESS;
873
874 pThis->enmState = DBGFFLOWTRACEMODSTATE_ENABLED;
875
876 RTListForEach(&pThis->LstProbes, pProbeLoc, DBGFFLOWTRACEMODPROBELOC, NdProbes)
877 {
878 uint16_t fBpFlags = DBGF_BP_F_ENABLED;
879
880 if (pProbeLoc->fFlags & DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC)
881 fBpFlags |= DBGF_BP_F_HIT_EXEC_BEFORE;
882 if (pProbeLoc->fFlags & DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC)
883 fBpFlags |= DBGF_BP_F_HIT_EXEC_AFTER;
884
885 rc = DBGFR3BpSetInt3Ex(pThis->pUVM, pThis->hBpOwner, pProbeLoc,
886 0 /*idSrcCpu*/, &pProbeLoc->AddrProbe, fBpFlags,
887 0 /*iHitTrigger*/, ~0ULL /*iHitDisable*/, &pProbeLoc->hBp);
888 if (RT_FAILURE(rc))
889 break;
890 }
891
892 if (RT_FAILURE(rc))
893 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
894
895 return rc;
896}
897
898
899/**
900 * Worker for DBGFR3FlowTraceModDisable(), doing the work in an EMT rendezvous point to
901 * ensure no probe is hit in an inconsistent state.
902 *
903 * @returns Struct VBox status code.
904 * @param pVM The VM instance data.
905 * @param pVCpu The virtual CPU we execute on.
906 * @param pvUser Opaque user data.
907 */
908static DECLCALLBACK(VBOXSTRICTRC) dbgfR3FlowTraceModDisableWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
909{
910 RT_NOREF2(pVM, pVCpu);
911 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)pvUser;
912 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = NULL;
913 int rc = VINF_SUCCESS;
914
915 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
916
917 RTListForEach(&pThis->LstProbes, pProbeLoc, DBGFFLOWTRACEMODPROBELOC, NdProbes)
918 {
919 rc = DBGFR3BpClear(pThis->pUVM, pProbeLoc->hBp);
920 AssertRC(rc);
921 }
922
923 return rc;
924}
925
926
927/**
928 * Checks whether both addresses are equal.
929 *
930 * @returns true if both addresses point to the same location, false otherwise.
931 * @param pAddr1 First address.
932 * @param pAddr2 Second address.
933 */
934static bool dbgfR3FlowTraceAddrEqual(PCDBGFADDRESS pAddr1, PCDBGFADDRESS pAddr2)
935{
936 return pAddr1->Sel == pAddr2->Sel
937 && pAddr1->off == pAddr2->off;
938}
939
940
941/**
942 * Returns the probe location pointer at the given address for the given trace module.
943 *
944 * @returns Pointer to the probe location or NULL if there is no probe at the given location.
945 * @param pThis The flow trace module instance data.
946 * @param pAddrProbe Address of the probe to check.
947 */
948static PDBGFFLOWTRACEMODPROBELOC dbgfR3TraceModGetProbeLocAtAddr(PDBGFFLOWTRACEMODINT pThis, PCDBGFADDRESS pAddrProbe)
949{
950 RTSemFastMutexRequest(pThis->hMtx);
951
952 PDBGFFLOWTRACEMODPROBELOC pIt;
953 RTListForEach(&pThis->LstProbes, pIt, DBGFFLOWTRACEMODPROBELOC, NdProbes)
954 {
955 if (dbgfR3FlowTraceAddrEqual(&pIt->AddrProbe, pAddrProbe))
956 {
957 RTSemFastMutexRelease(pThis->hMtx);
958 return pIt;
959 }
960 }
961 RTSemFastMutexRelease(pThis->hMtx);
962 return NULL;
963}
964
965
966/**
967 * Cleans up any allocated resources for each entry in the given probe for the given range.
968 *
969 * @param pProbe The probe instance.
970 * @param idxStart Start index to clean up.
971 * @param cEntries How many entries to clean up.
972 */
973static void dbgfR3ProbeEntryCleanup(PDBGFFLOWTRACEPROBEINT pProbe, uint32_t idxStart, uint32_t cEntries)
974{
975 AssertReturnVoid(pProbe->cEntriesMax >= idxStart + cEntries);
976
977 for (uint32_t i = idxStart; i < idxStart + cEntries; i++)
978 {
979 PDBGFFLOWTRACEPROBEENTRY pEntry = &pProbe->paEntries[i];
980
981 switch (pEntry->enmType)
982 {
983 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
984 if (pEntry->Type.Reg.pszName)
985 MMR3HeapFree((void *)pEntry->Type.Reg.pszName);
986 pEntry->Type.Reg.pszName = NULL;
987 break;
988 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
989 pEntry->Type.ConstMem.cbMem = 0;
990 break;
991 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
992 pEntry->Type.IndirectMem.uScale = 0;
993 pEntry->Type.IndirectMem.cbMem = 0;
994 if (pEntry->Type.IndirectMem.RegBase.pszName)
995 MMR3HeapFree((void *)pEntry->Type.IndirectMem.RegBase.pszName);
996 if (pEntry->Type.IndirectMem.RegIndex.pszName)
997 MMR3HeapFree((void *)pEntry->Type.IndirectMem.RegIndex.pszName);
998 pEntry->Type.IndirectMem.RegBase.pszName = NULL;
999 pEntry->Type.IndirectMem.RegIndex.pszName = NULL;
1000 break;
1001 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
1002 pEntry->Type.Callback.pfnCallback = NULL;
1003 pEntry->Type.Callback.pvUser = NULL;
1004 break;
1005 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
1006 break;
1007 default:
1008 AssertFailed();
1009 }
1010 }
1011}
1012
1013
1014/**
1015 * Destroys the given flow trace probe freeing all allocated resources.
1016 *
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 * @param pProbe The probe instance.
1154 */
1155static void dbgfR3ProbeRecalcSize(PDBGFFLOWTRACEPROBEINT pProbe)
1156{
1157 size_t cbProbe = 0;
1158
1159 for (uint32_t i = 0; i < pProbe->cEntries; i++)
1160 {
1161 PDBGFFLOWTRACEPROBEENTRY pEntry = &pProbe->paEntries[i];
1162
1163 cbProbe += sizeof(DBGFFLOWTRACEPROBEVAL);
1164
1165 switch (pEntry->enmType)
1166 {
1167 case DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM:
1168 cbProbe += pEntry->Type.ConstMem.cbMem;
1169 break;
1170 case DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM:
1171 cbProbe += pEntry->Type.IndirectMem.cbMem;
1172 break;
1173 case DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK:
1174 case DBGFFLOWTRACEPROBEENTRYTYPE_REG:
1175 case DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER:
1176 break;
1177 default:
1178 AssertFailed();
1179 }
1180 }
1181
1182 pProbe->cbProbe = cbProbe;
1183}
1184
1185
1186/**
1187 * Creates a new empty flow trace module.
1188 *
1189 * @returns VBox status code.
1190 * @param pUVM The usermode VM handle.
1191 * @param idCpu CPU ID the module is for, use VMCPUID_ANY for any CPU.
1192 * @param hFlowTraceProbeCommon Optional probe handle of data to capture regardless of the actual
1193 * probe.
1194 * @param phFlowTraceMod Where to store the handle to the created module on success.
1195 */
1196VMMR3DECL(int) DBGFR3FlowTraceModCreate(PUVM pUVM, VMCPUID idCpu,
1197 DBGFFLOWTRACEPROBE hFlowTraceProbeCommon,
1198 PDBGFFLOWTRACEMOD phFlowTraceMod)
1199{
1200 int rc = VINF_SUCCESS;
1201 PDBGFFLOWTRACEMODINT pThis = (PDBGFFLOWTRACEMODINT)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_FLOWTRACE,
1202 sizeof(DBGFFLOWTRACEMODINT));
1203 if (RT_LIKELY(pThis))
1204 {
1205 pThis->cRefs = 1;
1206 pThis->pUVM = pUVM;
1207 pThis->idCpu = idCpu;
1208 pThis->enmState = DBGFFLOWTRACEMODSTATE_CREATED;
1209 pThis->u64SeqNoNext = 0;
1210 pThis->cHitsLeft = 0;
1211 pThis->cRecordsMax = 0;
1212 pThis->cRecords = 0;
1213 pThis->cProbes = 0;
1214 RTListInit(&pThis->LstProbes);
1215 RTListInit(&pThis->LstRecords);
1216
1217 rc = RTSemFastMutexCreate(&pThis->hMtx);
1218 if (RT_SUCCESS(rc))
1219 {
1220 rc = DBGFR3BpOwnerCreate(pUVM, dbgfR3FlowTraceModProbeFiredWorker, NULL /*pfnBpIoHit*/, &pThis->hBpOwner);
1221 if (RT_SUCCESS(rc))
1222 {
1223 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbeCommon;
1224 if (pProbe)
1225 {
1226 DBGFR3FlowTraceProbeRetain(pProbe);
1227 pThis->pProbeCmn = pProbe;
1228 }
1229 }
1230
1231 *phFlowTraceMod = pThis;
1232 }
1233
1234 if (RT_FAILURE(rc))
1235 MMR3HeapFree(pThis);
1236 }
1237 else
1238 rc = VERR_NO_MEMORY;
1239
1240 return rc;
1241}
1242
1243
1244/**
1245 * Create a new flow trace module from the given control flow graph adding the given probes
1246 * at the entries, exits and branches.
1247 *
1248 * @returns VBox status code.
1249 * @param pUVM The usermode VM handle.
1250 * @param idCpu CPU ID the module is for, use VMCPUID_ANY for any CPU.
1251 * @param hFlow Control flow graph handle to use.
1252 * @param hFlowTraceProbeCommon Optional probe handle of data to capture regardless of the actual
1253 * probe.
1254 * @param hFlowTraceProbeEntry Probe handle to use for all entry blocks.
1255 * @param hFlowTraceProbeRegular Probe handle to use for all branches.
1256 * @param hFlowTraceProbeExit Probe handle to use for all exits.
1257 * @param phFlowTraceMod Where to store the handle to the created module on success.
1258 */
1259VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow,
1260 DBGFFLOWTRACEPROBE hFlowTraceProbeCommon,
1261 DBGFFLOWTRACEPROBE hFlowTraceProbeEntry,
1262 DBGFFLOWTRACEPROBE hFlowTraceProbeRegular,
1263 DBGFFLOWTRACEPROBE hFlowTraceProbeExit,
1264 PDBGFFLOWTRACEMOD phFlowTraceMod)
1265{
1266 DBGFFLOWIT hFlowIt;
1267 int rc = DBGFR3FlowItCreate(hFlow, DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST, &hFlowIt);
1268 if (RT_SUCCESS(rc))
1269 {
1270 DBGFFLOWTRACEMOD hFlowTraceMod;
1271 rc = DBGFR3FlowTraceModCreate(pUVM, idCpu, hFlowTraceProbeCommon, &hFlowTraceMod);
1272 if (RT_SUCCESS(rc))
1273 {
1274 DBGFFLOWBB hFlowBb = DBGFR3FlowItNext(hFlowIt);
1275 while (hFlowBb && RT_SUCCESS(rc))
1276 {
1277 uint32_t fFlags = DBGFR3FlowBbGetFlags(hFlowBb);
1278
1279 if (!(fFlags & (DBGF_FLOW_BB_F_EMPTY | DBGF_FLOW_BB_F_INCOMPLETE_ERR)))
1280 {
1281 DBGFADDRESS AddrInstr;
1282
1283 if (fFlags & DBGF_FLOW_BB_F_ENTRY)
1284 {
1285 rc = DBGFR3FlowBbQueryInstr(hFlowBb, 0, &AddrInstr, NULL, NULL);
1286 AssertRC(rc);
1287
1288 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeEntry,
1289 DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC);
1290 }
1291 else
1292 {
1293 DBGFFLOWBBENDTYPE enmType = DBGFR3FlowBbGetType(hFlowBb);
1294 uint32_t cInstr = enmType == DBGFFLOWBBENDTYPE_EXIT ? DBGFR3FlowBbGetInstrCount(hFlowBb) - 1 : 0;
1295 rc = DBGFR3FlowBbQueryInstr(hFlowBb, cInstr, &AddrInstr, NULL, NULL);
1296 if (RT_SUCCESS(rc))
1297 {
1298 if (enmType == DBGFFLOWBBENDTYPE_EXIT)
1299 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeExit,
1300 DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC);
1301 else
1302 rc = DBGFR3FlowTraceModAddProbe(hFlowTraceMod, &AddrInstr, hFlowTraceProbeRegular,
1303 DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC);
1304 }
1305 }
1306 }
1307
1308 hFlowBb = DBGFR3FlowItNext(hFlowIt);
1309 }
1310
1311 if (RT_FAILURE(rc))
1312 DBGFR3FlowTraceModRelease(hFlowTraceMod);
1313 else
1314 *phFlowTraceMod = hFlowTraceMod;
1315 }
1316
1317 DBGFR3FlowItDestroy(hFlowIt);
1318 }
1319
1320 return rc;
1321}
1322
1323
1324/**
1325 * Retain a reference to the given flow trace module.
1326 *
1327 * @returns New reference count.
1328 * @param hFlowTraceMod Flow trace module handle.
1329 */
1330VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod)
1331{
1332 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1333 AssertPtrReturn(pThis, UINT32_MAX);
1334
1335 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1336 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1337 return cRefs;
1338}
1339
1340
1341/**
1342 * Release a reference of the given flow trace module.
1343 *
1344 * @returns New reference count, on 0 the module is destroyed and all containing records
1345 * are deleted.
1346 * @param hFlowTraceMod Flow trace module handle.
1347 */
1348VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod)
1349{
1350 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1351 if (!pThis)
1352 return 0;
1353 AssertPtrReturn(pThis, UINT32_MAX);
1354
1355 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1356 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1357 if (cRefs == 0)
1358 dbgfR3FlowTraceModDestroy(pThis);
1359 return cRefs;
1360}
1361
1362
1363/**
1364 * Enables and arms all probes in the given flow trace module.
1365 *
1366 * @returns VBox status code.
1367 * @param hFlowTraceMod Flow trace module handle.
1368 * @param cHits Number of hits inside this module until the module is disabled
1369 * automatically, 0 if not to disable automatically.
1370 * @param cRecordsMax Maximum number of records to keep until the oldest is evicted.
1371 */
1372VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax)
1373{
1374 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1375 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1376 AssertReturn(pThis->cProbes > 0, VERR_INVALID_STATE);
1377 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_CREATED, VERR_INVALID_STATE);
1378
1379 pThis->cHitsLeft = cHits;
1380 pThis->cRecordsMax = cRecordsMax;
1381
1382 return VMMR3EmtRendezvous(pThis->pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
1383 dbgfR3FlowTraceModEnableWorker, pThis);
1384}
1385
1386
1387/**
1388 * Disables all probes in the given flow trace module.
1389 *
1390 * @returns VBox status code.
1391 * @param hFlowTraceMod Flow trace module handle.
1392 */
1393VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod)
1394{
1395 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1396 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1397 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_ENABLED, VERR_INVALID_STATE);
1398
1399 return VMMR3EmtRendezvous(pThis->pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE,
1400 dbgfR3FlowTraceModDisableWorker, pThis);
1401}
1402
1403
1404/**
1405 * Returns a report containing all existing records in the given flow trace module.
1406 *
1407 * @returns VBox status code.
1408 * @param hFlowTraceMod Flow trace module handle.
1409 * @param phFlowTraceReport Where to store the flow trace report handle on success.
1410 */
1411VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod,
1412 PDBGFFLOWTRACEREPORT phFlowTraceReport)
1413{
1414 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1415 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1416 AssertPtrReturn(phFlowTraceReport, VERR_INVALID_POINTER);
1417
1418 /** @todo Locking. */
1419 int rc = VINF_SUCCESS;
1420 PDBGFFLOWTRACEREPORTINT pReport = dbgfR3FlowTraceReportCreate(pThis->pUVM, pThis->cRecords);
1421 if (RT_LIKELY(pReport))
1422 {
1423 PDBGFFLOWTRACERECORDINT pIt;
1424 uint32_t idx = 0;
1425
1426 RTSemFastMutexRequest(pThis->hMtx);
1427 RTListForEach(&pThis->LstRecords, pIt, DBGFFLOWTRACERECORDINT, NdRecord)
1428 {
1429 DBGFR3FlowTraceRecordRetain(pIt);
1430 pReport->apRec[idx++] = pIt;
1431 }
1432 RTSemFastMutexRelease(pThis->hMtx);
1433
1434 *phFlowTraceReport = pReport;
1435 }
1436 else
1437 rc = VERR_NO_MEMORY;
1438
1439 return rc;
1440}
1441
1442
1443/**
1444 * Clears all records contained in the flow trace module.
1445 *
1446 * @returns VBox status code.
1447 * @param hFlowTraceMod Flow trace module handle.
1448 */
1449VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod)
1450{
1451 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1452 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1453
1454 RTSemFastMutexRequest(pThis->hMtx);
1455 RTLISTANCHOR LstTmp;
1456 RTListMove(&LstTmp, &pThis->LstRecords);
1457 ASMAtomicWriteU32(&pThis->cRecords, 0);
1458 RTSemFastMutexRelease(pThis->hMtx);
1459
1460 PDBGFFLOWTRACERECORDINT pIt, pItNext;
1461 RTListForEachSafe(&LstTmp, pIt, pItNext, DBGFFLOWTRACERECORDINT, NdRecord)
1462 {
1463 RTListNodeRemove(&pIt->NdRecord);
1464 DBGFR3FlowTraceRecordRelease(pIt);
1465 }
1466
1467 return VINF_SUCCESS;
1468}
1469
1470
1471/**
1472 * Adds a new probe to the given flow trace module.
1473 *
1474 * @returns VBox status code
1475 * @retval VERR_INVALID_STATE if the probe is active or was destroyed already.
1476 * @retval VERR_ALREADY_EXISTS if there is already a probe at the specified location.
1477 * @param hFlowTraceMod Flow trace module handle.
1478 * @param pAddrProbe Guest address to insert the probe at.
1479 * @param hFlowTraceProbe The handle of the probe to insert.
1480 * @param fFlags Combination of DBGF_FLOW_TRACE_PROBE_ADD_F_*.
1481 */
1482VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe,
1483 DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags)
1484{
1485 PDBGFFLOWTRACEMODINT pThis = hFlowTraceMod;
1486 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1487 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1488 AssertPtrReturn(pProbe, VERR_INVALID_HANDLE);
1489 AssertPtrReturn(pAddrProbe, VERR_INVALID_POINTER);
1490 AssertReturn(!(fFlags & ~DBGF_FLOW_TRACE_PROBE_ADD_F_VALID_MASK), VERR_INVALID_PARAMETER);
1491 AssertReturn(pThis->enmState == DBGFFLOWTRACEMODSTATE_CREATED, VERR_INVALID_STATE);
1492
1493 int rc = VINF_SUCCESS;
1494 PDBGFFLOWTRACEMODPROBELOC pProbeLoc = dbgfR3TraceModGetProbeLocAtAddr(pThis, pAddrProbe);
1495 if (!pProbeLoc)
1496 {
1497 pProbeLoc = (PDBGFFLOWTRACEMODPROBELOC)MMR3HeapAllocZU(pThis->pUVM, MM_TAG_DBGF_FLOWTRACE,
1498 sizeof(DBGFFLOWTRACEMODPROBELOC));
1499 if (RT_LIKELY(pProbeLoc))
1500 {
1501 pProbeLoc->pTraceMod = pThis;
1502 pProbeLoc->pProbe = pProbe;
1503 pProbeLoc->AddrProbe = *pAddrProbe;
1504 pProbeLoc->fFlags = fFlags;
1505 ASMAtomicIncU32(&pProbe->cRefs);
1506 ASMAtomicIncU32(&pProbe->cRefsMod);
1507 RTSemFastMutexRequest(pThis->hMtx);
1508 RTListAppend(&pThis->LstProbes, &pProbeLoc->NdProbes);
1509 pThis->cProbes++;
1510 RTSemFastMutexRelease(pThis->hMtx);
1511 }
1512 else
1513 rc = VERR_NO_MEMORY;
1514 }
1515 else
1516 rc = VERR_ALREADY_EXISTS;
1517
1518 return rc;
1519}
1520
1521
1522/**
1523 * Creates a new empty probe.
1524 *
1525 * @returns VBox status code.
1526 * @param pUVM The usermode VM handle.
1527 * @param pszDescr Description of the probe, optional.
1528 * @param phFlowTraceProbe Where to store the probe handle on success.
1529 */
1530VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe)
1531{
1532 int rc = VINF_SUCCESS;
1533 PDBGFFLOWTRACEPROBEINT pProbe = (PDBGFFLOWTRACEPROBEINT)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_FLOWTRACE,
1534 sizeof(DBGFFLOWTRACEPROBEINT));
1535 if (RT_LIKELY(pProbe))
1536 {
1537 pProbe->cRefs = 1;
1538 pProbe->cRefsMod = 0;
1539 pProbe->pUVM = pUVM;
1540 pProbe->cbProbe = 0;
1541 pProbe->cEntries = 0;
1542 pProbe->cEntriesMax = 0;
1543 pProbe->paEntries = NULL;
1544 pProbe->pszDescr = NULL;
1545 if (pszDescr)
1546 {
1547 pProbe->pszDescr = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_FLOWTRACE, pszDescr);
1548 if (!pProbe->pszDescr)
1549 {
1550 MMR3HeapFree(pProbe);
1551 rc = VERR_NO_MEMORY;
1552 }
1553 }
1554
1555 if (RT_SUCCESS(rc))
1556 *phFlowTraceProbe = pProbe;
1557 }
1558 else
1559 rc = VERR_NO_MEMORY;
1560
1561 return rc;
1562}
1563
1564
1565/**
1566 * Retains a reference to the probe.
1567 *
1568 * @returns New reference count.
1569 * @param hFlowTraceProbe Flow trace probe handle.
1570 */
1571VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe)
1572{
1573 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1574 AssertPtrReturn(pProbe, UINT32_MAX);
1575
1576 uint32_t cRefs = ASMAtomicIncU32(&pProbe->cRefs);
1577 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pProbe));
1578 return cRefs;
1579}
1580
1581
1582/**
1583 * Release a probe reference.
1584 *
1585 * @returns New reference count, on 0 the probe is destroyed.
1586 * @param hFlowTraceProbe Flow trace probe handle.
1587 */
1588VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe)
1589{
1590 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1591 if (!pProbe)
1592 return 0;
1593 AssertPtrReturn(pProbe, UINT32_MAX);
1594
1595 uint32_t cRefs = ASMAtomicDecU32(&pProbe->cRefs);
1596 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pProbe));
1597 if (cRefs == 0)
1598 dbgfR3FlowTraceProbeDestroy(pProbe);
1599 return cRefs;
1600}
1601
1602
1603/**
1604 * Adds new data to log in the given probe.
1605 *
1606 * @returns VBox status code.
1607 * @retval VERR_INVALID_STATE if the probe is already part of a trace module and it is not
1608 * possible to add new entries at this point.
1609 * @param hFlowTraceProbe Flow trace probe handle.
1610 * @param paEntries Pointer to the array of entry descriptors.
1611 * @param cEntries Number of entries in the array.
1612 */
1613VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe,
1614 PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries)
1615{
1616 PDBGFFLOWTRACEPROBEINT pProbe = hFlowTraceProbe;
1617 AssertPtrReturn(pProbe, VERR_INVALID_HANDLE);
1618 AssertPtrReturn(paEntries, VERR_INVALID_POINTER);
1619 AssertReturn(cEntries > 0, VERR_INVALID_PARAMETER);
1620 AssertReturn(!pProbe->cRefsMod, VERR_INVALID_STATE);
1621
1622 int rc = dbgfR3ProbeEnsureSize(pProbe, cEntries);
1623 if (RT_SUCCESS(rc))
1624 {
1625 uint32_t idxEntry;
1626
1627 for (idxEntry = 0; idxEntry < cEntries && RT_SUCCESS(rc); idxEntry++)
1628 {
1629 PCDBGFFLOWTRACEPROBEENTRY pEntry = &paEntries[idxEntry];
1630 PDBGFFLOWTRACEPROBEENTRY pProbeEntry = &pProbe->paEntries[pProbe->cEntries + idxEntry];
1631
1632 rc = dbgfR3ProbeEntryDup(pProbe->pUVM, pProbeEntry, pEntry);
1633 }
1634
1635 if (RT_FAILURE(rc))
1636 dbgfR3ProbeEntryCleanup(pProbe, pProbe->cEntries, idxEntry + 1);
1637 else
1638 {
1639 pProbe->cEntries += cEntries;
1640 dbgfR3ProbeRecalcSize(pProbe);
1641 }
1642 }
1643
1644 return rc;
1645}
1646
1647
1648/**
1649 * Retains a reference to the given flow trace report.
1650 *
1651 * @returns New reference count.
1652 * @param hFlowTraceReport Flow trace report handle.
1653 */
1654VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport)
1655{
1656 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1657 AssertPtrReturn(pReport, UINT32_MAX);
1658
1659 uint32_t cRefs = ASMAtomicIncU32(&pReport->cRefs);
1660 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pReport));
1661 return cRefs;
1662}
1663
1664
1665/**
1666 * Releases a reference of the given flow trace report.
1667 *
1668 * @returns New reference count, on 0 the report is destroyed.
1669 * @param hFlowTraceReport Flow trace report handle.
1670 */
1671VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport)
1672{
1673 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1674 if (!pReport)
1675 return 0;
1676 AssertPtrReturn(pReport, UINT32_MAX);
1677
1678 uint32_t cRefs = ASMAtomicDecU32(&pReport->cRefs);
1679 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pReport));
1680 if (cRefs == 0)
1681 dbgfR3FlowTraceReportDestroy(pReport);
1682 return cRefs;
1683}
1684
1685
1686/**
1687 * Returns the number of records in the given report.
1688 *
1689 * @returns Number of records.
1690 * @param hFlowTraceReport Flow trace report handle.
1691 */
1692VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport)
1693{
1694 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1695 AssertPtrReturn(pReport, 0);
1696
1697 return pReport->cRecords;
1698}
1699
1700
1701/**
1702 * Queries the specified record contained in the given report.
1703 *
1704 * @returns VBox status code.
1705 * @param hFlowTraceReport Flow trace report handle.
1706 * @param idxRec The record index to query.
1707 * @param phFlowTraceRec Where to store the retained handle of the record on success.
1708 */
1709VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec)
1710{
1711 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1712 AssertPtrReturn(pReport, 0);
1713 AssertPtrReturn(phFlowTraceRec, VERR_INVALID_POINTER);
1714 AssertReturn(idxRec < pReport->cRecords, VERR_INVALID_PARAMETER);
1715
1716 DBGFR3FlowTraceRecordRetain(pReport->apRec[idxRec]);
1717 *phFlowTraceRec = pReport->apRec[idxRec];
1718 return VINF_SUCCESS;
1719}
1720
1721
1722/**
1723 * Filters the given flow trace report by the given criterias and returns a filtered report.
1724 *
1725 * @returns VBox status code.
1726 * @param hFlowTraceReport Flow trace report handle.
1727 * @param fFlags Combination of DBGF_FLOW_TRACE_REPORT_FILTER_F_*.
1728 * @param paFilters Pointer to the array of filters.
1729 * @param cFilters Number of entries in the filter array.
1730 * @param enmOp How the filters are connected to each other.
1731 * @param phFlowTraceReportFiltered Where to return the handle to the report containing the
1732 * filtered records on success.
1733 */
1734VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags,
1735 PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters,
1736 DBGFFLOWTRACEREPORTFILTEROP enmOp,
1737 PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered)
1738{
1739 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1740 AssertPtrReturn(pReport, VERR_INVALID_HANDLE);
1741 AssertReturn(!(fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_VALID), VERR_INVALID_PARAMETER);
1742 AssertPtrReturn(paFilters, VERR_INVALID_POINTER);
1743 AssertReturn(cFilters > 0, VERR_INVALID_PARAMETER);
1744 AssertReturn(enmOp > DBGFFLOWTRACEREPORTFILTEROP_INVALID && enmOp <= DBGFFLOWTRACEREPORTFILTEROP_OR,
1745 VERR_INVALID_PARAMETER);
1746 AssertPtrReturn(phFlowTraceReportFiltered, VERR_INVALID_POINTER);
1747
1748 int rc = VINF_SUCCESS;
1749 PDBGFFLOWTRACEREPORTINT pReportFiltered = dbgfR3FlowTraceReportCreate(pReport->pUVM, pReport->cRecords);
1750 if (RT_LIKELY(pReportFiltered))
1751 {
1752 uint32_t idxFiltered = 0;
1753
1754 for (uint32_t i = 0; i < pReport->cRecords; i++)
1755 {
1756 PDBGFFLOWTRACERECORDINT pCur = pReport->apRec[i];
1757 bool fRecFilterMatch = dbgfR3FlowTraceDoesRecordMatchFilter(pCur, paFilters, cFilters, enmOp);
1758
1759 if ( ( fRecFilterMatch
1760 && !(fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE))
1761 || ( !fRecFilterMatch
1762 && (fFlags & DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE)))
1763 {
1764 DBGFR3FlowTraceRecordRetain(pCur);
1765 pReportFiltered->apRec[idxFiltered++] = pCur;
1766 }
1767 }
1768
1769 pReportFiltered->cRecords = idxFiltered;
1770 *phFlowTraceReportFiltered = pReportFiltered;
1771 }
1772 else
1773 rc = VERR_NO_MEMORY;
1774
1775 return rc;
1776}
1777
1778
1779/**
1780 * Enumerates all records in the given flow trace report calling the supplied
1781 * enumeration callback.
1782 *
1783 * @returns VBox status code, return value of pfnEnum on error.
1784 * @param hFlowTraceReport Flow trace report handle.
1785 * @param pfnEnum The callback to call for every record.
1786 * @param pvUser Opaque user data to pass to the callback.
1787 */
1788VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport,
1789 PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum,
1790 void *pvUser)
1791{
1792 PDBGFFLOWTRACEREPORTINT pReport = hFlowTraceReport;
1793 AssertPtrReturn(pReport, VERR_INVALID_HANDLE);
1794
1795 int rc = VINF_SUCCESS;
1796 for (uint32_t i = 0; i < pReport->cRecords && RT_SUCCESS(rc); i++)
1797 rc = pfnEnum(pReport, pReport->apRec[i], pvUser);
1798
1799 return rc;
1800}
1801
1802
1803/**
1804 * Retains a reference to the given flow trace record handle.
1805 *
1806 * @returns New reference count.
1807 * @param hFlowTraceRecord The record handle to retain.
1808 */
1809VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord)
1810{
1811 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1812 AssertPtrReturn(pRecord, UINT32_MAX);
1813
1814 uint32_t cRefs = ASMAtomicIncU32(&pRecord->cRefs);
1815 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pRecord));
1816 return cRefs;
1817}
1818
1819
1820/**
1821 * Releases a reference of the given flow trace record.
1822 *
1823 * @returns New reference count, on 0 the record is destroyed.
1824 * @param hFlowTraceRecord Flow trace record handle.
1825 */
1826VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord)
1827{
1828 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1829 if (!pRecord)
1830 return 0;
1831 AssertPtrReturn(pRecord, UINT32_MAX);
1832
1833 uint32_t cRefs = ASMAtomicDecU32(&pRecord->cRefs);
1834 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pRecord));
1835 if (cRefs == 0)
1836 dbgfR3FlowTraceRecordDestroy(pRecord);
1837 return cRefs;
1838}
1839
1840
1841/**
1842 * Gets the sequence number of the given record handle.
1843 *
1844 * @returns Sequence number.
1845 * @param hFlowTraceRecord Flow trace record handle.
1846 */
1847VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord)
1848{
1849 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1850 AssertPtrReturn(pRecord, 0);
1851
1852 return pRecord->u64SeqNo;
1853}
1854
1855
1856/**
1857 * Returns the timestamp when the record was created.
1858 *
1859 * @returns Timestamp in nano seconds.
1860 * @param hFlowTraceRecord Flow trace record handle.
1861 */
1862VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord)
1863{
1864 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1865 AssertPtrReturn(pRecord, 0);
1866
1867 return pRecord->u64TsCollected;
1868}
1869
1870
1871/**
1872 * Gets the address in the guest the record was created.
1873 *
1874 * @returns Pointer to the address containing the guest location the record was created at.
1875 * @param hFlowTraceRecord Flow trace record handle.
1876 * @param pAddr Where to store the guest address.
1877 */
1878VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr)
1879{
1880 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1881 AssertPtrReturn(pRecord, NULL);
1882 AssertPtrReturn(pAddr, NULL);
1883
1884 *pAddr = pRecord->AddrProbe;
1885 return pAddr;
1886}
1887
1888
1889/**
1890 * Returns the handle to the probe for the given record.
1891 *
1892 * @returns Handle to the probe.
1893 * @param hFlowTraceRecord Flow trace record handle.
1894 */
1895VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord)
1896{
1897 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1898 AssertPtrReturn(pRecord, NULL);
1899
1900 DBGFR3FlowTraceProbeRetain(pRecord->pProbe);
1901 return pRecord->pProbe;
1902}
1903
1904
1905/**
1906 * Returns the number of values contained in the record.
1907 *
1908 * @returns Number of values in the record.
1909 * @param hFlowTraceRecord Flow trace record handle.
1910 */
1911VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord)
1912{
1913 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1914 AssertPtrReturn(pRecord, 0);
1915
1916 return pRecord->pProbe->cEntries;
1917}
1918
1919
1920/**
1921 * Returns the number of values contained in the record.
1922 *
1923 * @returns Number of values in the record.
1924 * @param hFlowTraceRecord Flow trace record handle.
1925 */
1926VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCommonCount(DBGFFLOWTRACERECORD hFlowTraceRecord)
1927{
1928 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1929 AssertPtrReturn(pRecord, 0);
1930
1931 return pRecord->pProbeCmn ? pRecord->pProbeCmn->cEntries : 0;
1932}
1933
1934
1935/**
1936 * Returns the values for the given record.
1937 *
1938 * @returns Pointer to the array of values.
1939 * @param hFlowTraceRecord Flow trace record handle.
1940 */
1941VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord)
1942{
1943 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1944 AssertPtrReturn(pRecord, NULL);
1945
1946 return &pRecord->aVal[0];
1947}
1948
1949
1950/**
1951 * Returns data collected by the common probe for the trace module this record is in if one
1952 * is active.
1953 *
1954 * @returns Pointer to the array of common probe values or NULL if no common probe was specified
1955 * for the trace module.
1956 * @param hFlowTraceRecord Flow trace record handle.
1957 */
1958VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord)
1959{
1960 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1961 AssertPtrReturn(pRecord, NULL);
1962
1963 return pRecord->paValCmn;
1964}
1965
1966
1967/**
1968 * Returns the vCPU ID the record was created on.
1969 *
1970 * @returns vCPU ID.
1971 * @param hFlowTraceRecord Flow trace record handle.
1972 */
1973VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord)
1974{
1975 PDBGFFLOWTRACERECORDINT pRecord = hFlowTraceRecord;
1976 AssertPtrReturn(pRecord, VMCPUID_ANY);
1977
1978 return pRecord->idCpu;
1979}
1980
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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