source: trunk/kProfile/kPrf2Read.cpp@ 3526

Last change on this file since 3526 was 3526, checked in by bird, 18 years ago

made it build again.

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