Skip to content

Commit a860c39

Browse files
authored
patterns: Added Java HPROF pattern
1 parent da934e2 commit a860c39

File tree

3 files changed

+363
-0
lines changed

3 files changed

+363
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
8484
| Halo Tag || [`patterns/hinf_tag.hexpat`](patterns/hinf_tag.hexpat) | Halo Infinite Tag Files |
8585
| Halo Module || [`patterns/hinf_module.hexpat`](patterns/hinf_module.hexpat) | Halo Infinite Module Archive Files |
8686
| Halo HavokScript || [`patterns/hinf_luas.hexpat`](patterns/hinf_luas.hexpat) | Halo Infinite HavokScript 5.1 Bytecode |
87+
| HPROF || [`patterns/hprof.hexpat`](patterns/hprof.hexpat) | Java HPROF Profiler Data Format |
8788
| HSDT || [`patterns/hsdt.hexpat`](patterns/hsdt.hexpat) | HiSilicon device-tree table images |
8889
| ICO | | [`patterns/ico.hexpat`](patterns/ico.hexpat) | Icon (.ico) or Cursor (.cur) files |
8990
| ID3 | `audio/mpeg` | [`patterns/id3.hexpat`](patterns/id3.hexpat) | ID3 tags in MP3 files |

patterns/hprof.hexpat

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
#pragma author WerWolv
2+
#pragma description Java HPROF Profiler Data Format
3+
#pragma endian big
4+
#pragma magic [ "JAVA PROFILE" ] @ 0x00
5+
6+
#pragma array_limit 0
7+
#pragma pattern_limit 0
8+
9+
import std.mem;
10+
import std.io;
11+
import std.sys;
12+
import std.core;
13+
14+
enum Tag : u8 {
15+
STRING_IN_UTF8 = 0x01,
16+
LOAD_CLASS = 0x02,
17+
UNLOAD_CLASS = 0x03,
18+
STACK_FRAME = 0x04,
19+
STACK_TRACE = 0x05,
20+
ALLOC_SITES = 0x06,
21+
HEAP_SUMMARY = 0x07,
22+
START_THREAD = 0x0A,
23+
END_THREAD = 0x0B,
24+
HEAP_DUMP = 0x0C,
25+
HEAP_DUMP_SEGMENT = 0x1C,
26+
HEAP_DUMP_END = 0x2C,
27+
CPU_SAMPLES = 0x0D,
28+
CONTROL_SETTINGS = 0x0E,
29+
};
30+
31+
u32 id_size = 0;
32+
struct ID {
33+
match (id_size) {
34+
(1): u8 value;
35+
(2): u16 value;
36+
(4): u32 value;
37+
(8): u64 value;
38+
(_): std::error("Invalid ID size");
39+
}
40+
} [[sealed, format("format_id")]];
41+
42+
fn format_id(ref auto id) {
43+
return std::format("0x{:0{}X}", id.value, id_size * 2);
44+
};
45+
46+
struct StringInUTF8 {
47+
ID id;
48+
char string[parent.length - sizeof(id)];
49+
};
50+
51+
struct LoadClass {
52+
u32 classSerialNumber;
53+
ID classObjectId;
54+
u32 stackTraceSerialNumber;
55+
ID classNameStringID;
56+
};
57+
58+
struct StackFrame {
59+
ID stackFrameId;
60+
ID methodNameStringId;
61+
ID methodSignatureStringId;
62+
ID sourceFileNameStringId;
63+
u32 classSerialNumber;
64+
u32 lineInformation;
65+
};
66+
67+
struct StackTrace {
68+
u32 stackTraceSerialNumber;
69+
u32 threadSerialNumber;
70+
u32 numberOfFrames;
71+
ID stackFrameIds[while(!std::mem::reached(addressof(this) + parent.length))];
72+
};
73+
74+
enum SubTag : u8 {
75+
RootUnknown = 0xFF,
76+
RootJNIGlobal = 0x01,
77+
RootJNILocal = 0x02,
78+
RootJavaFrame = 0x03,
79+
RootNativeStack = 0x04,
80+
RootStickyClass = 0x05,
81+
RootThreadBlock = 0x06,
82+
RootMonitorUsed = 0x07,
83+
RootThreadObject = 0x08,
84+
ClassDump = 0x20,
85+
InstanceDump = 0x21,
86+
ObjectArrayDump = 0x22,
87+
PrimitiveArrayDump = 0x23
88+
};
89+
90+
enum EntryType : u8 {
91+
Object = 2,
92+
Boolean = 4,
93+
Char = 5,
94+
Float = 6,
95+
Double = 7,
96+
Byte = 8,
97+
Short = 9,
98+
Int = 10,
99+
Long = 11
100+
};
101+
102+
struct BasicType<auto Tag> {
103+
match (Tag) {
104+
(EntryType::Object): ID value;
105+
(EntryType::Boolean): bool value;
106+
(EntryType::Char): { padding[1]; char value; }
107+
(EntryType::Float): float value;
108+
(EntryType::Double): double value;
109+
(EntryType::Byte): u8 value;
110+
(EntryType::Short): u16 value;
111+
(EntryType::Int): u32 value;
112+
(EntryType::Long): u64 value;
113+
(_): std::error("Invalid BasicType type");
114+
}
115+
} [[sealed, format("format_basic_type")]];
116+
117+
fn format_basic_type(ref auto basicType) {
118+
return std::format("{}", basicType.value);
119+
};
120+
121+
struct ConstantPoolEntry {
122+
u16 constantPoolIndex;
123+
EntryType type;
124+
BasicType<type> value;
125+
};
126+
127+
struct ConstantPoolArray {
128+
u16 size;
129+
ConstantPoolEntry entries[size];
130+
};
131+
132+
struct StaticFieldEntry {
133+
ID staticFieldNameStringId;
134+
EntryType type;
135+
BasicType<type> value;
136+
};
137+
138+
struct StaicFieldArray {
139+
u16 size;
140+
StaticFieldEntry entries[size];
141+
};
142+
143+
struct InstanceField {
144+
ID fieldNameStringId;
145+
EntryType fieldType;
146+
};
147+
148+
struct InstanceFieldsArray {
149+
u16 size;
150+
InstanceField instanceFields[size];
151+
};
152+
153+
struct HeapDump {
154+
SubTag subTag;
155+
match (subTag) {
156+
(SubTag::RootUnknown): {
157+
ID objectId;
158+
}
159+
(SubTag::RootJNIGlobal): {
160+
ID objectId;
161+
ID jniGlobalRefId;
162+
}
163+
(SubTag::RootJNILocal): {
164+
ID objectId;
165+
u32 threadSerialNumber;
166+
u32 frameNumberInStackTrace;
167+
}
168+
(SubTag::RootJavaFrame): {
169+
ID objectId;
170+
u32 threadSerialNumber;
171+
u32 frameNumberInStackTrace;
172+
}
173+
(SubTag::RootNativeStack): {
174+
ID objectId;
175+
u32 threadSerialNumber;
176+
}
177+
(SubTag::RootStickyClass): {
178+
ID objectId;
179+
}
180+
(SubTag::RootThreadBlock): {
181+
ID objectId;
182+
u32 threadSerialNumber;
183+
}
184+
(SubTag::RootMonitorUsed): {
185+
ID objectId;
186+
}
187+
(SubTag::RootThreadObject): {
188+
ID threadObjectId;
189+
u32 threadSerialNumber;
190+
u32 stackTraceSerialNumber;
191+
}
192+
(SubTag::ClassDump): {
193+
ID classObjectId;
194+
u32 stackTraceSerialNumber;
195+
ID superClassObjectId;
196+
ID classLoaderObjectId;
197+
ID signersObjectId;
198+
ID protectionDomainObjectId;
199+
ID reserved[2];
200+
u32 instanceSize;
201+
ConstantPoolArray constantPool;
202+
StaicFieldArray staticFields;
203+
InstanceFieldsArray instanceFields;
204+
}
205+
(SubTag::InstanceDump): {
206+
ID objectId;
207+
u32 stackTraceSerialNumber;
208+
ID classObjectId;
209+
u32 numBytes;
210+
std::mem::Bytes<numBytes> instanceFieldValues;
211+
}
212+
(SubTag::ObjectArrayDump): {
213+
ID arrayObjectId;
214+
u32 stackTraceSerialNumber;
215+
u32 numberOfElements;
216+
ID arrayClassObjectId;
217+
ID elements[numberOfElements];
218+
}
219+
(SubTag::PrimitiveArrayDump): {
220+
ID arrayObjectId;
221+
u32 stackTraceSerialNumber;
222+
u32 numberOfElements;
223+
EntryType type;
224+
BasicType<type> value[numberOfElements];
225+
}
226+
(_): std::error(std::format("Heap Dump Sub Tag {:02X} at 0x{:08X} {}", u32(subTag), $, std::core::array_index()));
227+
}
228+
229+
if ($ - addressof(parent.length) + sizeof(parent.length) >= parent.length)
230+
break;
231+
232+
u8 endTag [[no_unique_address, hidden]];
233+
if (endTag == 0x2C) {
234+
padding[1];
235+
break;
236+
}
237+
};
238+
239+
struct UnloadClass {
240+
u32 classSerialNumber;
241+
};
242+
243+
bitfield AllocSitesFlags {
244+
completeInsteadOfIncremental : 1;
245+
sortedByLineInsteadOfAllocation : 1;
246+
forceGc : 1;
247+
padding : 13;
248+
};
249+
250+
struct AllocSite {
251+
bool arrayIndicator;
252+
u32 classSerialNumber;
253+
u32 stackTraceSerialNumber;
254+
u32 numberOfLiveBytes;
255+
u32 numberOfLiveInstances;
256+
u32 numberOfBytesAllocated;
257+
u32 numberOfInstancesAllocated;
258+
};
259+
260+
struct AllocSites {
261+
AllocSitesFlags flags;
262+
float cutoffRatio;
263+
u32 totalLiveBytes;
264+
u32 totalLiveInstances;
265+
u64 totalBytesAllocated;
266+
u64 totalInstancesAllocated;
267+
u32 numSites;
268+
AllocSite sites[numSites];
269+
};
270+
271+
struct HeapSummary {
272+
u32 totalLiveBytes;
273+
u32 totalLiveInstances;
274+
u64 totalBytesAllocated;
275+
u64 totalInstancesAllocated;
276+
};
277+
278+
struct StartThread {
279+
u32 threadSerialNumber;
280+
ID threadObjectId;
281+
u32 stackTraceSerialNumber;
282+
ID threadNameStringId;
283+
ID threadGroupNameId;
284+
ID threadParentGroupNameId;
285+
};
286+
287+
struct EndThread {
288+
u32 threadSerialNumber;
289+
};
290+
291+
struct Sample {
292+
u32 numberOfSamples;
293+
u32 stackTraceSerialNumber;
294+
};
295+
296+
struct CpuSamples {
297+
u32 numSamples;
298+
Sample samples[numSamples];
299+
};
300+
301+
bitfield ControlSettingsFlags {
302+
allocTraces : 1;
303+
cpuSampling : 1;
304+
padding : 30;
305+
};
306+
307+
struct ControlSettings {
308+
ControlSettingsFlags flags;
309+
u16 stackTraceDepth;
310+
};
311+
312+
struct Record {
313+
Tag tag;
314+
u32 time;
315+
u32 length;
316+
317+
match (tag) {
318+
(Tag::STRING_IN_UTF8):
319+
StringInUTF8 body;
320+
(Tag::LOAD_CLASS):
321+
LoadClass body;
322+
(Tag::UNLOAD_CLASS):
323+
UnloadClass body;
324+
(Tag::STACK_FRAME):
325+
StackFrame body;
326+
(Tag::STACK_TRACE):
327+
StackTrace body;
328+
(Tag::ALLOC_SITES):
329+
AllocSites body;
330+
(Tag::HEAP_SUMMARY):
331+
HeapSummary body;
332+
(Tag::START_THREAD):
333+
StartThread body;
334+
(Tag::END_THREAD):
335+
EndThread body;
336+
(Tag::HEAP_DUMP | Tag::HEAP_DUMP_SEGMENT):
337+
HeapDump heapDumps[while(true)];
338+
(Tag::HEAP_DUMP_END):
339+
std::error("HEAP_DUMP_END Tag without previous HEAP_DUMP or HEAP_DUMP_SEGMENT Tag");
340+
(Tag::CPU_SAMPLES):
341+
CpuSamples body;
342+
(Tag::CONTROL_SETTINGS):
343+
ControlSettings body;
344+
(_):
345+
std::error(std::format("Unknown record type {:02X} at address 0x{:08X}, index {}", u8(tag), addressof(tag), std::core::array_index()));
346+
}
347+
};
348+
349+
struct Header {
350+
char format_name[];
351+
u32 identifier_size;
352+
id_size = identifier_size;
353+
u32 timestamp_high;
354+
u32 time_stamp_low;
355+
};
356+
357+
struct HPROF {
358+
Header header;
359+
Record records[while(!std::mem::eof())];
360+
};
361+
362+
HPROF hprof @ 0x00;
276 KB
Binary file not shown.

0 commit comments

Comments
 (0)