VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCCmdWorkers.cpp@ 94369

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/* $Id: DBGCCmdWorkers.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Command Worker Routines.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGC
23#include <VBox/dbg.h>
24#include <VBox/vmm/dbgf.h>
25#include <VBox/param.h>
26#include <VBox/err.h>
27#include <VBox/log.h>
28
29#include <iprt/alloc.h>
30#include <iprt/string.h>
31#include <iprt/assert.h>
32
33#include "DBGCInternal.h"
34
35
36
37
38//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
39//
40//
41// B r e a k p o i n t M a n a g e m e n t
42//
43//
44//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
45
46
47/**
48 * Adds a breakpoint to the DBGC breakpoint list.
49 */
50int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
51{
52 /*
53 * Check if it already exists.
54 */
55 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
56 if (pBp)
57 return VERR_DBGC_BP_EXISTS;
58
59 /*
60 * Add the breakpoint.
61 */
62 if (pszCmd)
63 pszCmd = RTStrStripL(pszCmd);
64 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
65 pBp = (PDBGCBP)RTMemAlloc(RT_UOFFSETOF_DYN(DBGCBP, szCmd[cchCmd + 1]));
66 if (!pBp)
67 return VERR_NO_MEMORY;
68 if (cchCmd)
69 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
70 else
71 pBp->szCmd[0] = '\0';
72 pBp->cchCmd = cchCmd;
73 pBp->iBp = iBp;
74 pBp->pNext = pDbgc->pFirstBp;
75 pDbgc->pFirstBp = pBp;
76
77 return VINF_SUCCESS;
78}
79
80/**
81 * Updates the a breakpoint.
82 *
83 * @returns VBox status code.
84 * @param pDbgc The DBGC instance.
85 * @param iBp The breakpoint to update.
86 * @param pszCmd The new command.
87 */
88int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
89{
90 /*
91 * Find the breakpoint.
92 */
93 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
94 if (!pBp)
95 return VERR_DBGC_BP_NOT_FOUND;
96
97 /*
98 * Do we need to reallocate?
99 */
100 if (pszCmd)
101 pszCmd = RTStrStripL(pszCmd);
102 if (!pszCmd || !*pszCmd)
103 pBp->szCmd[0] = '\0';
104 else
105 {
106 size_t cchCmd = strlen(pszCmd);
107 if (strlen(pBp->szCmd) >= cchCmd)
108 {
109 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
110 pBp->cchCmd = cchCmd;
111 }
112 else
113 {
114 /*
115 * Yes, let's do it the simple way...
116 */
117 int rc = dbgcBpDelete(pDbgc, iBp);
118 AssertRC(rc);
119 return dbgcBpAdd(pDbgc, iBp, pszCmd);
120 }
121 }
122 return VINF_SUCCESS;
123}
124
125
126/**
127 * Deletes a breakpoint.
128 *
129 * @returns VBox status code.
130 * @param pDbgc The DBGC instance.
131 * @param iBp The breakpoint to delete.
132 */
133int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
134{
135 /*
136 * Search thru the list, when found unlink and free it.
137 */
138 PDBGCBP pBpPrev = NULL;
139 PDBGCBP pBp = pDbgc->pFirstBp;
140 for (; pBp; pBp = pBp->pNext)
141 {
142 if (pBp->iBp == iBp)
143 {
144 if (pBpPrev)
145 pBpPrev->pNext = pBp->pNext;
146 else
147 pDbgc->pFirstBp = pBp->pNext;
148 RTMemFree(pBp);
149 return VINF_SUCCESS;
150 }
151 pBpPrev = pBp;
152 }
153
154 return VERR_DBGC_BP_NOT_FOUND;
155}
156
157
158/**
159 * Get a breakpoint.
160 *
161 * @returns Pointer to the breakpoint.
162 * @returns NULL if the breakpoint wasn't found.
163 * @param pDbgc The DBGC instance.
164 * @param iBp The breakpoint to get.
165 */
166PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
167{
168 /*
169 * Enumerate the list.
170 */
171 PDBGCBP pBp = pDbgc->pFirstBp;
172 for (; pBp; pBp = pBp->pNext)
173 if (pBp->iBp == iBp)
174 return pBp;
175 return NULL;
176}
177
178
179/**
180 * Executes the command of a breakpoint.
181 *
182 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
183 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
184 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
185 * @returns VBox status code from dbgcEvalCommand() otherwise.
186 * @param pDbgc The DBGC instance.
187 * @param iBp The breakpoint to execute.
188 */
189int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
190{
191 /*
192 * Find the breakpoint.
193 */
194 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
195 if (!pBp)
196 return VERR_DBGC_BP_NOT_FOUND;
197
198 /*
199 * Anything to do?
200 */
201 if (!pBp->cchCmd)
202 return VINF_DBGC_BP_NO_COMMAND;
203
204 /*
205 * Execute the command.
206 * This means copying it to the scratch buffer and process it as if it
207 * were user input. We must save and restore the state of the scratch buffer.
208 */
209 /* Save the scratch state. */
210 char *pszScratch = pDbgc->pszScratch;
211 unsigned iArg = pDbgc->iArg;
212
213 /* Copy the command to the scratch buffer. */
214 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
215 if (pBp->cchCmd >= cbScratch)
216 return VERR_BUFFER_OVERFLOW;
217 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
218
219 /* Execute the command. */
220 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
221 int rc = dbgcEvalCommand(pDbgc, pszScratch, pBp->cchCmd, false /* fNoExecute */);
222
223 /* Restore the scratch state. */
224 pDbgc->iArg = iArg;
225 pDbgc->pszScratch = pszScratch;
226
227 return rc;
228}
229
230
231
232
233//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
234//
235//
236// F l o w T r a c e M a n a g e m e n t
237//
238//
239//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
240
241
242
243/**
244 * Returns the trace flow module matching the given id or NULL if not found.
245 *
246 * @returns Pointer to the trace flow module or NULL if not found.
247 * @param pDbgc The DBGC instance.
248 * @param iTraceFlowMod The trace flow module identifier.
249 */
250DECLHIDDEN(PDBGCTFLOW) dbgcFlowTraceModGet(PDBGC pDbgc, uint32_t iTraceFlowMod)
251{
252 PDBGCTFLOW pIt;
253 RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
254 {
255 if (pIt->iTraceFlowMod == iTraceFlowMod)
256 return pIt;
257 }
258
259 return NULL;
260}
261
262
263/**
264 * Inserts the given trace flow module into the list.
265 *
266 * @returns nothing.
267 * @param pDbgc The DBGC instance.
268 * @param pTraceFlow The trace flow module.
269 */
270static void dbgcFlowTraceModInsert(PDBGC pDbgc, PDBGCTFLOW pTraceFlow)
271{
272 PDBGCTFLOW pIt = RTListGetLast(&pDbgc->LstTraceFlowMods, DBGCTFLOW, NdTraceFlow);
273
274 if ( !pIt
275 || pIt->iTraceFlowMod < pTraceFlow->iTraceFlowMod)
276 RTListAppend(&pDbgc->LstTraceFlowMods, &pTraceFlow->NdTraceFlow);
277 else
278 {
279 RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
280 {
281 if (pIt->iTraceFlowMod < pTraceFlow->iTraceFlowMod)
282 {
283 RTListNodeInsertBefore(&pIt->NdTraceFlow, &pTraceFlow->NdTraceFlow);
284 break;
285 }
286 }
287 }
288}
289
290
291/**
292 * Returns the smallest free flow trace mod identifier.
293 *
294 * @returns Free flow trace mod identifier.
295 * @param pDbgc The DBGC instance.
296 */
297static uint32_t dbgcFlowTraceModIdFindFree(PDBGC pDbgc)
298{
299 uint32_t iId = 0;
300
301 PDBGCTFLOW pIt;
302 RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
303 {
304 PDBGCTFLOW pNext = RTListGetNext(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow);
305 if ( ( pNext
306 && pIt->iTraceFlowMod + 1 != pNext->iTraceFlowMod)
307 || !pNext)
308 {
309 iId = pIt->iTraceFlowMod + 1;
310 break;
311 }
312 }
313
314 return iId;
315}
316
317
318/**
319 * Adds a flow trace module to the debugger console.
320 *
321 * @returns VBox status code.
322 * @param pDbgc The DBGC instance.
323 * @param hFlowTraceMod The flow trace module to add.
324 * @param hFlow The control flow graph to add.
325 * @param piId Where to store the ID of the module on success.
326 */
327DECLHIDDEN(int) dbgcFlowTraceModAdd(PDBGC pDbgc, DBGFFLOWTRACEMOD hFlowTraceMod, DBGFFLOW hFlow, uint32_t *piId)
328{
329 /*
330 * Add the module.
331 */
332 PDBGCTFLOW pTraceFlow = (PDBGCTFLOW)RTMemAlloc(sizeof(DBGCTFLOW));
333 if (!pTraceFlow)
334 return VERR_NO_MEMORY;
335
336 pTraceFlow->hTraceFlowMod = hFlowTraceMod;
337 pTraceFlow->hFlow = hFlow;
338 pTraceFlow->iTraceFlowMod = dbgcFlowTraceModIdFindFree(pDbgc);
339 dbgcFlowTraceModInsert(pDbgc, pTraceFlow);
340
341 *piId = pTraceFlow->iTraceFlowMod;
342
343 return VINF_SUCCESS;
344}
345
346
347/**
348 * Deletes a breakpoint.
349 *
350 * @returns VBox status code.
351 * @param pDbgc The DBGC instance.
352 * @param iTraceFlowMod The trace flow module identifier.
353 */
354DECLHIDDEN(int) dbgcFlowTraceModDelete(PDBGC pDbgc, uint32_t iTraceFlowMod)
355{
356 int rc = VINF_SUCCESS;
357 PDBGCTFLOW pTraceFlow = dbgcFlowTraceModGet(pDbgc, iTraceFlowMod);
358 if (pTraceFlow)
359 {
360 RTListNodeRemove(&pTraceFlow->NdTraceFlow);
361 RTMemFree(pTraceFlow);
362 }
363 else
364 rc = VERR_DBGC_BP_NOT_FOUND;
365
366 return rc;
367}
368
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