VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTTraceLogTool.cpp@ 106020

Last change on this file since 106020 was 104975, checked in by vboxsync, 5 months ago

Runtime/tools/RTTraceLogTool: Allow saving a tracelog received over network to a local file, bugref:10701

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1/* $Id: RTTraceLogTool.cpp 104975 2024-06-20 10:17:11Z vboxsync $ */
2/** @file
3 * IPRT - Utility for reading/receiving and dissecting trace logs.
4 */
5
6/*
7 * Copyright (C) 2018-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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/tracelog.h>
42#include <iprt/tracelog-decoder-plugin.h>
43
44#include <iprt/assert.h>
45#include <iprt/errcore.h>
46#include <iprt/file.h>
47#include <iprt/getopt.h>
48#include <iprt/initterm.h>
49#include <iprt/ldr.h>
50#include <iprt/message.h>
51#include <iprt/mem.h>
52#include <iprt/path.h>
53#include <iprt/stream.h>
54#include <iprt/string.h>
55#include <iprt/tcp.h>
56
57
58typedef struct RTTRACELOGDECODER
59{
60 /** The tracelog decoder registration structure. */
61 PCRTTRACELOGDECODERREG pReg;
62 /** The helper structure for this decoder. */
63 RTTRACELOGDECODERHLP Hlp;
64 /** The decoder state if created. */
65 void *pvDecoderState;
66 /** The free callback of any attached decoder state. */
67 PFNTRACELOGDECODERSTATEFREE pfnDecoderStateFree;
68 /** Current struct nesting level. */
69 uint32_t cStructNesting;
70 /** Current array level nesting. */
71 uint32_t cArrayNesting;
72} RTTRACELOGDECODER;
73typedef RTTRACELOGDECODER *PRTTRACELOGDECODER;
74typedef const RTTRACELOGDECODER *PCRTTRACELOGDECODER;
75
76
77/**
78 * Loaded tracelog decoders.
79 */
80typedef struct RTTRACELOGDECODERSTATE
81{
82 /** Pointer to the array of registered decoders. */
83 PRTTRACELOGDECODER paDecoders;
84 /** Number of entries in the decoder array. */
85 uint32_t cDecoders;
86 /** Allocation size of the decoder array. */
87 uint32_t cDecodersAlloc;
88} RTTRACELOGDECODERSTATE;
89typedef RTTRACELOGDECODERSTATE *PRTTRACELOGDECODERSTATE;
90
91
92/**
93 * The tracelog tool TCP server/client state.
94 */
95typedef struct RTTRACELOGTOOLTCP
96{
97 /** Flag whether this is a server. */
98 bool fIsServer;
99 /** The TCP socket handle for the connection. */
100 RTSOCKET hSock;
101 /** The TCP server. */
102 PRTTCPSERVER pTcpSrv;
103 /** File to save the read data to. */
104 RTFILE hFile;
105} RTTRACELOGTOOLTCP;
106/** Pointer to the TCP server/client state. */
107typedef RTTRACELOGTOOLTCP *PRTTRACELOGTOOLTCP;
108
109
110static void rtTraceLogTcpDestroy(PRTTRACELOGTOOLTCP pTrcLogTcp)
111{
112 if (pTrcLogTcp->fIsServer)
113 RTTcpServerDestroy(pTrcLogTcp->pTcpSrv);
114 if (pTrcLogTcp->hSock != NIL_RTSOCKET)
115 {
116 if (pTrcLogTcp->fIsServer)
117 RTTcpServerDisconnectClient2(pTrcLogTcp->hSock);
118 else
119 RTTcpClientClose(pTrcLogTcp->hSock);
120 }
121 if (pTrcLogTcp->hFile != NIL_RTFILE)
122 {
123 RTFileClose(pTrcLogTcp->hFile);
124 pTrcLogTcp->hFile = NIL_RTFILE;
125 }
126 RTMemFree(pTrcLogTcp);
127}
128
129
130static DECLCALLBACK(int) rtTraceLogToolTcpInput(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead,
131 RTMSINTERVAL cMsTimeout)
132{
133 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)pvUser;
134 if ( pTrcLogTcp->fIsServer
135 && pTrcLogTcp->hSock == NIL_RTSOCKET)
136 {
137 int rc = RTTcpServerListen2(pTrcLogTcp->pTcpSrv, &pTrcLogTcp->hSock);
138 if (RT_FAILURE(rc))
139 return rc;
140 }
141
142 int rc = RTTcpSelectOne(pTrcLogTcp->hSock, cMsTimeout);
143 if (RT_SUCCESS(rc))
144 rc = RTTcpReadNB(pTrcLogTcp->hSock, pvBuf, cbBuf, pcbRead);
145
146 if ( RT_SUCCESS(rc)
147 && pTrcLogTcp->hFile != NIL_RTFILE)
148 {
149 int rc2 = RTFileWrite(pTrcLogTcp->hFile, pvBuf, *pcbRead, NULL);
150 if (RT_FAILURE(rc2))
151 RTMsgError("Failed to write received data to save file: %Rrc\n", rc2);
152 }
153
154 return rc;
155}
156
157
158static DECLCALLBACK(int) rtTraceLogToolTcpClose(void *pvUser)
159{
160 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)pvUser;
161 rtTraceLogTcpDestroy(pTrcLogTcp);
162 return VINF_SUCCESS;
163}
164
165
166/**
167 * Tries to create a new trace log reader using the given input.
168 *
169 * @returns IPRT status code.
170 * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success.
171 * @param pszInput The input path.
172 * @param pszSave The optional path to save
173 */
174static int rtTraceLogToolReaderCreate(PRTTRACELOGRDR phTraceLogRdr, const char *pszInput, const char *pszSave)
175{
176 /* Try treating the input as a file first. */
177 int rc = RTTraceLogRdrCreateFromFile(phTraceLogRdr, pszInput);
178 if (RT_FAILURE(rc))
179 {
180 /*
181 * Check whether the input looks like a port number or an address:port pair.
182 * The former will create a server listening on the port while the latter tries
183 * to connect to the given address:port combination.
184 */
185 uint32_t uPort = 0;
186 bool fIsServer = false;
187 PRTTCPSERVER pTcpSrv = NULL;
188 RTSOCKET hSock = NIL_RTSOCKET;
189 rc = RTStrToUInt32Full(pszInput, 10, &uPort);
190 if (rc == VINF_SUCCESS)
191 {
192 fIsServer = true;
193 rc = RTTcpServerCreateEx(NULL, uPort, &pTcpSrv);
194 }
195 else
196 {
197 /* Try treating the input as an address:port pair. */
198 }
199
200 if (RT_SUCCESS(rc))
201 {
202 /* Initialize structure and reader. */
203 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)RTMemAllocZ(sizeof(*pTrcLogTcp));
204 if (pTrcLogTcp)
205 {
206 pTrcLogTcp->fIsServer = fIsServer;
207 pTrcLogTcp->hSock = hSock;
208 pTrcLogTcp->pTcpSrv = pTcpSrv;
209 rc = RTTraceLogRdrCreate(phTraceLogRdr, rtTraceLogToolTcpInput, rtTraceLogToolTcpClose, pTrcLogTcp);
210 if (RT_FAILURE(rc))
211 rtTraceLogTcpDestroy(pTrcLogTcp);
212
213 if (pszSave)
214 {
215 rc = RTFileOpen(&pTrcLogTcp->hFile, pszSave, RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_READWRITE);
216 if (RT_FAILURE(rc))
217 rtTraceLogTcpDestroy(pTrcLogTcp);
218 }
219 }
220 else
221 {
222 if (fIsServer)
223 RTTcpServerDestroy(pTcpSrv);
224 else
225 RTSocketClose(hSock);
226 }
227 }
228 }
229 return rc;
230}
231
232
233static DECLCALLBACK(int) rtTraceLogToolDecoderHlpPrintf(PRTTRACELOGDECODERHLP pHlp, const char *pszFormat, ...)
234{
235 RT_NOREF(pHlp);
236 va_list Args;
237 va_start(Args, pszFormat);
238 int rc = RTPrintfV(pszFormat, Args);
239 va_end(Args);
240 return rc;
241}
242
243
244static DECLCALLBACK(int) rtTraceLogToolDecoderHlpErrorMsg(PRTTRACELOGDECODERHLP pHlp, const char *pszFormat, ...)
245{
246 RT_NOREF(pHlp);
247 va_list Args;
248 va_start(Args, pszFormat);
249 int rc = RTMsgErrorV(pszFormat, Args);
250 va_end(Args);
251 return rc;
252}
253
254
255static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStateCreate(PRTTRACELOGDECODERHLP pHlp, size_t cbState, PFNTRACELOGDECODERSTATEFREE pfnFree,
256 void **ppvState)
257{
258 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
259
260 if (pDecoder->pvDecoderState)
261 {
262 if (pDecoder->pfnDecoderStateFree)
263 pDecoder->pfnDecoderStateFree(pHlp, pDecoder->pvDecoderState);
264 RTMemFree(pDecoder->pvDecoderState);
265 pDecoder->pvDecoderState = NULL;
266 pDecoder->pfnDecoderStateFree = NULL;
267 }
268
269 pDecoder->pvDecoderState = RTMemAllocZ(cbState);
270 if (pDecoder->pvDecoderState)
271 {
272 pDecoder->pfnDecoderStateFree = pfnFree;
273 *ppvState = pDecoder->pvDecoderState;
274 return VINF_SUCCESS;
275 }
276
277 return VERR_NO_MEMORY;
278}
279
280
281static DECLCALLBACK(void) rtTraceLogToolDecoderHlpStateDestroy(PRTTRACELOGDECODERHLP pHlp)
282{
283 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
284
285 if (pDecoder->pvDecoderState)
286 {
287 if (pDecoder->pfnDecoderStateFree)
288 pDecoder->pfnDecoderStateFree(pHlp, pDecoder->pvDecoderState);
289 RTMemFree(pDecoder->pvDecoderState);
290 pDecoder->pvDecoderState = NULL;
291 pDecoder->pfnDecoderStateFree = NULL;
292 }
293}
294
295
296static DECLCALLBACK(void*) rtTraceLogToolDecoderHlpStateGet(PRTTRACELOGDECODERHLP pHlp)
297{
298 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
299
300 return pDecoder->pvDecoderState;
301}
302
303
304static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldBegin(PRTTRACELOGDECODERHLP pHlp, const char *pszName)
305{
306 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
307
308 RTPrintf("%*s%s:\n", pDecoder->cStructNesting * 4, "", pszName);
309 pDecoder->cStructNesting++;
310 return VINF_SUCCESS;
311}
312
313
314static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldEnd(PRTTRACELOGDECODERHLP pHlp)
315{
316 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
317
318 pDecoder->cStructNesting--;
319 return VINF_SUCCESS;
320}
321
322
323static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddBool(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, bool f)
324{
325 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
326
327 RT_NOREF(fFlags);
328 RTPrintf("%*s%-16s %32RTbool\n", pDecoder->cStructNesting * 4, "", pszName, f);
329 return VINF_SUCCESS;
330}
331
332
333static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddU8(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, uint8_t u8)
334{
335 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
336
337 if (pszName)
338 {
339 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
340 RTPrintf("%*s%-16s %#32RX8\n", pDecoder->cStructNesting * 4, "", pszName, u8);
341 else
342 RTPrintf("%*s%-16s %32RU8\n", pDecoder->cStructNesting * 4, "", pszName, u8);
343 }
344 else
345 {
346 Assert(pDecoder->cArrayNesting > 0);
347 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
348 RTPrintf(" %#02RX8", u8);
349 else
350 RTPrintf(" %02RU8", u8);
351 }
352 return VINF_SUCCESS;
353}
354
355
356static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddU16(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, uint16_t u16)
357{
358 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
359
360 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
361 RTPrintf("%*s%-16s %#32RX16\n", pDecoder->cStructNesting * 4, "", pszName, u16);
362 else
363 RTPrintf("%*s%-16s %32RU16\n", pDecoder->cStructNesting * 4, "", pszName, u16);
364 return VINF_SUCCESS;
365}
366
367
368static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddU32(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, uint32_t u32)
369{
370 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
371
372 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
373 RTPrintf("%*s%-16s %#32RX32\n", pDecoder->cStructNesting * 4, "", pszName, u32);
374 else
375 RTPrintf("%*s%-16s %32RU32\n", pDecoder->cStructNesting * 4, "", pszName, u32);
376 return VINF_SUCCESS;
377}
378
379
380static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddU64(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, uint64_t u64)
381{
382 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
383
384 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
385 RTPrintf("%*s%-16s %#32RX64\n", pDecoder->cStructNesting * 4, "", pszName, u64);
386 else
387 RTPrintf("%*s%-16s %32RU64\n", pDecoder->cStructNesting * 4, "", pszName, u64);
388 return VINF_SUCCESS;
389}
390
391
392static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddS8(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, int8_t i8)
393{
394 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
395
396 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
397 RTPrintf("%*s%-16s %#32RX8\n", pDecoder->cStructNesting * 4, "", pszName, i8);
398 else
399 RTPrintf("%*s%-16s %32RI8\n", pDecoder->cStructNesting * 4, "", pszName, i8);
400 return VINF_SUCCESS;
401}
402
403
404static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddS16(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, int16_t i16)
405{
406 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
407
408 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
409 RTPrintf("%*s%-16s %#32RX16\n", pDecoder->cStructNesting * 4, "", pszName, i16);
410 else
411 RTPrintf("%*s%-16s %32RI16\n", pDecoder->cStructNesting * 4, "", pszName, i16);
412 return VINF_SUCCESS;
413}
414
415
416static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddS32(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, int32_t i32)
417{
418 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
419
420 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
421 RTPrintf("%*s%-16s %#RX32\n", pDecoder->cStructNesting * 4, "", pszName, i32);
422 else
423 RTPrintf("%*s%-16s %RI32\n", pDecoder->cStructNesting * 4, "", pszName, i32);
424 return VINF_SUCCESS;
425}
426
427
428static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddS64(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, int64_t i64)
429{
430 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
431
432 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
433 RTPrintf("%*s%-16s %#RX64\n", pDecoder->cStructNesting * 4, "", pszName, i64);
434 else
435 RTPrintf("%*s%-16s %RI64\n", pDecoder->cStructNesting * 4, "", pszName, i64);
436 return VINF_SUCCESS;
437}
438
439
440static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddStr(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, const char *pszStr)
441{
442 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
443
444 RT_NOREF(fFlags);
445 RTPrintf("%*s%-16s %32s\n", pDecoder->cStructNesting * 4, "", pszName, pszStr);
446 return VINF_SUCCESS;
447}
448
449
450static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddBuf(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, const uint8_t *pb, size_t cb)
451{
452 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
453
454 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX_DUMP_STR)
455 RTPrintf("%*s%-16s %.*Rhxs\n", pDecoder->cStructNesting * 4, "", pszName, cb, pb);
456 else
457 RTPrintf("%*s%-16s\n"
458 "%.*Rhxd\n", pDecoder->cStructNesting * 4, "", pszName, cb, pb);
459 return VINF_SUCCESS;
460}
461
462
463static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldAddEnum(PRTTRACELOGDECODERHLP pHlp, const char *pszName, uint32_t fFlags, uint8_t cBits,
464 PCRTTRACELOGDECODERSTRUCTBLDENUM paEnums, uint64_t u64Val)
465{
466 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
467
468 const char *pszEnum = "<UNKNOWN>";
469 while (paEnums->pszString)
470 {
471 if (paEnums->u64EnumVal == u64Val)
472 {
473 pszEnum = paEnums->pszString;
474 break;
475 }
476 paEnums++;
477 }
478
479 RT_NOREF(cBits);
480 if (fFlags & RTTRACELOG_DECODER_HLP_STRUCT_BLD_F_HEX)
481 RTPrintf("%*s%-16s 0x%0*RX64 (%s)\n", pDecoder->cStructNesting * 4, "", pszName, cBits / 4, u64Val, pszEnum);
482 else
483 RTPrintf("%*s%-16s %RU64 (%s)\n", pDecoder->cStructNesting * 4, "", pszName, u64Val, pszEnum);
484 return VINF_SUCCESS;
485}
486
487
488static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldArrayBegin(PRTTRACELOGDECODERHLP pHlp, const char *pszName)
489{
490 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
491
492 RTPrintf("%*s%-16s [", pDecoder->cStructNesting * 4, "", pszName);
493 Assert(!pDecoder->cArrayNesting);
494 pDecoder->cArrayNesting++;
495 return VINF_SUCCESS;
496}
497
498
499static DECLCALLBACK(int) rtTraceLogToolDecoderHlpStructBldArrayEnd(PRTTRACELOGDECODERHLP pHlp)
500{
501 PRTTRACELOGDECODER pDecoder = RT_FROM_MEMBER(pHlp, RTTRACELOGDECODER, Hlp);
502 RTPrintf(" ]\n");
503 Assert(pDecoder->cArrayNesting > 0);
504 pDecoder->cArrayNesting--;
505 return VINF_SUCCESS;
506}
507
508
509static DECLCALLBACK(int) rtTraceLogToolRegisterDecoders(void *pvUser, PCRTTRACELOGDECODERREG paDecoders, uint32_t cDecoders)
510{
511 PRTTRACELOGDECODERSTATE pDecoderState = (PRTTRACELOGDECODERSTATE)pvUser;
512
513 if (pDecoderState->cDecodersAlloc - pDecoderState->cDecoders <= cDecoders)
514 {
515 PRTTRACELOGDECODER paNew = (PRTTRACELOGDECODER)RTMemRealloc(pDecoderState->paDecoders,
516 (pDecoderState->cDecodersAlloc + cDecoders) * sizeof(*paNew));
517 if (!paNew)
518 return VERR_NO_MEMORY;
519
520 pDecoderState->paDecoders = paNew;
521 pDecoderState->cDecodersAlloc += cDecoders;
522 }
523
524 for (uint32_t i = 0; i < cDecoders; i++)
525 {
526 PRTTRACELOGDECODER pDecoder = &pDecoderState->paDecoders[i];
527
528 pDecoder->pReg = &paDecoders[i];
529 pDecoder->pvDecoderState = NULL;
530 pDecoder->pfnDecoderStateFree = NULL;
531 pDecoder->cStructNesting = 0;
532 pDecoder->cArrayNesting = 0;
533 pDecoder->Hlp.pfnPrintf = rtTraceLogToolDecoderHlpPrintf;
534 pDecoder->Hlp.pfnErrorMsg = rtTraceLogToolDecoderHlpErrorMsg;
535 pDecoder->Hlp.pfnDecoderStateCreate = rtTraceLogToolDecoderHlpStateCreate;
536 pDecoder->Hlp.pfnDecoderStateDestroy = rtTraceLogToolDecoderHlpStateDestroy;
537 pDecoder->Hlp.pfnDecoderStateGet = rtTraceLogToolDecoderHlpStateGet;
538 pDecoder->Hlp.pfnStructBldBegin = rtTraceLogToolDecoderHlpStructBldBegin;
539 pDecoder->Hlp.pfnStructBldEnd = rtTraceLogToolDecoderHlpStructBldEnd;
540 pDecoder->Hlp.pfnStructBldAddBool = rtTraceLogToolDecoderHlpStructBldAddBool;
541 pDecoder->Hlp.pfnStructBldAddU8 = rtTraceLogToolDecoderHlpStructBldAddU8;
542 pDecoder->Hlp.pfnStructBldAddU16 = rtTraceLogToolDecoderHlpStructBldAddU16;
543 pDecoder->Hlp.pfnStructBldAddU32 = rtTraceLogToolDecoderHlpStructBldAddU32;
544 pDecoder->Hlp.pfnStructBldAddU64 = rtTraceLogToolDecoderHlpStructBldAddU64;
545 pDecoder->Hlp.pfnStructBldAddS8 = rtTraceLogToolDecoderHlpStructBldAddS8;
546 pDecoder->Hlp.pfnStructBldAddS16 = rtTraceLogToolDecoderHlpStructBldAddS16;
547 pDecoder->Hlp.pfnStructBldAddS32 = rtTraceLogToolDecoderHlpStructBldAddS32;
548 pDecoder->Hlp.pfnStructBldAddS64 = rtTraceLogToolDecoderHlpStructBldAddS64;
549 pDecoder->Hlp.pfnStructBldAddStr = rtTraceLogToolDecoderHlpStructBldAddStr;
550 pDecoder->Hlp.pfnStructBldAddBuf = rtTraceLogToolDecoderHlpStructBldAddBuf;
551 pDecoder->Hlp.pfnStructBldAddEnum = rtTraceLogToolDecoderHlpStructBldAddEnum;
552 pDecoder->Hlp.pfnStructBldArrayBegin = rtTraceLogToolDecoderHlpStructBldArrayBegin;
553 pDecoder->Hlp.pfnStructBldArrayEnd = rtTraceLogToolDecoderHlpStructBldArrayEnd;
554 }
555
556 pDecoderState->cDecoders += cDecoders;
557 return VINF_SUCCESS;
558}
559
560
561int main(int argc, char **argv)
562{
563 int rc = RTR3InitExe(argc, &argv, 0);
564 if (RT_FAILURE(rc))
565 return RTMsgInitFailure(rc);
566
567 /*
568 * Parse arguments.
569 */
570 static const RTGETOPTDEF s_aOptions[] =
571 {
572 { "--input", 'i', RTGETOPT_REQ_STRING },
573 { "--save", 's', RTGETOPT_REQ_STRING },
574 { "--load-decoder", 'l', RTGETOPT_REQ_STRING },
575 { "--help", 'h', RTGETOPT_REQ_NOTHING },
576 { "--version", 'V', RTGETOPT_REQ_NOTHING },
577 };
578
579 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
580 const char *pszInput = NULL;
581 const char *pszSave = NULL;
582 RTTRACELOGDECODERSTATE DecoderState; RT_ZERO(DecoderState);
583
584 RTGETOPTUNION ValueUnion;
585 RTGETOPTSTATE GetState;
586 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
587 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
588 {
589 switch (rc)
590 {
591 case 'h':
592 RTPrintf("Usage: %s [options]\n"
593 "\n"
594 "Options:\n"
595 " -i,--input=<file|port|address:port>\n"
596 " Input path, can be a file a port to start listening on for incoming connections or an address:port to connect to\n"
597 " -s,--save=file\n"
598 " Save the input to a file for later use\n"
599 " -l,--load-decoder=<plugin path>\n"
600 " Loads the given decoder library used for decoding events\n"
601 " -h, -?, --help\n"
602 " Display this help text and exit successfully.\n"
603 " -V, --version\n"
604 " Display the revision and exit successfully.\n"
605 , RTPathFilename(argv[0]));
606 return RTEXITCODE_SUCCESS;
607 case 'V':
608 RTPrintf("$Revision: 104975 $\n");
609 return RTEXITCODE_SUCCESS;
610
611 case 'i':
612 pszInput = ValueUnion.psz;
613 break;
614 case 's':
615 pszSave = ValueUnion.psz;
616 break;
617 case 'l':
618 {
619 RTLDRMOD hLdrMod;
620 rc = RTLdrLoadEx(ValueUnion.psz, &hLdrMod, RTLDRLOAD_FLAGS_NO_UNLOAD, NULL);
621 if (RT_SUCCESS(rc))
622 {
623 PFNTRACELOGDECODERPLUGINLOAD pfnLoad = NULL;
624 rc = RTLdrGetSymbol(hLdrMod, RT_TRACELOG_DECODER_PLUGIN_LOAD, (void **)&pfnLoad);
625 if (RT_SUCCESS(rc))
626 {
627 RTTRACELOGDECODERREGISTER RegCb;
628
629 RegCb.u32Version = RT_TRACELOG_DECODERREG_CB_VERSION;
630 RegCb.pfnRegisterDecoders = rtTraceLogToolRegisterDecoders;
631
632 rc = pfnLoad(&DecoderState, &RegCb);
633 if (RT_FAILURE(rc))
634 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to register decoders %Rrc\n", rc);
635 }
636 else
637 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to lretrieve entry point '%s' %Rrc\n",
638 RT_TRACELOG_DECODER_PLUGIN_LOAD, rc);
639
640 RTLdrClose(hLdrMod);
641 }
642 else
643 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to load decoder library %Rrc\n", rc);
644 break;
645 }
646 default:
647 return RTGetOptPrintError(rc, &ValueUnion);
648 }
649 }
650
651 if (!pszInput)
652 {
653 RTPrintf("An input path must be given\n");
654 return RTEXITCODE_FAILURE;
655 }
656
657 /*
658 * Create trace log reader instance.
659 */
660 RTTRACELOGRDR hTraceLogRdr = NIL_RTTRACELOGRDR;
661 rc = rtTraceLogToolReaderCreate(&hTraceLogRdr, pszInput, pszSave);
662 if (RT_SUCCESS(rc))
663 {
664 do
665 {
666 RTTRACELOGRDRPOLLEVT enmEvt = RTTRACELOGRDRPOLLEVT_INVALID;
667 rc = RTTraceLogRdrEvtPoll(hTraceLogRdr, &enmEvt, RT_INDEFINITE_WAIT);
668 if (RT_SUCCESS(rc))
669 {
670 switch (enmEvt)
671 {
672 case RTTRACELOGRDRPOLLEVT_HDR_RECVD:
673 RTMsgInfo("A valid header was received\n");
674 break;
675 case RTTRACELOGRDRPOLLEVT_TRACE_EVENT_RECVD:
676 {
677 RTTRACELOGRDREVT hTraceLogEvt;
678 rc = RTTraceLogRdrQueryLastEvt(hTraceLogRdr, &hTraceLogEvt);
679 if (RT_SUCCESS(rc))
680 {
681 PCRTTRACELOGEVTDESC pEvtDesc = RTTraceLogRdrEvtGetDesc(hTraceLogEvt);
682 RTMsgInfo("%llu %llu %s\n",
683 RTTraceLogRdrEvtGetSeqNo(hTraceLogEvt),
684 RTTraceLogRdrEvtGetTs(hTraceLogEvt),
685 pEvtDesc->pszId);
686
687 /*
688 * Look through our registered decoders and pass the decoding on to it.
689 * If there is no decoder registered just dump the raw values.
690 */
691 PRTTRACELOGDECODER pDecoder = NULL;
692 PCRTTRACELOGDECODEEVT pDecodeEvt = NULL;
693 for (uint32_t i = 0; (i < DecoderState.cDecoders) && !pDecoder; i++)
694 {
695 PCRTTRACELOGDECODEEVT pTmp = DecoderState.paDecoders[i].pReg->paEvtIds;
696 while (pTmp->pszEvtId)
697 {
698 if (!strcmp(pTmp->pszEvtId, pEvtDesc->pszId))
699 {
700 pDecoder = &DecoderState.paDecoders[i];
701 pDecodeEvt = pTmp;
702 break;
703 }
704 pTmp++;
705 }
706 }
707
708 if (pDecoder)
709 {
710 Assert(pDecodeEvt);
711
712 /** @todo Dynamic value allocation (too lazy right now). */
713 RTTRACELOGEVTVAL aVals[32];
714 uint32_t cVals = 0;
715 rc = RTTraceLogRdrEvtFillVals(hTraceLogEvt, 0, &aVals[0], RT_ELEMENTS(aVals),
716 &cVals);
717 if ( RT_SUCCESS(rc)
718 || cVals != pEvtDesc->cEvtItems)
719 {
720 pDecoder->cStructNesting = 0;
721 pDecoder->cArrayNesting = 0;
722 rc = pDecoder->pReg->pfnDecode(&pDecoder->Hlp, pDecodeEvt->idDecodeEvt, hTraceLogEvt,
723 pEvtDesc, &aVals[0], cVals);
724 if (RT_FAILURE(rc))
725 RTMsgError("Failed to decode event with ID '%s' -> %Rrc\n", pEvtDesc->pszId, rc);
726 }
727 else
728 RTMsgError("Failed to fill values for event with ID '%s' -> %Rrc (cVals=%u vs. cEvtItems=%u)\n",
729 pEvtDesc->pszId, rc, cVals, pEvtDesc->cEvtItems);
730 }
731 else
732 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
733 {
734 RTTRACELOGEVTVAL Val;
735 unsigned cVals = 0;
736 rc = RTTraceLogRdrEvtFillVals(hTraceLogEvt, i, &Val, 1, &cVals);
737 if (RT_SUCCESS(rc))
738 {
739 switch (Val.pItemDesc->enmType)
740 {
741 case RTTRACELOGTYPE_BOOL:
742 RTMsgInfo(" %s: %s\n", Val.pItemDesc->pszName, Val.u.f ? "true" : "false");
743 break;
744 case RTTRACELOGTYPE_UINT8:
745 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u8);
746 break;
747 case RTTRACELOGTYPE_INT8:
748 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i8);
749 break;
750 case RTTRACELOGTYPE_UINT16:
751 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u16);
752 break;
753 case RTTRACELOGTYPE_INT16:
754 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i16);
755 break;
756 case RTTRACELOGTYPE_UINT32:
757 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u32);
758 break;
759 case RTTRACELOGTYPE_INT32:
760 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i32);
761 break;
762 case RTTRACELOGTYPE_UINT64:
763 RTMsgInfo(" %s: %llu\n", Val.pItemDesc->pszName, Val.u.u64);
764 break;
765 case RTTRACELOGTYPE_INT64:
766 RTMsgInfo(" %s: %lld\n", Val.pItemDesc->pszName, Val.u.i64);
767 break;
768 case RTTRACELOGTYPE_RAWDATA:
769 RTMsgInfo(" %s:\n"
770 "%.*Rhxd\n", Val.pItemDesc->pszName, Val.u.RawData.cb, Val.u.RawData.pb);
771 break;
772 case RTTRACELOGTYPE_FLOAT32:
773 case RTTRACELOGTYPE_FLOAT64:
774 RTMsgInfo(" %s: Float32 and Float64 data not supported yet\n", Val.pItemDesc->pszName);
775 break;
776 case RTTRACELOGTYPE_POINTER:
777 RTMsgInfo(" %s: %#llx\n", Val.pItemDesc->pszName, Val.u.uPtr);
778 break;
779 case RTTRACELOGTYPE_SIZE:
780 RTMsgInfo(" %s: %llu\n", Val.pItemDesc->pszName, Val.u.sz);
781 break;
782 default:
783 RTMsgError(" %s: Invalid type given %d\n", Val.pItemDesc->pszName, Val.pItemDesc->enmType);
784 }
785 }
786 else
787 RTMsgInfo(" Failed to retrieve event data with %Rrc\n", rc);
788 }
789 }
790 break;
791 }
792 default:
793 RTMsgInfo("Invalid event received: %d\n", enmEvt);
794 }
795 }
796 else
797 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Polling for an event failed with %Rrc\n", rc);
798 } while (RT_SUCCESS(rc));
799
800 RTTraceLogRdrDestroy(hTraceLogRdr);
801 }
802 else
803 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create trace log reader with %Rrc\n", rc);
804
805 return rcExit;
806}
807
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