Repository navigation
Expand file tree
/
Copy pathCLASSTemplate.bt
More file actions
executable file
·253 lines (232 loc) · 8 KB
/
Copy pathCLASSTemplate.bt
File metadata and controls
executable file
·253 lines (232 loc) · 8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
//-------------------------------------------------------------------------
//--- 010 Editor v2.1 Binary Template
//
// File: CLASSTemplate.bt
// Author: Kevin O. Grover <kevin@kevingrover.net>
// Purpose: A template for parsing Java Class (JVM) Files
// Version: 1.1 2014-08-13
// History:
// 2007-02-26 kog Original Version
// 2014-08-13 kog Updated for Java 7/8 Version number (and future)
//
// This template was written to the "The Java Virtual Machine
// Specification", Second Edition, by Tim Lindholm, Frank Yellin.
// It was later updated to include the provisio in that spec (and future
// specs).
//
// The details used to write this Template came mainly from Chapter 4:
// "The <code>class</code> File Format".
//
// You can get the document from the Oracle Java Pages or Wikipedia:
// http://docs.oracle.com/javase/specs/
// http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf
// http://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf
// http://en.wikipedia.org/wiki/Class_file
//-------------------------------------------------------------------------
BigEndian();
// Types used in the JVM Spec.
// (To make this code as close to the text in the spec as possible.)
typedef uint32 u4;
typedef uint16 u2;
typedef ubyte u1;
typedef enum <u2> eACCESS_FLAGS {
ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package.
ACC_PRIVATE = 0x0002, // Declared private; usable only within the defining class.
ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses.
ACC_STATIC = 0x0008, // Declared static.
ACC_FINAL = 0x0010, // Declared final; no subclasses allowed.
ACC_SUPER = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_VOLATILE = 0x0040, // Declared volatile; cannot be cached.
ACC_TRANSIENT = 0x0080, // Declared transient; not written or read by a persistent object manager.
ACC_NATIVE = 0x0100, // Declared native; implemented in a language other than Java.
ACC_INTERFACE = 0x0200, // Is an interface, not a class.
ACC_ABSTRACT = 0x0400, // Declared abstract; may not be instantiated.
ACC_STRICT = 0x0800 // Declared strictfp; floating-point mode is FP-strict
} AF <read=read_AF>;
string read_AF (local AF &af) {
local string s = "";
local int commaNeeded = 0;
local AF i = 1;
SPrintf (s, "%d: ", af);
// Iterate over all possible values the flags
// if the given bit is set, add it's text representation to the
// return string.
// NOTE: There's probably a better way to do this. (More portable?)
while (i < ACC_STRICT) {
if (af && i) {
if (commaNeeded) {
s += ", ";
}
s += EnumToString(i);
commaNeeded = 1;
}
i = i << 1;
}
return s;
}
// Constants for cp_info.tag ...
typedef enum <u1> eCP_CONST {
CONSTANT_Utf8 = 1,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameAndType = 12,
} CP_CONST;
// Constant Pool Table Structure
// NOTE: These are NOT constant sized items. Although referenced
// like an array in the main structure, you can not use position
// to directly infer a byte offset because you do not know the
// sizes of the items preceeding it.
typedef struct {
CP_CONST tag;
switch(tag)
{
case CONSTANT_Class:
u2 name_index;
break;
case CONSTANT_Methodref:
case CONSTANT_Fieldref:
case CONSTANT_InterfaceMethodref:
u2 class_index;
u2 name_and_type_index;
break;
case CONSTANT_Utf8:
u2 length;
char bytes[length];
break;
case CONSTANT_Integer:
case CONSTANT_Float:
u4 bytes;
break;
case CONSTANT_Long:
case CONSTANT_Double:
u4 high_bytes;
u4 low_bytes;
break;
case CONSTANT_String:
u2 string_index;
break;
case CONSTANT_NameAndType:
u2 name_index;
u2 descriptor_index;
break;
default:
local string s;
SPrintf(s, "Unknown 'constant_pool' tag: %d", tag);
Warning(s);
return -3;
}
} cp_info <read=read_cp_info, optimize=false>;
/**
* Reader for 'cp_info'
* @param cp_info Constant Pool info structure
*/
string read_cp_info (local cp_info &i)
{
local string s = "";
s = EnumToString(i.tag);
if (i.tag == CONSTANT_Utf8) {
s += ": " + i.bytes;
}
return s;
}
typedef struct {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
} attribute_info <optimize=false>;
typedef struct {
AF access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
} field_info <optimize=false>;
typedef struct {
AF access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
} method_info <optimize=false>;
// MAIN Structure
typedef struct {
u4 magic <format=hex>;
if (magic != 0xCAFEBABE) { // Check that 'magic' is correct
Warning("Incorrect Magic Number. This is not a JVM Class. Template Terminated.");
return -1;
}
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
AF access_flags;
u2 this_class; // Reference into constant_pool table
if (this_class < 1 || this_class > constant_pool_count-1) {
local string s;
SPrintf(s,"Bad 'this_class' reference (%d). It should be in the range [1..%d]", this_class, constant_pool_count-1);
Warning(s);
return -2;
}
u2 super_class; // Reference into constant_pool table
if (super_class < 1 || super_class > constant_pool_count-1) {
local string s;
SPrintf(s,"Bad 'super_class' reference (%d). It should be in the range [1..%d]", super_class, constant_pool_count-1);
Warning(s);
return -2;
}
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
} JVMClass <read=read_JVMClass, optimize=false>;
/**
* Reader for 'JVMClass'
* Returns the JVM Version: major.minor and the Java version (if it can
* calculate it from the JVM Version.
* @param j JVMClass The JVM Class Structure
* @return string The version information
*/
string read_JVMClass (local JVMClass &j)
{
// JVM Version (as stored in the class file)
local string s;
SPrintf (s, "JVM class v%d.%d", j.major_version, j.minor_version);
// Java Runtime Version. From the JVM Spec for class files
local int major = 1;
local int minor = 0;
if (j.major_version == 45) {
if (j.minor_version >= 3) minor = 1;
} else {
if (j.major_version >= 46) {
minor = j.major_version - 44;
} else {
// Unknown: it's either newer or older than expected
major = 0;
minor = 0;
Warning("Unexpected JVM major version number.");
}
}
if (major || minor) {
local string jre_v;
SPrintf(jre_v, " (Java %d.%d)", major, minor);
s += jre_v;
} else {
s += " (Unknown Java Version)";
}
return s;
}
// *****************************************
// MAIN - Allocate data here...
// *****************************************
struct JVMClass jc;