VirtualBox

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

Last change on this file since 96159 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: 13.3 KB
Line 
1/* $Id: RTTraceLogTool.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Utility for reading/receiving and dissecting trace logs.
4 */
5
6/*
7 * Copyright (C) 2018-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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/tracelog.h>
32
33#include <iprt/assert.h>
34#include <iprt/errcore.h>
35#include <iprt/getopt.h>
36#include <iprt/initterm.h>
37#include <iprt/message.h>
38#include <iprt/mem.h>
39#include <iprt/path.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42#include <iprt/tcp.h>
43
44
45/**
46 * The tracelog tool TCP server/client state.
47 */
48typedef struct RTTRACELOGTOOLTCP
49{
50 /** Flag whether this is a server. */
51 bool fIsServer;
52 /** The TCP socket handle for the connection. */
53 RTSOCKET hSock;
54 /** The TCP server. */
55 PRTTCPSERVER pTcpSrv;
56} RTTRACELOGTOOLTCP;
57/** Pointer to the TCP server/client state. */
58typedef RTTRACELOGTOOLTCP *PRTTRACELOGTOOLTCP;
59
60
61static void rtTraceLogTcpDestroy(PRTTRACELOGTOOLTCP pTrcLogTcp)
62{
63 if (pTrcLogTcp->fIsServer)
64 RTTcpServerDestroy(pTrcLogTcp->pTcpSrv);
65 if (pTrcLogTcp->hSock != NIL_RTSOCKET)
66 {
67 if (pTrcLogTcp->fIsServer)
68 RTTcpServerDisconnectClient2(pTrcLogTcp->hSock);
69 else
70 RTTcpClientClose(pTrcLogTcp->hSock);
71 }
72 RTMemFree(pTrcLogTcp);
73}
74
75
76static DECLCALLBACK(int) rtTraceLogToolTcpInput(void *pvUser, void *pvBuf, size_t cbBuf, size_t *pcbRead,
77 RTMSINTERVAL cMsTimeout)
78{
79 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)pvUser;
80 if ( pTrcLogTcp->fIsServer
81 && pTrcLogTcp->hSock == NIL_RTSOCKET)
82 {
83 int rc = RTTcpServerListen2(pTrcLogTcp->pTcpSrv, &pTrcLogTcp->hSock);
84 if (RT_FAILURE(rc))
85 return rc;
86 }
87
88 int rc = RTTcpSelectOne(pTrcLogTcp->hSock, cMsTimeout);
89 if (RT_SUCCESS(rc))
90 rc = RTTcpReadNB(pTrcLogTcp->hSock, pvBuf, cbBuf, pcbRead);
91
92 return rc;
93}
94
95
96static DECLCALLBACK(int) rtTraceLogToolTcpClose(void *pvUser)
97{
98 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)pvUser;
99 rtTraceLogTcpDestroy(pTrcLogTcp);
100 return VINF_SUCCESS;
101}
102
103
104/**
105 * Tries to create a new trace log reader using the given input.
106 *
107 * @returns IPRT status code.
108 * @param phTraceLogRdr Where to store the handle to the trace log reader instance on success.
109 * @param pszInput The input path.
110 * @param pszSave The optional path to save
111 */
112static int rtTraceLogToolReaderCreate(PRTTRACELOGRDR phTraceLogRdr, const char *pszInput, const char *pszSave)
113{
114 RT_NOREF(pszSave);
115
116 /* Try treating the input as a file first. */
117 int rc = RTTraceLogRdrCreateFromFile(phTraceLogRdr, pszInput);
118 if (RT_FAILURE(rc))
119 {
120 /*
121 * Check whether the input looks like a port number or an address:port pair.
122 * The former will create a server listening on the port while the latter tries
123 * to connect to the given address:port combination.
124 */
125 uint32_t uPort = 0;
126 bool fIsServer = false;
127 PRTTCPSERVER pTcpSrv = NULL;
128 RTSOCKET hSock = NIL_RTSOCKET;
129 rc = RTStrToUInt32Full(pszInput, 10, &uPort);
130 if (rc == VINF_SUCCESS)
131 {
132 fIsServer = true;
133 rc = RTTcpServerCreateEx(NULL, uPort, &pTcpSrv);
134 }
135 else
136 {
137 /* Try treating the input as an address:port pair. */
138 }
139
140 if (RT_SUCCESS(rc))
141 {
142 /* Initialize structure and reader. */
143 PRTTRACELOGTOOLTCP pTrcLogTcp = (PRTTRACELOGTOOLTCP)RTMemAllocZ(sizeof(*pTrcLogTcp));
144 if (pTrcLogTcp)
145 {
146 pTrcLogTcp->fIsServer = fIsServer;
147 pTrcLogTcp->hSock = hSock;
148 pTrcLogTcp->pTcpSrv = pTcpSrv;
149 rc = RTTraceLogRdrCreate(phTraceLogRdr, rtTraceLogToolTcpInput, rtTraceLogToolTcpClose, pTrcLogTcp);
150 if (RT_FAILURE(rc))
151 rtTraceLogTcpDestroy(pTrcLogTcp);
152 }
153 else
154 {
155 if (fIsServer)
156 RTTcpServerDestroy(pTcpSrv);
157 else
158 RTSocketClose(hSock);
159 }
160 }
161 }
162 return rc;
163}
164
165
166int main(int argc, char **argv)
167{
168 int rc = RTR3InitExe(argc, &argv, 0);
169 if (RT_FAILURE(rc))
170 return RTMsgInitFailure(rc);
171
172 /*
173 * Parse arguments.
174 */
175 static const RTGETOPTDEF s_aOptions[] =
176 {
177 { "--input", 'i', RTGETOPT_REQ_STRING },
178 { "--save", 's', RTGETOPT_REQ_STRING },
179 { "--help", 'h', RTGETOPT_REQ_NOTHING },
180 { "--version", 'V', RTGETOPT_REQ_NOTHING },
181 };
182
183 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
184 const char *pszInput = NULL;
185 const char *pszSave = NULL;
186
187 RTGETOPTUNION ValueUnion;
188 RTGETOPTSTATE GetState;
189 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
190 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
191 {
192 switch (rc)
193 {
194 case 'h':
195 RTPrintf("Usage: %s [options]\n"
196 "\n"
197 "Options:\n"
198 " -i,--input=<file|port|address:port>\n"
199 " Input path, can be a file a port to start listening on for incoming connections or an address:port to connect to\n"
200 " -s,--save=file\n"
201 " Save the input to a file for later use\n"
202 " -h, -?, --help\n"
203 " Display this help text and exit successfully.\n"
204 " -V, --version\n"
205 " Display the revision and exit successfully.\n"
206 , RTPathFilename(argv[0]));
207 return RTEXITCODE_SUCCESS;
208 case 'V':
209 RTPrintf("$Revision: 93115 $\n");
210 return RTEXITCODE_SUCCESS;
211
212 case 'i':
213 pszInput = ValueUnion.psz;
214 break;
215 case 's':
216 pszSave = ValueUnion.psz;
217 break;
218 default:
219 return RTGetOptPrintError(rc, &ValueUnion);
220 }
221 }
222
223 if (!pszInput)
224 {
225 RTPrintf("An input path must be given\n");
226 return RTEXITCODE_FAILURE;
227 }
228
229 /*
230 * Create trace log reader instance.
231 */
232 RTTRACELOGRDR hTraceLogRdr = NIL_RTTRACELOGRDR;
233 rc = rtTraceLogToolReaderCreate(&hTraceLogRdr, pszInput, pszSave);
234 if (RT_SUCCESS(rc))
235 {
236 do
237 {
238 RTTRACELOGRDRPOLLEVT enmEvt = RTTRACELOGRDRPOLLEVT_INVALID;
239 rc = RTTraceLogRdrEvtPoll(hTraceLogRdr, &enmEvt, RT_INDEFINITE_WAIT);
240 if (RT_SUCCESS(rc))
241 {
242 switch (enmEvt)
243 {
244 case RTTRACELOGRDRPOLLEVT_HDR_RECVD:
245 RTMsgInfo("A valid header was received\n");
246 break;
247 case RTTRACELOGRDRPOLLEVT_TRACE_EVENT_RECVD:
248 {
249 RTTRACELOGRDREVT hTraceLogEvt;
250 rc = RTTraceLogRdrQueryLastEvt(hTraceLogRdr, &hTraceLogEvt);
251 if (RT_SUCCESS(rc))
252 {
253 PCRTTRACELOGEVTDESC pEvtDesc = RTTraceLogRdrEvtGetDesc(hTraceLogEvt);
254 RTMsgInfo("%llu %llu %s\n",
255 RTTraceLogRdrEvtGetSeqNo(hTraceLogEvt),
256 RTTraceLogRdrEvtGetTs(hTraceLogEvt),
257 pEvtDesc->pszId);
258 for (unsigned i = 0; i < pEvtDesc->cEvtItems; i++)
259 {
260 RTTRACELOGEVTVAL Val;
261 unsigned cVals = 0;
262 rc = RTTraceLogRdrEvtFillVals(hTraceLogEvt, i, &Val, 1, &cVals);
263 if (RT_SUCCESS(rc))
264 {
265 switch (Val.pItemDesc->enmType)
266 {
267 case RTTRACELOGTYPE_BOOL:
268 RTMsgInfo(" %s: %s\n", Val.pItemDesc->pszName, Val.u.f ? "true" : "false");
269 break;
270 case RTTRACELOGTYPE_UINT8:
271 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u8);
272 break;
273 case RTTRACELOGTYPE_INT8:
274 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i8);
275 break;
276 case RTTRACELOGTYPE_UINT16:
277 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u16);
278 break;
279 case RTTRACELOGTYPE_INT16:
280 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i16);
281 break;
282 case RTTRACELOGTYPE_UINT32:
283 RTMsgInfo(" %s: %u\n", Val.pItemDesc->pszName, Val.u.u32);
284 break;
285 case RTTRACELOGTYPE_INT32:
286 RTMsgInfo(" %s: %d\n", Val.pItemDesc->pszName, Val.u.i32);
287 break;
288 case RTTRACELOGTYPE_UINT64:
289 RTMsgInfo(" %s: %llu\n", Val.pItemDesc->pszName, Val.u.u64);
290 break;
291 case RTTRACELOGTYPE_INT64:
292 RTMsgInfo(" %s: %lld\n", Val.pItemDesc->pszName, Val.u.i64);
293 break;
294 case RTTRACELOGTYPE_RAWDATA:
295 RTMsgInfo(" %s:\n"
296 "%.*Rhxd\n", Val.pItemDesc->pszName, Val.u.RawData.cb, Val.u.RawData.pb);
297 break;
298 case RTTRACELOGTYPE_FLOAT32:
299 case RTTRACELOGTYPE_FLOAT64:
300 RTMsgInfo(" %s: Float32 and Float64 data not supported yet\n", Val.pItemDesc->pszName);
301 break;
302 case RTTRACELOGTYPE_POINTER:
303 RTMsgInfo(" %s: %#llx\n", Val.pItemDesc->pszName, Val.u.uPtr);
304 break;
305 case RTTRACELOGTYPE_SIZE:
306 RTMsgInfo(" %s: %llu\n", Val.pItemDesc->pszName, Val.u.sz);
307 break;
308 default:
309 RTMsgError(" %s: Invalid type given %d\n", Val.pItemDesc->pszName, Val.pItemDesc->enmType);
310 }
311 }
312 else
313 RTMsgInfo(" Failed to retrieve event data with %Rrc\n", rc);
314 }
315 }
316 break;
317 }
318 default:
319 RTMsgInfo("Invalid event received: %d\n", enmEvt);
320 }
321 }
322 else
323 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Polling for an event failed with %Rrc\n", rc);
324 } while (RT_SUCCESS(rc));
325
326 RTTraceLogRdrDestroy(hTraceLogRdr);
327 }
328 else
329 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create trace log reader with %Rrc\n", rc);
330
331 return rcExit;
332}
333
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