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