VirtualBox

source: kStuff/trunk/kProfiler2/kPrf2Read.cpp@ 2

Last change on this file since 2 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

  • Property svn:keywords set to Id Revision
File size: 14.1 KB
Line 
1/* $Id: kPrf2Read.cpp 2 2007-11-16 16:07:14Z bird $ */
2/** @file
3 * kProfiler Mark 2 - The reader and producer of statistics.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * This file is part of kProfiler.
10 *
11 * kProfiler is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * kProfiler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with kProfiler; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdarg.h>
35#include <k/kDbg.h>
36
37
38/** @def KPRF_OFF2PTR
39 * Internal helper for converting a offset to a pointer.
40 * @internal
41 */
42#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
43 ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) )
44
45/** @def KPRF_ALIGN
46 * The usual align macro.
47 * @internal
48 */
49#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) )
50
51/** @def KPRF_OFFSETOF
52 * My usual extended offsetof macro, except this returns KU32 and mangles the type name.
53 * @internal
54 */
55#define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member )
56
57/** @def PRF_SIZEOF
58 * Size of a kPrf type.
59 * @internal
60 */
61#define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType))
62
63#ifdef _MSC_VER
64# define KPRF_FMT_U64 "I64u"
65# define KPRF_FMT_X64 "I64x"
66# define KPRF_FMT_I64 "I64d"
67#else
68# define KPRF_FMT_X64 "llx"
69# define KPRF_FMT_U64 "llu"
70# define KPRF_FMT_I64 "lld"
71#endif
72
73
74/*
75 * Instantiate the readers.
76 */
77/* 32-bit */
78#define KPRF_NAME(Suffix) KPrf32##Suffix
79#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix
80#define KPRF_BITS 32
81#define KPRF_FMT_UPTR "#010x"
82
83#include "prfcore.h.h"
84#include "prfreader.cpp.h"
85
86#undef KPRF_FMT_UPTR
87#undef KPRF_NAME
88#undef KPRF_TYPE
89#undef KPRF_BITS
90
91/* 64-bit */
92#define KPRF_NAME(Suffix) KPrf64##Suffix
93#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix
94#define KPRF_BITS 64
95#ifdef _MSC_VER
96# define KPRF_FMT_UPTR "#018I64x"
97#else
98# define KPRF_FMT_UPTR "#018llx"
99#endif
100
101#include "prfcore.h.h"
102#include "prfreader.cpp.h"
103
104#undef KPRF_FMT_UPTR
105#undef KPRF_NAME
106#undef KPRF_TYPE
107#undef KPRF_BITS
108
109
110/*******************************************************************************
111* Structures and Typedefs *
112*******************************************************************************/
113/**
114 * Header union type.
115 */
116typedef union KPRFHDR
117{
118 KPRF32HDR Hdr32;
119 KPRF64HDR Hdr64;
120} KPRFHDR;
121typedef KPRFHDR *PKPRFHDR;
122typedef const KPRFHDR *PCKPRFHDR;
123
124
125
126/**
127 * Read the data set into memory.
128 *
129 * @returns Pointer to the loaded data set. (release using free()).
130 *
131 * @param pszFilename The path to the profiler data set.
132 * @param pcb Where to store the size of the data set.
133 * @param pOut Where to write errors.
134 */
135PKPRFHDR kPrfLoad(const char *pszFilename, KU32 *pcb, FILE *pOut)
136{
137 FILE *pFile = fopen(pszFilename, "rb");
138 if (!pFile)
139 {
140 fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename);
141 return NULL;
142 }
143
144 /*
145 * Read the file into memory.
146 */
147 long cbFile;
148 if ( !fseek(pFile, 0, SEEK_END)
149 && (cbFile = ftell(pFile)) >= 0
150 && !fseek(pFile, 0, SEEK_SET)
151 )
152 {
153 if (pcb)
154 *pcb = cbFile;
155
156 void *pvData = malloc(cbFile);
157 if (pvData)
158 {
159 if (fread(pvData, cbFile, 1, pFile))
160 {
161
162 fclose(pFile);
163 return (PKPRFHDR)pvData;
164 }
165 fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename);
166 free(pvData);
167 }
168 else
169 fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename);
170 }
171 else
172 fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename);
173
174 fclose(pFile);
175 return NULL;
176}
177
178
179/**
180 * Validates the data set
181 *
182 * @returns true if valid.
183 * @returns false if invalid.
184 *
185 * @param pHdr Pointer to the data set.
186 * @param cb The size of the data set.
187 * @param pOut Where to write error messages.
188 */
189static bool kPrfIsValidate(PCKPRFHDR pHdr, KU32 cb, FILE *pOut)
190{
191 /*
192 * We ASSUMES that the header is identicial with the exception
193 * of the uBasePtr size. (this is padded out and the upper bits are all zero)
194 */
195
196 if ( pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC
197 && pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC)
198 {
199 fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic);
200 return false;
201 }
202
203 if ( pHdr->Hdr32.cFormatBits != 32
204 && pHdr->Hdr32.cFormatBits != 64)
205 {
206 fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits);
207 return false;
208 }
209
210 if (pHdr->Hdr32.cb > cb)
211 {
212 fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb);
213 return false;
214 }
215
216#define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\
217 if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \
218 { \
219 fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \
220 (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \
221 return false; \
222 }\
223 } while (0)
224
225 KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC));
226 KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD));
227 KPRF_VALIDATE_SIZE(Stack,
228 (KU32)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames],
229 (KU32)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]);
230
231 KUPTR cbHeader = (KUPTR)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (KUPTR)pHdr;
232 if ( cbHeader != (KU32)cbHeader
233 || cbHeader >= cb)
234 {
235 fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n",
236 pHdr->Hdr32.cFunctions);
237 return false;
238 }
239
240 /* The space assignment is hereby required to be equal to the member order in the header. */
241 KU32 offMin = cbHeader;
242#define KPRF_VALIDATE_OFF(off, name) do {\
243 if ( off > 0 \
244 && off < offMin) \
245 { \
246 fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \
247 return false; \
248 }\
249 if (off >= cb) \
250 { \
251 fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \
252 return false; \
253 }\
254 } while (0)
255#define KPRF_VALIDATE_MEM(MemBaseName) do {\
256 KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \
257 if ( pHdr->Hdr32.off##MemBaseName##s \
258 && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \
259 || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\
260 ) \
261 { \
262 fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \
263 pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \
264 return false; \
265 }\
266 if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \
267 { \
268 fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \
269 pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \
270 return false; \
271 } \
272 if (pHdr->Hdr32.off##MemBaseName##s) \
273 offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \
274 } while (0)
275
276 KPRF_VALIDATE_MEM(Function);
277 KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs);
278 if (pHdr->Hdr32.offModSegs)
279 KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs);
280 if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs)
281 {
282 fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n",
283 pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs);
284 return false;
285 }
286 if (pHdr->Hdr32.offModSegs) \
287 offMin += pHdr->Hdr32.cbMaxModSegs; \
288 KPRF_VALIDATE_MEM(Thread);
289 KPRF_VALIDATE_MEM(Stack);
290 KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine);
291 KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine);
292
293 /*
294 * Validate the function lookup table
295 */
296 for (KU32 i = 0; i < pHdr->Hdr32.cFunctions; i++)
297 if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions)
298 {
299 fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n",
300 i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions);
301 return false;
302 }
303
304 /*
305 * Validate the functions.
306 */
307 switch (pHdr->Hdr32.cFormatBits)
308 {
309 case 32:
310 return KPrf32IsValid(&pHdr->Hdr32, cb, pOut);
311
312 case 64:
313 return KPrf64IsValid(&pHdr->Hdr64, cb, pOut);
314 }
315 return false;
316#undef KPRF_VALIDATE_SIZE
317#undef KPRF_VALIDATE_MEM
318#undef KPRF_VALIDATE_OFF
319}
320
321
322/**
323 * Dumps a kProfiler 2 format file.
324 *
325 * @returns 0 on success.
326 * @returns -1 on failure.
327 *
328 * @param pszFilename The path to the profiler data set.
329 * @param pOut Where to write the output.
330 */
331int KPrfDumpFile(const char *pszFilename, FILE *pOut)
332{
333 /*
334 * Load and validate the data set.
335 */
336 KU32 cb;
337 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
338 if (!pHdr)
339 return -1;
340 if (!kPrfIsValidate(pHdr, cb, pOut))
341 return -1;
342
343 /*
344 * Switch to the appropirate dumper routine.
345 */
346 int rc;
347 switch (pHdr->Hdr32.cFormatBits)
348 {
349 case 32:
350 rc = KPrf32Dump(&pHdr->Hdr32, pOut);
351 break;
352
353 case 64:
354 rc = KPrf64Dump(&pHdr->Hdr64, pOut);
355 break;
356
357 default:
358 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
359 rc = -1;
360 break;
361 }
362
363 return rc;
364}
365
366
367/**
368 * Creates a HTML report from a kProfiler 2 format file.
369 *
370 * @returns 0 on success.
371 * @returns -1 on failure.
372 *
373 * @param pszFilename The path to the profiler data set.
374 * @param pOut Where to write the output.
375 */
376int KPrfHtmlReport(const char *pszFilename, FILE *pOut)
377{
378 /*
379 * Load and validate the data set.
380 */
381 KU32 cb;
382 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
383 if (!pHdr)
384 return -1;
385 if (!kPrfIsValidate(pHdr, cb, pOut))
386 return -1;
387
388 /*
389 * Switch to the appropirate dumper routine.
390 */
391 int rc;
392 switch (pHdr->Hdr32.cFormatBits)
393 {
394 case 32:
395 {
396 PKPRF32REPORT pReport;
397 rc = KPrf32Analyse(&pHdr->Hdr32, &pReport);
398 if (!rc)
399 {
400 rc = KPrf32WriteHtmlReport(pReport, pOut);
401 if (rc)
402 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
403 KPrf32DeleteReport(pReport);
404 }
405 else
406 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
407 break;
408 }
409
410 case 64:
411 {
412 PKPRF64REPORT pReport;
413 rc = KPrf64Analyse(&pHdr->Hdr64, &pReport);
414 if (!rc)
415 {
416 rc = KPrf64WriteHtmlReport(pReport, pOut);
417 if (rc)
418 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
419 KPrf64DeleteReport(pReport);
420 }
421 else
422 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
423 break;
424 }
425
426 default:
427 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
428 rc = -1;
429 break;
430 }
431
432 return rc;
433}
434
435
436
437/**
438 * Prints the usage.
439 */
440static int Usage(void)
441{
442 printf("kProfiler MK2 - Reader & Producer of Statistics\n"
443 "usage: kPrf2Read [-r|-d] <file1> [[-r|-d] file2 []]\n"
444 );
445 return 1;
446}
447
448
449int main(int argc, char **argv)
450{
451 /*
452 * Parse arguments.
453 */
454 if (argc <= 1)
455 return Usage();
456 enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP;
457 for (int i = 1; i < argc; i++)
458 {
459 if (argv[i][0] == '-')
460 {
461 switch (argv[i][1])
462 {
463 case 'h':
464 case 'H':
465 case '?':
466 case '-':
467 return Usage();
468
469 case 'd':
470 enmOp = OP_DUMP;
471 break;
472
473 case 'r':
474 enmOp = OP_HTML;
475 break;
476
477 default:
478 printf("Syntax error: Unknown argument '%s'\n", argv[i]);
479 return 1;
480 }
481 }
482 else
483 {
484 int rc;
485 switch (enmOp)
486 {
487 case OP_DUMP:
488 rc = KPrfDumpFile(argv[i], stdout);
489 break;
490 case OP_HTML:
491 rc = KPrfHtmlReport(argv[i], stdout);
492 break;
493 }
494 if (rc)
495 return rc;
496 }
497 }
498
499 return 0;
500}
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