Skip to content

Instantly share code, notes, and snippets.

@bitbckt
Last active December 16, 2015 00:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitbckt/5348042 to your computer and use it in GitHub Desktop.
Save bitbckt/5348042 to your computer and use it in GitHub Desktop.
An example hprof reader.
#include <arpa/inet.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define HPROF_OK 0
#define HPROF_ERR -1
/* Shamelessly copied from src/share/vm/services/heapDumper.cpp */
enum tag {
HPROF_UTF8 = 0x01,
HPROF_LOAD_CLASS = 0x02,
HPROF_UNLOAD_CLASS = 0x03,
HPROF_FRAME = 0x04,
HPROF_TRACE = 0x05,
HPROF_ALLOC_SITES = 0x06,
HPROF_HEAP_SUMMARY = 0x07,
HPROF_START_THREAD = 0x0A,
HPROF_END_THREAD = 0x0B,
HPROF_HEAP_DUMP = 0x0C,
HPROF_CPU_SAMPLES = 0x0D,
HPROF_CONTROL_SETTINGS = 0x0E,
/* 1.0.2 record types */
HPROF_HEAP_DUMP_SEGMENT = 0x1C,
HPROF_HEAP_DUMP_END = 0x2C,
/* field types */
HPROF_ARRAY_OBJECT = 0x01,
HPROF_NORMAL_OBJECT = 0x02,
HPROF_BOOLEAN = 0x04,
HPROF_CHAR = 0x05,
HPROF_FLOAT = 0x06,
HPROF_DOUBLE = 0x07,
HPROF_BYTE = 0x08,
HPROF_SHORT = 0x09,
HPROF_INT = 0x0A,
HPROF_LONG = 0x0B,
/* data-dump sub-records */
HPROF_GC_ROOT_UNKNOWN = 0xFF,
HPROF_GC_ROOT_JNI_GLOBAL = 0x01,
HPROF_GC_ROOT_JNI_LOCAL = 0x02,
HPROF_GC_ROOT_JAVA_FRAME = 0x03,
HPROF_GC_ROOT_NATIVE_STACK = 0x04,
HPROF_GC_ROOT_STICKY_CLASS = 0x05,
HPROF_GC_ROOT_THREAD_BLOCK = 0x06,
HPROF_GC_ROOT_MONITOR_USED = 0x07,
HPROF_GC_ROOT_THREAD_OBJ = 0x08,
HPROF_GC_CLASS_DUMP = 0x20,
HPROF_GC_INSTANCE_DUMP = 0x21,
HPROF_GC_OBJ_ARRAY_DUMP = 0x22,
HPROF_GC_PRIM_ARRAY_DUMP = 0x23
};
static const char *__version = "JAVA PROFILE 1.0.2";
static uint32_t __id_size = 0;
static uint64_t __timestamp = 0;
static uint32_t
btol(unsigned char *b)
{
uint32_t l;
memcpy(&l, b, sizeof(l));
return ntohl(l);
}
static uint64_t
btoll(unsigned char *b)
{
uint64_t l = 0;
uint32_t msb, lsb;
memcpy(&msb, b, sizeof(msb));
l |= ntohl(msb);
l <<= 32;
memcpy(&lsb, b + 4, sizeof(lsb));
l |= ntohl(lsb);
return l;
}
static uint8_t
readu1(FILE *file)
{
unsigned char buf;
fread(&buf, sizeof(buf), 1, file);
return (uint8_t)buf;
}
static uint32_t
readu4(FILE *file)
{
unsigned char buf[4];
fread(buf, sizeof(*buf), 4, file);
return btol(buf);
}
static uint64_t
readu8(FILE *file)
{
unsigned char buf[8];
fread(buf, sizeof(*buf), 8, file);
return btoll(buf);
}
static int
version_check(FILE *file)
{
int ret;
char buf[21];
size_t bytes;
size_t len = strlen(__version) + 1; /* + NUL */
bytes = fread(buf, 1, len, file);
ret = ferror(file);
if (ret != 0) {
return ret;
}
if (bytes == len) {
return strncmp(__version, buf, len - 1);
} else {
return HPROF_ERR;
}
}
static int
id_size_check(FILE *file)
{
__id_size = readu4(file);
return HPROF_OK;
}
static int
timestamp_check(FILE *file)
{
__timestamp = readu8(file);
return HPROF_OK;
}
static int
record_check(FILE *file)
{
enum tag tag;
uint32_t bytes;
tag = readu1(file);
(void)readu4(file); /* usecs. since __timestamp */
bytes = readu4(file);
switch (tag) {
case HPROF_HEAP_SUMMARY:
printf("found heap summary!\n");
break;
default:
break;
}
fseek(file, bytes, SEEK_CUR);
return HPROF_OK;
}
int
main(int argc, char *argv[])
{
FILE *file = NULL;
int ret = EXIT_SUCCESS;
if (argc < 2) {
fprintf(stderr, "Usage: hprof <file>\n");
ret = EXIT_FAILURE;
goto out;
}
file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen(): ");
ret = EXIT_FAILURE;
goto out;
}
ret = version_check(file);
if (ret != 0) {
fprintf(stderr, "version_check(): %d\n", ret);
ret = EXIT_FAILURE;
goto out;
} else {
printf("version check passed\n");
}
ret = id_size_check(file);
if (ret != 0) {
fprintf(stderr, "id_size_check(): %d\n", ret);
ret = EXIT_FAILURE;
goto out;
} else {
printf("identifier size %d\n", __id_size);
}
ret = timestamp_check(file);
if (ret != 0) {
fprintf(stderr, "timestamp_check(): %d\n", ret);
ret = EXIT_FAILURE;
goto out;
} else {
printf("timestamp %ld\n", __timestamp);
}
while (!feof(file)) {
ret = record_check(file);
if (ret != 0) {
fprintf(stderr, "record_check(): %d\n", ret);
ret = EXIT_FAILURE;
goto out;
}
}
out:
if (file) {
fclose(file);
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment