1 /*
2 * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of Oracle nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * This source code is provided to illustrate the usage of a given feature
34 * or technique and has been deliberately simplified. Additional steps
35 * required for a production-quality application, such as security checks,
36 * input validation and proper error handling, might not be present in
37 * this sample code.
38 */
39
40
41 /* Functionality for checking hprof format=b output. */
42
43 /* ONLY used with logflags=4. */
44
45 /* Verifies and write a verbose textual version of a format=b file.
46 * Textual output file is gdata->checkfilename, fd is gdata->check_fd.
47 * Buffer is in gdata too, see gdata->check* variables.
48 * Could probably be isolated to a separate library or utility.
49 */
50
51 #include "hprof.h"
52
53 typedef TableIndex HprofId;
54
55 #include "hprof_b_spec.h"
56
57 static int type_size[ /*HprofType*/ ] = HPROF_TYPE_SIZES;
58
59 /* For map from HPROF_UTF8 to a string */
60 typedef struct UmapInfo {
61 char *str;
62 } UmapInfo;
63
64 /* Field information */
65 typedef struct Finfo {
66 HprofId id;
67 HprofType ty;
68 } Finfo;
69
70 /* Class information map from class ID (ClassIndex) to class information */
71 typedef struct CmapInfo {
72 int max_finfo;
73 int n_finfo;
74 Finfo *finfo;
75 int inst_size;
76 HprofId sup;
77 } CmapInfo;
78
79 /* Read raw bytes from the file image, update the pointer */
80 static void
read_raw(unsigned char ** pp,unsigned char * buf,int len)81 read_raw(unsigned char **pp, unsigned char *buf, int len)
82 {
83 while ( len > 0 ) {
84 *buf = **pp;
85 buf++;
86 (*pp)++;
87 len--;
88 }
89 }
90
91 /* Read various sized elements, properly converted from big to right endian.
92 * File will contain big endian format.
93 */
94 static unsigned
read_u1(unsigned char ** pp)95 read_u1(unsigned char **pp)
96 {
97 unsigned char b;
98
99 read_raw(pp, &b, 1);
100 return b;
101 }
102 static unsigned
read_u2(unsigned char ** pp)103 read_u2(unsigned char **pp)
104 {
105 unsigned short s;
106
107 read_raw(pp, (void*)&s, 2);
108 return md_htons(s);
109 }
110 static unsigned
read_u4(unsigned char ** pp)111 read_u4(unsigned char **pp)
112 {
113 unsigned int u;
114
115 read_raw(pp, (void*)&u, 4);
116 return md_htonl(u);
117 }
118 static jlong
read_u8(unsigned char ** pp)119 read_u8(unsigned char **pp)
120 {
121 unsigned int high;
122 unsigned int low;
123 jlong x;
124
125 high = read_u4(pp);
126 low = read_u4(pp);
127 x = high;
128 x = (x << 32) | low;
129 return x;
130 }
131 static HprofId
read_id(unsigned char ** pp)132 read_id(unsigned char **pp)
133 {
134 return (HprofId)read_u4(pp);
135 }
136
137 /* System error routine */
138 static void
system_error(const char * system_call,int rc,int errnum)139 system_error(const char *system_call, int rc, int errnum)
140 {
141 char buf[256];
142 char details[256];
143
144 details[0] = 0;
145 if ( errnum != 0 ) {
146 md_system_error(details, (int)sizeof(details));
147 } else if ( rc >= 0 ) {
148 (void)strcpy(details,"Only part of buffer processed");
149 }
150 if ( details[0] == 0 ) {
151 (void)strcpy(details,"Unknown system error condition");
152 }
153 (void)md_snprintf(buf, sizeof(buf), "System %s failed: %s\n",
154 system_call, details);
155 HPROF_ERROR(JNI_TRUE, buf);
156 }
157
158 /* Write to a fd */
159 static void
system_write(int fd,void * buf,int len)160 system_write(int fd, void *buf, int len)
161 {
162 int res;
163
164 HPROF_ASSERT(fd>=0);
165 res = md_write(fd, buf, len);
166 if (res < 0 || res!=len) {
167 system_error("write", res, errno);
168 }
169 }
170
171 /* Flush check buffer */
172 static void
check_flush(void)173 check_flush(void)
174 {
175 if ( gdata->check_fd < 0 ) {
176 return;
177 }
178 if (gdata->check_buffer_index) {
179 system_write(gdata->check_fd, gdata->check_buffer, gdata->check_buffer_index);
180 gdata->check_buffer_index = 0;
181 }
182 }
183
184 /* Read out a given typed element */
185 static jvalue
read_val(unsigned char ** pp,HprofType ty)186 read_val(unsigned char **pp, HprofType ty)
187 {
188 jvalue val;
189 static jvalue empty_val;
190
191 val = empty_val;
192 switch ( ty ) {
193 case 0:
194 case HPROF_ARRAY_OBJECT:
195 case HPROF_NORMAL_OBJECT:
196 val.i = read_id(pp);
197 break;
198 case HPROF_BYTE:
199 case HPROF_BOOLEAN:
200 val.b = read_u1(pp);
201 break;
202 case HPROF_CHAR:
203 case HPROF_SHORT:
204 val.s = read_u2(pp);
205 break;
206 case HPROF_FLOAT:
207 case HPROF_INT:
208 val.i = read_u4(pp);
209 break;
210 case HPROF_DOUBLE:
211 case HPROF_LONG:
212 val.j = read_u8(pp);
213 break;
214 default:
215 HPROF_ERROR(JNI_TRUE, "bad type number");
216 break;
217 }
218 return val;
219 }
220
221 /* Move arbitrary byte stream into gdata->check_fd */
222 static void
check_raw(void * buf,int len)223 check_raw(void *buf, int len)
224 {
225 if ( gdata->check_fd < 0 ) {
226 return;
227 }
228
229 if ( len <= 0 ) {
230 return;
231 }
232
233 if (gdata->check_buffer_index + len > gdata->check_buffer_size) {
234 check_flush();
235 if (len > gdata->check_buffer_size) {
236 system_write(gdata->check_fd, buf, len);
237 return;
238 }
239 }
240 (void)memcpy(gdata->check_buffer + gdata->check_buffer_index, buf, len);
241 gdata->check_buffer_index += len;
242 }
243
244 /* Printf for gdata->check_fd */
245 static void
check_printf(char * fmt,...)246 check_printf(char *fmt, ...)
247 {
248 char buf[1024];
249 va_list args;
250
251 if ( gdata->check_fd < 0 ) {
252 return;
253 }
254
255 va_start(args, fmt);
256 (void)md_vsnprintf(buf, sizeof(buf), fmt, args);
257 buf[sizeof(buf)-1] = 0;
258 check_raw(buf, (int)strlen(buf));
259 va_end(args);
260 }
261
262 /* Printf of an element for gdata->check_fd */
263 static void
check_printf_val(HprofType ty,jvalue val,int long_form)264 check_printf_val(HprofType ty, jvalue val, int long_form)
265 {
266 jint low;
267 jint high;
268
269 switch ( ty ) {
270 case HPROF_ARRAY_OBJECT:
271 check_printf("0x%08x", val.i);
272 break;
273 case HPROF_NORMAL_OBJECT:
274 check_printf("0x%08x", val.i);
275 break;
276 case HPROF_BOOLEAN:
277 check_printf("0x%02x", val.b);
278 break;
279 case HPROF_CHAR:
280 if ( long_form ) {
281 if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) {
282 check_printf("0x%04x", val.s);
283 } else {
284 check_printf("0x%04x(%c)", val.s, val.s);
285 }
286 } else {
287 if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) {
288 check_printf("\\u%04x", val.s);
289 } else {
290 check_printf("%c", val.s);
291 }
292 }
293 break;
294 case HPROF_FLOAT:
295 low = jlong_low(val.j);
296 check_printf("0x%08x(%f)", low, (double)val.f);
297 break;
298 case HPROF_DOUBLE:
299 high = jlong_high(val.j);
300 low = jlong_low(val.j);
301 check_printf("0x%08x%08x(%f)", high, low, val.d);
302 break;
303 case HPROF_BYTE:
304 check_printf("0x%02x", val.b);
305 break;
306 case HPROF_SHORT:
307 check_printf("0x%04x", val.s);
308 break;
309 case HPROF_INT:
310 check_printf("0x%08x", val.i);
311 break;
312 case HPROF_LONG:
313 high = jlong_high(val.j);
314 low = jlong_low(val.j);
315 check_printf("0x%08x%08x", high, low);
316 break;
317 }
318 }
319
320 /* Printf of a string for gdata->check_fd */
321 static void
check_printf_str(char * str)322 check_printf_str(char *str)
323 {
324 int len;
325 int i;
326
327 if ( str == NULL ) {
328 check_printf("<null>");
329 }
330 check_printf("\"");
331 len = (int)strlen(str);
332 for (i = 0; i < len; i++) {
333 unsigned char c;
334 c = str[i];
335 if ( isprint(c) ) {
336 check_printf("%c", c);
337 } else {
338 check_printf("\\x%02x", c);
339 }
340 }
341 check_printf("\"");
342 }
343
344 /* Printf of a utf8 id for gdata->check_fd */
345 static void
check_print_utf8(struct LookupTable * utab,char * prefix,HprofId id)346 check_print_utf8(struct LookupTable *utab, char *prefix, HprofId id)
347 {
348 TableIndex uindex;
349
350 if ( id == 0 ) {
351 check_printf("%s0x%x", prefix, id);
352 } else {
353 uindex = table_find_entry(utab, &id, sizeof(id));
354 if ( uindex == 0 ) {
355 check_printf("%s0x%x", prefix, id);
356 } else {
357 UmapInfo *umap;
358
359 umap = (UmapInfo*)table_get_info(utab, uindex);
360 HPROF_ASSERT(umap!=NULL);
361 HPROF_ASSERT(umap->str!=NULL);
362 check_printf("%s0x%x->", prefix, id);
363 check_printf_str(umap->str);
364 }
365 }
366 }
367
368 /* Add a instance field information to this cmap. */
369 static void
add_inst_field_to_cmap(CmapInfo * cmap,HprofId id,HprofType ty)370 add_inst_field_to_cmap(CmapInfo *cmap, HprofId id, HprofType ty)
371 {
372 int i;
373
374 HPROF_ASSERT(cmap!=NULL);
375 i = cmap->n_finfo++;
376 if ( i+1 >= cmap->max_finfo ) {
377 int osize;
378 Finfo *new_finfo;
379
380 osize = cmap->max_finfo;
381 cmap->max_finfo += 12;
382 new_finfo = (Finfo*)HPROF_MALLOC(cmap->max_finfo*(int)sizeof(Finfo));
383 (void)memset(new_finfo,0,cmap->max_finfo*(int)sizeof(Finfo));
384 if ( i == 0 ) {
385 cmap->finfo = new_finfo;
386 } else {
387 (void)memcpy(new_finfo,cmap->finfo,osize*(int)sizeof(Finfo));
388 HPROF_FREE(cmap->finfo);
389 cmap->finfo = new_finfo;
390 }
391 }
392 cmap->finfo[i].id = id;
393 cmap->finfo[i].ty = ty;
394 }
395
396 /* LookupTable callback for cmap entry cleanup */
397 static void
cmap_cleanup(TableIndex i,void * key_ptr,int key_len,void * info,void * data)398 cmap_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data)
399 {
400 CmapInfo *cmap = info;
401
402 if ( cmap == NULL ) {
403 return;
404 }
405 if ( cmap->finfo != NULL ) {
406 HPROF_FREE(cmap->finfo);
407 cmap->finfo = NULL;
408 }
409 }
410
411 /* Case label for a switch on hprof heap dump elements */
412 #define CASE_HEAP(name) case name: label = #name;
413
414 /* Given the heap dump data and the utf8 map, check/write the heap dump. */
415 static int
check_heap_tags(struct LookupTable * utab,unsigned char * pstart,int nbytes)416 check_heap_tags(struct LookupTable *utab, unsigned char *pstart, int nbytes)
417 {
418 int nrecords;
419 unsigned char *p;
420 unsigned char *psave;
421 struct LookupTable *ctab;
422 CmapInfo cmap;
423 char *label;
424 unsigned tag;
425 HprofType ty;
426 HprofId id, id2, fr, sup;
427 int num_elements;
428 int num_bytes;
429 SerialNumber trace_serial_num;
430 SerialNumber thread_serial_num;
431 int npos;
432 int i;
433 int inst_size;
434
435 ctab = table_initialize("temp ctab", 64, 64, 512, sizeof(CmapInfo));
436
437 /* First pass over heap records just fills in the CmapInfo table */
438 nrecords = 0;
439 p = pstart;
440 while ( p < (pstart+nbytes) ) {
441 nrecords++;
442 /*LINTED*/
443 npos = (int)(p - pstart);
444 tag = read_u1(&p);
445 switch ( tag ) {
446 CASE_HEAP(HPROF_GC_ROOT_UNKNOWN)
447 id = read_id(&p);
448 break;
449 CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL)
450 id = read_id(&p);
451 id2 = read_id(&p);
452 break;
453 CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL)
454 id = read_id(&p);
455 thread_serial_num = read_u4(&p);
456 fr = read_u4(&p);
457 break;
458 CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME)
459 id = read_id(&p);
460 thread_serial_num = read_u4(&p);
461 fr = read_u4(&p);
462 break;
463 CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK)
464 id = read_id(&p);
465 thread_serial_num = read_u4(&p);
466 break;
467 CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS)
468 id = read_id(&p);
469 break;
470 CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK)
471 id = read_id(&p);
472 thread_serial_num = read_u4(&p);
473 break;
474 CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED)
475 id = read_id(&p);
476 break;
477 CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ)
478 id = read_id(&p);
479 thread_serial_num = read_u4(&p);
480 trace_serial_num = read_u4(&p);
481 break;
482 CASE_HEAP(HPROF_GC_CLASS_DUMP)
483 (void)memset((void*)&cmap, 0, sizeof(cmap));
484 id = read_id(&p);
485 trace_serial_num = read_u4(&p);
486 {
487 HprofId ld, si, pr, re1, re2;
488
489 sup = read_id(&p);
490 ld = read_id(&p);
491 si = read_id(&p);
492 pr = read_id(&p);
493 re1 = read_id(&p);
494 re2 = read_id(&p);
495 cmap.sup = sup;
496 }
497 inst_size = read_u4(&p);
498 cmap.inst_size = inst_size;
499 num_elements = read_u2(&p);
500 for(i=0; i<num_elements; i++) {
501 (void)read_u2(&p);
502 ty = read_u1(&p);
503 (void)read_val(&p, ty);
504 }
505 num_elements = read_u2(&p);
506 for(i=0; i<num_elements; i++) {
507 (void)read_id(&p);
508 ty = read_u1(&p);
509 (void)read_val(&p, ty);
510 }
511 num_elements = read_u2(&p);
512 for(i=0; i<num_elements; i++) {
513 HprofType ty;
514 HprofId id;
515
516 id = read_id(&p);
517 ty = read_u1(&p);
518 add_inst_field_to_cmap(&cmap, id, ty);
519 }
520 (void)table_create_entry(ctab, &id, sizeof(id), &cmap);
521 break;
522 CASE_HEAP(HPROF_GC_INSTANCE_DUMP)
523 id = read_id(&p);
524 trace_serial_num = read_u4(&p);
525 id2 = read_id(&p); /* class id */
526 num_bytes = read_u4(&p);
527 p += num_bytes;
528 break;
529 CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP)
530 id = read_id(&p);
531 trace_serial_num = read_u4(&p);
532 num_elements = read_u4(&p);
533 id2 = read_id(&p);
534 p += num_elements*(int)sizeof(HprofId);
535 break;
536 CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP)
537 id = read_id(&p);
538 trace_serial_num = read_u4(&p);
539 num_elements = read_u4(&p);
540 ty = read_u1(&p);
541 p += type_size[ty]*num_elements;
542 break;
543 default:
544 label = "UNKNOWN";
545 check_printf("H#%d@%d %s: ERROR!\n",
546 nrecords, npos, label);
547 HPROF_ERROR(JNI_TRUE, "unknown heap record type");
548 break;
549 }
550 }
551 CHECK_FOR_ERROR(p==pstart+nbytes);
552
553 /* Scan again once we have our cmap */
554 nrecords = 0;
555 p = pstart;
556 while ( p < (pstart+nbytes) ) {
557 nrecords++;
558 /*LINTED*/
559 npos = (int)(p - pstart);
560 tag = read_u1(&p);
561 switch ( tag ) {
562 CASE_HEAP(HPROF_GC_ROOT_UNKNOWN)
563 id = read_id(&p);
564 check_printf("H#%d@%d %s: id=0x%x\n",
565 nrecords, npos, label, id);
566 break;
567 CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL)
568 id = read_id(&p);
569 id2 = read_id(&p);
570 check_printf("H#%d@%d %s: id=0x%x, id2=0x%x\n",
571 nrecords, npos, label, id, id2);
572 break;
573 CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL)
574 id = read_id(&p);
575 thread_serial_num = read_u4(&p);
576 fr = read_u4(&p);
577 check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n",
578 nrecords, npos, label, id, thread_serial_num, fr);
579 break;
580 CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME)
581 id = read_id(&p);
582 thread_serial_num = read_u4(&p);
583 fr = read_u4(&p);
584 check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n",
585 nrecords, npos, label, id, thread_serial_num, fr);
586 break;
587 CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK)
588 id = read_id(&p);
589 thread_serial_num = read_u4(&p);
590 check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n",
591 nrecords, npos, label, id, thread_serial_num);
592 break;
593 CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS)
594 id = read_id(&p);
595 check_printf("H#%d@%d %s: id=0x%x\n",
596 nrecords, npos, label, id);
597 break;
598 CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK)
599 id = read_id(&p);
600 thread_serial_num = read_u4(&p);
601 check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n",
602 nrecords, npos, label, id, thread_serial_num);
603 break;
604 CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED)
605 id = read_id(&p);
606 check_printf("H#%d@%d %s: id=0x%x\n",
607 nrecords, npos, label, id);
608 break;
609 CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ)
610 id = read_id(&p);
611 thread_serial_num = read_u4(&p);
612 trace_serial_num = read_u4(&p);
613 CHECK_TRACE_SERIAL_NO(trace_serial_num);
614 check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u,"
615 " trace_serial_num=%u\n",
616 nrecords, npos, label, id, thread_serial_num,
617 trace_serial_num);
618 break;
619 CASE_HEAP(HPROF_GC_CLASS_DUMP)
620 id = read_id(&p);
621 trace_serial_num = read_u4(&p);
622 CHECK_TRACE_SERIAL_NO(trace_serial_num);
623 check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u\n",
624 nrecords, npos, label, id, trace_serial_num);
625 {
626 HprofId ld, si, pr, re1, re2;
627
628 sup = read_id(&p);
629 ld = read_id(&p);
630 si = read_id(&p);
631 pr = read_id(&p);
632 re1 = read_id(&p);
633 re2 = read_id(&p);
634 check_printf(" su=0x%x, ld=0x%x, si=0x%x,"
635 " pr=0x%x, re1=0x%x, re2=0x%x\n",
636 sup, ld, si, pr, re1, re2);
637 }
638 inst_size = read_u4(&p);
639 check_printf(" instance_size=%d\n", inst_size);
640
641 num_elements = read_u2(&p);
642 for(i=0; i<num_elements; i++) {
643 HprofType ty;
644 unsigned cpi;
645 jvalue val;
646
647 cpi = read_u2(&p);
648 ty = read_u1(&p);
649 val = read_val(&p, ty);
650 check_printf(" constant_pool %d: cpi=%d, ty=%d, val=",
651 i, cpi, ty);
652 check_printf_val(ty, val, 1);
653 check_printf("\n");
654 }
655
656 num_elements = read_u2(&p);
657 check_printf(" static_field_count=%d\n", num_elements);
658 for(i=0; i<num_elements; i++) {
659 HprofType ty;
660 HprofId id;
661 jvalue val;
662
663 id = read_id(&p);
664 ty = read_u1(&p);
665 val = read_val(&p, ty);
666 check_printf(" static field %d: ", i);
667 check_print_utf8(utab, "id=", id);
668 check_printf(", ty=%d, val=", ty);
669 check_printf_val(ty, val, 1);
670 check_printf("\n");
671 }
672
673 num_elements = read_u2(&p);
674 check_printf(" instance_field_count=%d\n", num_elements);
675 for(i=0; i<num_elements; i++) {
676 HprofType ty;
677 HprofId id;
678
679 id = read_id(&p);
680 ty = read_u1(&p);
681 check_printf(" instance_field %d: ", i);
682 check_print_utf8(utab, "id=", id);
683 check_printf(", ty=%d\n", ty);
684 }
685 break;
686 CASE_HEAP(HPROF_GC_INSTANCE_DUMP)
687 id = read_id(&p);
688 trace_serial_num = read_u4(&p);
689 CHECK_TRACE_SERIAL_NO(trace_serial_num);
690 id2 = read_id(&p); /* class id */
691 num_bytes = read_u4(&p);
692 check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u,"
693 " cid=0x%x, nbytes=%d\n",
694 nrecords, npos, label, id, trace_serial_num,
695 id2, num_bytes);
696 /* This is a packed set of bytes for the instance fields */
697 if ( num_bytes > 0 ) {
698 TableIndex cindex;
699 int ifield;
700 CmapInfo *map;
701
702 cindex = table_find_entry(ctab, &id2, sizeof(id2));
703 HPROF_ASSERT(cindex!=0);
704 map = (CmapInfo*)table_get_info(ctab, cindex);
705 HPROF_ASSERT(map!=NULL);
706 HPROF_ASSERT(num_bytes==map->inst_size);
707
708 psave = p;
709 ifield = 0;
710
711 do {
712 for(i=0;i<map->n_finfo;i++) {
713 HprofType ty;
714 HprofId id;
715 jvalue val;
716
717 ty = map->finfo[i].ty;
718 id = map->finfo[i].id;
719 HPROF_ASSERT(ty!=0);
720 HPROF_ASSERT(id!=0);
721 val = read_val(&p, ty);
722 check_printf(" field %d: ", ifield);
723 check_print_utf8(utab, "id=", id);
724 check_printf(", ty=%d, val=", ty);
725 check_printf_val(ty, val, 1);
726 check_printf("\n");
727 ifield++;
728 }
729 id2 = map->sup;
730 map = NULL;
731 cindex = 0;
732 if ( id2 != 0 ) {
733 cindex = table_find_entry(ctab, &id2, sizeof(id2));
734 HPROF_ASSERT(cindex!=0);
735 map = (CmapInfo*)table_get_info(ctab, cindex);
736 HPROF_ASSERT(map!=NULL);
737 }
738 } while ( map != NULL );
739 HPROF_ASSERT(num_bytes==(p-psave));
740 }
741 break;
742 CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP)
743 id = read_id(&p);
744 trace_serial_num = read_u4(&p);
745 CHECK_TRACE_SERIAL_NO(trace_serial_num);
746 num_elements = read_u4(&p);
747 id2 = read_id(&p);
748 check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, nelems=%d, eid=0x%x\n",
749 nrecords, npos, label, id, trace_serial_num, num_elements, id2);
750 for(i=0; i<num_elements; i++) {
751 HprofId id;
752
753 id = read_id(&p);
754 check_printf(" [%d]: id=0x%x\n", i, id);
755 }
756 break;
757 CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP)
758 id = read_id(&p);
759 trace_serial_num = read_u4(&p);
760 CHECK_TRACE_SERIAL_NO(trace_serial_num);
761 num_elements = read_u4(&p);
762 ty = read_u1(&p);
763 psave = p;
764 check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, "
765 "nelems=%d, ty=%d\n",
766 nrecords, npos, label, id, trace_serial_num, num_elements, ty);
767 HPROF_ASSERT(HPROF_TYPE_IS_PRIMITIVE(ty));
768 if ( num_elements > 0 ) {
769 int count;
770 int long_form;
771 int max_count;
772 char *quote;
773
774 quote = "";
775 long_form = 1;
776 max_count = 8;
777 count = 0;
778 switch ( ty ) {
779 case HPROF_CHAR:
780 long_form = 0;
781 max_count = 72;
782 quote = "\"";
783 /*FALLTHRU*/
784 case HPROF_INT:
785 case HPROF_DOUBLE:
786 case HPROF_LONG:
787 case HPROF_BYTE:
788 case HPROF_BOOLEAN:
789 case HPROF_SHORT:
790 case HPROF_FLOAT:
791 check_printf(" val=%s", quote);
792 for(i=0; i<num_elements; i++) {
793 jvalue val;
794
795 if ( i > 0 && count == 0 ) {
796 check_printf(" %s", quote);
797 }
798 val = read_val(&p, ty);
799 check_printf_val(ty, val, long_form);
800 count += 1;
801 if ( count >= max_count ) {
802 check_printf("\"\n");
803 count = 0;
804 }
805 }
806 if ( count != 0 ) {
807 check_printf("%s\n", quote);
808 }
809 break;
810 }
811 }
812 HPROF_ASSERT(type_size[ty]*num_elements==(p-psave));
813 break;
814 default:
815 label = "UNKNOWN";
816 check_printf("H#%d@%d %s: ERROR!\n",
817 nrecords, npos, label);
818 HPROF_ERROR(JNI_TRUE, "unknown heap record type");
819 break;
820 }
821 }
822 CHECK_FOR_ERROR(p==pstart+nbytes);
823
824 table_cleanup(ctab, &cmap_cleanup, NULL);
825
826 return nrecords;
827 }
828
829 /* LookupTable cleanup callback for utab */
830 static void
utab_cleanup(TableIndex i,void * key_ptr,int key_len,void * info,void * data)831 utab_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data)
832 {
833 UmapInfo *umap = info;
834
835 if ( umap == NULL ) {
836 return;
837 }
838 if ( umap->str != NULL ) {
839 HPROF_FREE(umap->str);
840 umap->str = NULL;
841 }
842 }
843
844 /* Check all the heap tags in a heap dump */
845 static int
check_tags(unsigned char * pstart,int nbytes)846 check_tags(unsigned char *pstart, int nbytes)
847 {
848 unsigned char *p;
849 int nrecord;
850 struct LookupTable *utab;
851 UmapInfo umap;
852
853 check_printf("\nCHECK TAGS: starting\n");
854
855 utab = table_initialize("temp utf8 map", 64, 64, 512, sizeof(UmapInfo));
856
857 /* Walk the tags, assumes UTF8 tags are defined before used */
858 p = pstart;
859 nrecord = 0;
860 while ( p < (pstart+nbytes) ) {
861 unsigned tag;
862 unsigned size;
863 int nheap_records;
864 int npos;
865 char *label;
866 HprofId id, nm, sg, so, gr, gn;
867 int i, li, num_elements;
868 HprofType ty;
869 SerialNumber trace_serial_num;
870 SerialNumber thread_serial_num;
871 SerialNumber class_serial_num;
872 unsigned flags;
873 unsigned depth;
874 float cutoff;
875 unsigned temp;
876 jint nblive;
877 jint nilive;
878 jlong tbytes;
879 jlong tinsts;
880 jint total_samples;
881 jint trace_count;
882
883 nrecord++;
884 /*LINTED*/
885 npos = (int)(p - pstart);
886 tag = read_u1(&p);
887 (void)read_u4(&p); /* microsecs */
888 size = read_u4(&p);
889 #define CASE_TAG(name) case name: label = #name;
890 switch ( tag ) {
891 CASE_TAG(HPROF_UTF8)
892 CHECK_FOR_ERROR(size>=(int)sizeof(HprofId));
893 id = read_id(&p);
894 check_printf("#%d@%d: %s, sz=%d, name_id=0x%x, \"",
895 nrecord, npos, label, size, id);
896 num_elements = size-(int)sizeof(HprofId);
897 check_raw(p, num_elements);
898 check_printf("\"\n");
899 /* Create entry in umap */
900 umap.str = HPROF_MALLOC(num_elements+1);
901 (void)strncpy(umap.str, (char*)p, (size_t)num_elements);
902 umap.str[num_elements] = 0;
903 (void)table_create_entry(utab, &id, sizeof(id), &umap);
904 p += num_elements;
905 break;
906 CASE_TAG(HPROF_LOAD_CLASS)
907 CHECK_FOR_ERROR(size==2*4+2*(int)sizeof(HprofId));
908 class_serial_num = read_u4(&p);
909 CHECK_CLASS_SERIAL_NO(class_serial_num);
910 id = read_id(&p);
911 trace_serial_num = read_u4(&p);
912 CHECK_TRACE_SERIAL_NO(trace_serial_num);
913 nm = read_id(&p);
914 check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u,"
915 " id=0x%x, trace_serial_num=%u, name_id=0x%x\n",
916 nrecord, npos, label, size, class_serial_num,
917 id, trace_serial_num, nm);
918 break;
919 CASE_TAG(HPROF_UNLOAD_CLASS)
920 CHECK_FOR_ERROR(size==4);
921 class_serial_num = read_u4(&p);
922 CHECK_CLASS_SERIAL_NO(class_serial_num);
923 check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u\n",
924 nrecord, npos, label, size, class_serial_num);
925 break;
926 CASE_TAG(HPROF_FRAME)
927 CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId));
928 id = read_id(&p);
929 nm = read_id(&p);
930 sg = read_id(&p);
931 so = read_id(&p);
932 class_serial_num = read_u4(&p);
933 CHECK_CLASS_SERIAL_NO(class_serial_num);
934 li = read_u4(&p);
935 check_printf("#%d@%d: %s, sz=%d, ", nrecord, npos, label, size);
936 check_print_utf8(utab, "id=", id);
937 check_printf(" name_id=0x%x, sig_id=0x%x, source_id=0x%x,"
938 " class_serial_num=%u, lineno=%d\n",
939 nm, sg, so, class_serial_num, li);
940 break;
941 CASE_TAG(HPROF_TRACE)
942 CHECK_FOR_ERROR(size>=3*4);
943 trace_serial_num = read_u4(&p);
944 CHECK_TRACE_SERIAL_NO(trace_serial_num);
945 thread_serial_num = read_u4(&p); /* Can be 0 */
946 num_elements = read_u4(&p);
947 check_printf("#%d@%d: %s, sz=%d, trace_serial_num=%u,"
948 " thread_serial_num=%u, nelems=%d [",
949 nrecord, npos, label, size,
950 trace_serial_num, thread_serial_num, num_elements);
951 for(i=0; i< num_elements; i++) {
952 check_printf("0x%x,", read_id(&p));
953 }
954 check_printf("]\n");
955 break;
956 CASE_TAG(HPROF_ALLOC_SITES)
957 CHECK_FOR_ERROR(size>=2+4*4+2*8);
958 flags = read_u2(&p);
959 temp = read_u4(&p);
960 cutoff = *((float*)&temp);
961 nblive = read_u4(&p);
962 nilive = read_u4(&p);
963 tbytes = read_u8(&p);
964 tinsts = read_u8(&p);
965 num_elements = read_u4(&p);
966 check_printf("#%d@%d: %s, sz=%d, flags=0x%x, cutoff=%g,"
967 " nblive=%d, nilive=%d, tbytes=(%d,%d),"
968 " tinsts=(%d,%d), num_elements=%d\n",
969 nrecord, npos, label, size,
970 flags, cutoff, nblive, nilive,
971 jlong_high(tbytes), jlong_low(tbytes),
972 jlong_high(tinsts), jlong_low(tinsts),
973 num_elements);
974 for(i=0; i< num_elements; i++) {
975 ty = read_u1(&p);
976 class_serial_num = read_u4(&p);
977 CHECK_CLASS_SERIAL_NO(class_serial_num);
978 trace_serial_num = read_u4(&p);
979 CHECK_TRACE_SERIAL_NO(trace_serial_num);
980 nblive = read_u4(&p);
981 nilive = read_u4(&p);
982 tbytes = read_u4(&p);
983 tinsts = read_u4(&p);
984 check_printf("\t %d: ty=%d, class_serial_num=%u,"
985 " trace_serial_num=%u, nblive=%d, nilive=%d,"
986 " tbytes=%d, tinsts=%d\n",
987 i, ty, class_serial_num, trace_serial_num,
988 nblive, nilive, (jint)tbytes, (jint)tinsts);
989 }
990 break;
991 CASE_TAG(HPROF_HEAP_SUMMARY)
992 CHECK_FOR_ERROR(size==2*4+2*8);
993 nblive = read_u4(&p);
994 nilive = read_u4(&p);
995 tbytes = read_u8(&p);
996 tinsts = read_u8(&p);
997 check_printf("#%d@%d: %s, sz=%d,"
998 " nblive=%d, nilive=%d, tbytes=(%d,%d),"
999 " tinsts=(%d,%d)\n",
1000 nrecord, npos, label, size,
1001 nblive, nilive,
1002 jlong_high(tbytes), jlong_low(tbytes),
1003 jlong_high(tinsts), jlong_low(tinsts));
1004 break;
1005 CASE_TAG(HPROF_START_THREAD)
1006 CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId));
1007 thread_serial_num = read_u4(&p);
1008 CHECK_THREAD_SERIAL_NO(thread_serial_num);
1009 id = read_id(&p);
1010 trace_serial_num = read_u4(&p);
1011 CHECK_TRACE_SERIAL_NO(trace_serial_num);
1012 nm = read_id(&p);
1013 gr = read_id(&p);
1014 gn = read_id(&p);
1015 check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u,"
1016 " id=0x%x, trace_serial_num=%u, ",
1017 nrecord, npos, label, size,
1018 thread_serial_num, id, trace_serial_num);
1019 check_print_utf8(utab, "nm=", id);
1020 check_printf(" trace_serial_num=%u, nm=0x%x,"
1021 " gr=0x%x, gn=0x%x\n",
1022 trace_serial_num, nm, gr, gn);
1023 break;
1024 CASE_TAG(HPROF_END_THREAD)
1025 CHECK_FOR_ERROR(size==4);
1026 thread_serial_num = read_u4(&p);
1027 CHECK_THREAD_SERIAL_NO(thread_serial_num);
1028 check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u\n",
1029 nrecord, npos, label, size, thread_serial_num);
1030 break;
1031 CASE_TAG(HPROF_HEAP_DUMP)
1032 check_printf("#%d@%d: BEGIN: %s, sz=%d\n",
1033 nrecord, npos, label, size);
1034 nheap_records = check_heap_tags(utab, p, size);
1035 check_printf("#%d@%d: END: %s, sz=%d, nheap_recs=%d\n",
1036 nrecord, npos, label, size, nheap_records);
1037 p += size;
1038 break;
1039 CASE_TAG(HPROF_HEAP_DUMP_SEGMENT) /* 1.0.2 */
1040 check_printf("#%d@%d: BEGIN SEGMENT: %s, sz=%d\n",
1041 nrecord, npos, label, size);
1042 nheap_records = check_heap_tags(utab, p, size);
1043 check_printf("#%d@%d: END SEGMENT: %s, sz=%d, nheap_recs=%d\n",
1044 nrecord, npos, label, size, nheap_records);
1045 p += size;
1046 break;
1047 CASE_TAG(HPROF_HEAP_DUMP_END) /* 1.0.2 */
1048 check_printf("#%d@%d: SEGMENT END: %s, sz=%d\n",
1049 nrecord, npos, label, size);
1050 break;
1051 CASE_TAG(HPROF_CPU_SAMPLES)
1052 CHECK_FOR_ERROR(size>=2*4);
1053 total_samples = read_u4(&p);
1054 trace_count = read_u4(&p);
1055 check_printf("#%d@%d: %s, sz=%d, total_samples=%d,"
1056 " trace_count=%d\n",
1057 nrecord, npos, label, size,
1058 total_samples, trace_count);
1059 for(i=0; i< trace_count; i++) {
1060 num_elements = read_u4(&p);
1061 trace_serial_num = read_u4(&p);
1062 CHECK_TRACE_SERIAL_NO(trace_serial_num);
1063 check_printf("\t %d: samples=%d, trace_serial_num=%u\n",
1064 trace_serial_num, num_elements);
1065 }
1066 break;
1067 CASE_TAG(HPROF_CONTROL_SETTINGS)
1068 CHECK_FOR_ERROR(size==4+2);
1069 flags = read_u4(&p);
1070 depth = read_u2(&p);
1071 check_printf("#%d@%d: %s, sz=%d, flags=0x%x, depth=%d\n",
1072 nrecord, npos, label, size, flags, depth);
1073 break;
1074 default:
1075 label = "UNKNOWN";
1076 check_printf("#%d@%d: %s, sz=%d\n",
1077 nrecord, npos, label, size);
1078 HPROF_ERROR(JNI_TRUE, "unknown record type");
1079 p += size;
1080 break;
1081 }
1082 CHECK_FOR_ERROR(p<=(pstart+nbytes));
1083 }
1084 check_flush();
1085 CHECK_FOR_ERROR(p==(pstart+nbytes));
1086 table_cleanup(utab, &utab_cleanup, NULL);
1087 return nrecord;
1088 }
1089
1090 /* Read the entire file into memory */
1091 static void *
get_binary_file_image(char * filename,int * pnbytes)1092 get_binary_file_image(char *filename, int *pnbytes)
1093 {
1094 unsigned char *image;
1095 int fd;
1096 jlong nbytes;
1097 int nread;
1098
1099 *pnbytes = 0;
1100 fd = md_open_binary(filename);
1101 CHECK_FOR_ERROR(fd>=0);
1102 if ( (nbytes = md_seek(fd, (jlong)-1)) == (jlong)-1 ) {
1103 HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to end of file");
1104 }
1105 CHECK_FOR_ERROR(((jint)nbytes)>512);
1106 if ( md_seek(fd, (jlong)0) != (jlong)0 ) {
1107 HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to start of file");
1108 }
1109 image = HPROF_MALLOC(((jint)nbytes)+1);
1110 CHECK_FOR_ERROR(image!=NULL);
1111
1112 /* Read the entire file image into memory */
1113 nread = md_read(fd, image, (jint)nbytes);
1114 if ( nread <= 0 ) {
1115 HPROF_ERROR(JNI_TRUE, "System read failed.");
1116 }
1117 CHECK_FOR_ERROR(((jint)nbytes)==nread);
1118 md_close(fd);
1119 *pnbytes = (jint)nbytes;
1120 return image;
1121 }
1122
1123 /* ------------------------------------------------------------------ */
1124
1125 void
check_binary_file(char * filename)1126 check_binary_file(char *filename)
1127 {
1128 unsigned char *image;
1129 unsigned char *p;
1130 unsigned idsize;
1131 int nbytes;
1132 int nrecords;
1133
1134 image = get_binary_file_image(filename, &nbytes);
1135 if ( image == NULL ) {
1136 check_printf("No file image: %s\n", filename);
1137 return;
1138 }
1139 p = image;
1140 CHECK_FOR_ERROR(strcmp((char*)p, gdata->header)==0);
1141 check_printf("Filename=%s, nbytes=%d, header=\"%s\"\n",
1142 filename, nbytes, p);
1143 p+=((int)strlen((char*)p)+1);
1144 idsize = read_u4(&p);
1145 CHECK_FOR_ERROR(idsize==sizeof(HprofId));
1146 (void)read_u4(&p);
1147 (void)read_u4(&p);
1148 /* LINTED */
1149 nrecords = check_tags(p, nbytes - (int)( p - image ) );
1150 check_printf("#%d total records found in %d bytes\n", nrecords, nbytes);
1151 HPROF_FREE(image);
1152 }
1153