VirtualBox

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

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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