VirtualBox

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

Last change on this file since 29 was 29, checked in by bird, 15 years ago

Finally got around execute the switch to the MIT license.

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