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
  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
  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
 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
 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
 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
 132 read_id(unsigned char **pp)
 133 {
 134     return (HprofId)read_u4(pp);
 135 }
 136 
 137 /* System error routine */
 138 static void
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
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
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 }