Skip to content

Instantly share code, notes, and snippets.

@shinaisan
Created August 6, 2012 14:55
Show Gist options
  • Select an option

  • Save shinaisan/3275010 to your computer and use it in GitHub Desktop.

Select an option

Save shinaisan/3275010 to your computer and use it in GitHub Desktop.
C program that analyzes a constant pool in a Java class file and prints out its contents.
/* -*- mode: c; coding: utf-8-dos; indent-tabs-mode: nil; c-basic-offset: 4 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <arpa/inet.h>
#pragma pack(1)
typedef enum {
CONSTANT_Class = 7,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_String = 8,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_NameAndType = 12,
CONSTANT_Utf8 = 1,
CONSTANT_MethodHandle = 15,
CONSTANT_MethodType = 16,
CONSTANT_InvokeDynamic = 18,
} constant_type_t;
typedef struct _CLASS_FILE_1 {
uint32_t magic;
uint16_t minor_version;
uint16_t major_version;
uint16_t constant_pool_count;
} CLASS_FILE_1;
typedef struct _CONSTANT_CLASS_INFO {
uint8_t tag;
uint16_t name_index;
} CONSTANT_CLASS_INFO;
typedef struct _CONSTANT_FIELDREF_INFO {
uint8_t tag;
uint16_t class_index;
uint16_t name_and_type_index;
} CONSTANT_FIELDREF_INFO;
typedef struct _CONSTANT_METHODREF_INFO {
uint8_t tag;
uint16_t class_index;
uint16_t name_and_type_index;
} CONSTANT_METHODREF_INFO;
typedef struct _CONSTANT_INTERFACEMETHODREF_INFO {
uint8_t tag;
uint16_t class_index;
uint16_t name_and_type_index;
} CONSTANT_INTERFACEMETHODREF_INFO;
typedef struct _CONSTANT_STRING_INFO {
uint8_t tag;
uint16_t string_index;
} CONSTANT_STRING_INFO;
typedef struct _CONSTANT_INTEGER_INFO {
uint8_t tag;
uint32_t bytes;
} CONSTANT_INTEGER_INFO;
typedef struct _CONSTANT_FLOAT_INFO {
uint8_t tag;
uint32_t bytes;
} CONSTANT_FLOAT_INFO;
typedef struct _CONSTANT_LONG_INFO {
uint8_t tag;
uint32_t high_bytes;
uint32_t low_bytes;
} CONSTANT_LONG_INFO;
typedef struct _CONSTANT_DOUBLE_INFO {
uint8_t tag;
uint32_t high_bytes;
uint32_t low_bytes;
} CONSTANT_DOUBLE_INFO;
typedef struct _CONSTANT_NAMEANDTYPE_INFO {
uint8_t tag;
uint16_t name_index;
uint16_t descriptor_index;
} CONSTANT_NAMEANDTYPE_INFO;
typedef struct _CONSTANT_UTF8_INFO {
uint8_t tag;
uint16_t length; /* The number of bytes. */
uint8_t bytes[];
} CONSTANT_UTF8_INFO;
typedef struct _CONSTANT_METHODHANDLE_INFO {
uint8_t tag;
uint8_t reference_kind;
uint8_t reference_index;
} CONSTANT_METHODHANDLE_INFO;
typedef struct _CONSTANT_METHODTYPE_INFO {
uint8_t tag;
uint16_t descriptor_index;
} CONSTANT_METHODTYPE_INFO;
typedef struct _CONSTANT_INVOKEDYNAMIC_INFO {
uint8_t tag;
uint16_t bootstrap_method_attr_index;
uint16_t name_and_type_index;
} CONSTANT_INVOKEDYNAMIC_INFO;
int get_constant_info_size(uint8_t *bytes) {
uint8_t tag;
int size = 0;
tag = *bytes;
switch (tag) {
case CONSTANT_Class:
size = sizeof(CONSTANT_CLASS_INFO);
break;
case CONSTANT_Fieldref:
size = sizeof(CONSTANT_FIELDREF_INFO);
break;
case CONSTANT_Methodref:
size = sizeof(CONSTANT_METHODREF_INFO);
break;
case CONSTANT_InterfaceMethodref:
size = sizeof(CONSTANT_INTERFACEMETHODREF_INFO);
break;
case CONSTANT_String:
size = sizeof(CONSTANT_STRING_INFO);
break;
case CONSTANT_Integer:
size = sizeof(CONSTANT_INTEGER_INFO);
break;
case CONSTANT_Float:
size = sizeof(CONSTANT_FLOAT_INFO);
break;
case CONSTANT_Long:
size = sizeof(CONSTANT_LONG_INFO);
break;
case CONSTANT_Double:
size = sizeof(CONSTANT_DOUBLE_INFO);
break;
case CONSTANT_NameAndType:
size = sizeof(CONSTANT_NAMEANDTYPE_INFO);
break;
case CONSTANT_Utf8:
{
CONSTANT_UTF8_INFO *putf8 = (CONSTANT_UTF8_INFO *)bytes;
int n = ntohs(putf8->length);
size = sizeof(CONSTANT_UTF8_INFO) + n;
}
break;
case CONSTANT_MethodHandle:
size = sizeof(CONSTANT_METHODHANDLE_INFO);
break;
case CONSTANT_MethodType:
size = sizeof(CONSTANT_METHODTYPE_INFO);
break;
case CONSTANT_InvokeDynamic:
size = sizeof(CONSTANT_INVOKEDYNAMIC_INFO);
break;
default:
size = 0;
break;
}
return size;
}
/* The memory pointed to by (*pbuf) must be freed manually after use. */
long read_class_file(FILE *fp, uint8_t **pbuf) {
long buf_size = 0;
fpos_t file_size = 0;
long size_read = 0;
if (fseek(fp, 0, SEEK_END) != 0) {
return 0;
}
file_size = ftell(fp);
if (file_size >= (fpos_t)INT_MAX) {
return 0;
}
if (fseek(fp, 0, SEEK_SET) != 0) {
return 0;
}
buf_size = (long)file_size;
*pbuf = malloc(buf_size);
if (*pbuf == NULL) {
return 0;
}
memset(*pbuf, 0, buf_size);
size_read = fread(*pbuf, 1, buf_size, fp);
if (size_read < buf_size) {
free(*pbuf);
*pbuf = NULL;
return 0;
}
return size_read;
}
int get_constant_pool(CLASS_FILE_1 *class_file_bytes, uint8_t ***ppointers) {
int i;
int cpcnt;
uint8_t *current_bytes;
cpcnt = class_file_bytes->constant_pool_count;
cpcnt = ntohs(cpcnt);
if (cpcnt <= 1) {
return cpcnt;
}
*ppointers = (uint8_t **)malloc(cpcnt * sizeof(**ppointers));
(*ppointers)[0] = NULL;
current_bytes = (uint8_t *)class_file_bytes;
current_bytes += sizeof(*class_file_bytes);
for (i = 1; i < cpcnt; i++) {
int size;
(*ppointers)[i] = current_bytes;
size = get_constant_info_size(current_bytes);
current_bytes += size;
}
return cpcnt;
}
void print_constant_info(uint8_t *bytes) {
uint8_t tag;
tag = *bytes;
switch (tag) {
case CONSTANT_Class:
{
CONSTANT_CLASS_INFO *p = (CONSTANT_CLASS_INFO *)bytes;
printf("Class: tag=%#x, name_index=%#x\n", p->tag, ntohs(p->name_index));
}
break;
case CONSTANT_Fieldref:
{
CONSTANT_FIELDREF_INFO *p = (CONSTANT_FIELDREF_INFO *)bytes;
printf("Fieldref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n",
p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index));
}
break;
case CONSTANT_Methodref:
{
CONSTANT_METHODREF_INFO *p = (CONSTANT_METHODREF_INFO *)bytes;
printf("Methodref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n",
p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index));
}
break;
case CONSTANT_InterfaceMethodref:
{
CONSTANT_INTERFACEMETHODREF_INFO *p = (CONSTANT_INTERFACEMETHODREF_INFO *)bytes;
printf("InterfaceMethodref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n",
p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index));
}
break;
case CONSTANT_String:
{
CONSTANT_STRING_INFO *p = (CONSTANT_STRING_INFO *)bytes;
printf("String: tag=%#x, string_index=%#x\n", p->tag, ntohs(p->string_index));
}
break;
case CONSTANT_Integer:
{
CONSTANT_INTEGER_INFO *p = (CONSTANT_INTEGER_INFO *)bytes;
printf("Integer: tag=%#x, bytes=%#x\n", p->tag, p->bytes);
}
break;
case CONSTANT_Float:
{
CONSTANT_FLOAT_INFO *p = (CONSTANT_FLOAT_INFO *)bytes;
printf("Float: tag=%#x, bytes=%#x\n", p->tag, p->bytes);
}
break;
case CONSTANT_Long:
{
CONSTANT_LONG_INFO *p = (CONSTANT_LONG_INFO *)bytes;
printf("Long: tag=%#x, high_bytes=%#x, low_bytes=%#x\n",
p->tag, p->high_bytes, p->low_bytes);
}
break;
case CONSTANT_Double:
{
CONSTANT_DOUBLE_INFO *p = (CONSTANT_DOUBLE_INFO *)bytes;
printf("Long: tag=%#x, high_bytes=%#x, low_bytes=%#x\n",
p->tag, p->high_bytes, p->low_bytes);
}
break;
case CONSTANT_NameAndType:
{
CONSTANT_NAMEANDTYPE_INFO *p = (CONSTANT_NAMEANDTYPE_INFO *)bytes;
printf("NameAndType: tag=%#x, name_index=%#x, descriptor_index=%#x\n",
p->tag, ntohs(p->name_index), ntohs(p->descriptor_index));
}
break;
case CONSTANT_Utf8:
{
CONSTANT_UTF8_INFO *p = (CONSTANT_UTF8_INFO *)bytes;
int n = ntohs(p->length);
int i;
uint8_t *str = &(p->bytes[0]);
printf("Utf8: tag=%#x, bytes=");
for (i = 0; i < n; i++) {
char c = (char)str[i];
if (isprint(c)) {
printf("%c ", c);
} else {
printf("%02x ", c);
}
}
printf("\n");
}
break;
case CONSTANT_MethodHandle:
{
CONSTANT_METHODHANDLE_INFO *p = (CONSTANT_METHODHANDLE_INFO *)bytes;
printf("MethodHandle: tag=%#x, reference_kind=%#x, reference_index=%#x\n",
p->tag, p->reference_kind, p->reference_index);
}
break;
case CONSTANT_MethodType:
{
CONSTANT_METHODTYPE_INFO *p = (CONSTANT_METHODTYPE_INFO *)bytes;
printf("MethodType: tag=%#x, descriptor_index=%#x\n", p->tag, ntohs(p->descriptor_index));
}
break;
case CONSTANT_InvokeDynamic:
{
CONSTANT_INVOKEDYNAMIC_INFO *p = (CONSTANT_INVOKEDYNAMIC_INFO *)bytes;
printf("InvokeDynamic: tag=%#x, bootstrap_method_attr_index=%#x, name_and_type_index=%#x\n",
p->tag, ntohs(p->bootstrap_method_attr_index), ntohs(p->name_and_type_index));
}
break;
default:
{
printf("Unknown: tag=%#x\n", tag);
}
break;
}
}
void print_constant_pool(uint8_t **cppointers, int cpcnt) {
int i;
for (i = 1; i < cpcnt; i++) {
uint8_t *p = cppointers[i];
printf("------------------------\n[%03x] ", i);
print_constant_info(p);
printf("------------------------\n");
}
}
int main(int argc, char *argv[]) {
char *class_file_name = NULL;
FILE *class_file = NULL;
uint8_t *class_file_bytes = NULL;
long class_file_size = 0;
uint8_t **cppointers = NULL;
int cpcnt = 0;
int exitstat = 0;
if (argc < 2) {
printf("[USAGE] %s <class-file-name>\n", argv[0]);
goto END;
}
class_file_name = argv[1];
class_file = fopen(class_file_name, "rb");
if (class_file == NULL) {
exitstat = -1;
goto END;
}
class_file_size = read_class_file(class_file, &class_file_bytes);
if (class_file_bytes == NULL) {
exitstat = -1;
goto END;
}
cpcnt = get_constant_pool((CLASS_FILE_1 *)class_file_bytes, &cppointers);
if (cppointers == NULL) {
exitstat = -1;
goto END;
}
print_constant_pool(cppointers, cpcnt);
END:
if (class_file != NULL) {
fclose(class_file);
}
if (class_file_bytes != NULL) {
free(class_file_bytes);
}
if (cppointers != NULL) {
free(cppointers);
}
return exitstat;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment