dsh-ris-ide 0.0.0-stage → 1.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,310 @@
1
+ // JDWP Command Sets and Commands
2
+ // Reference: https://docs.oracle.com/en/java/javase/17/docs/specs/jdwp/jdwp-protocol.html
3
+
4
+ export const HANDSHAKE = "JDWP-Handshake";
5
+
6
+ // Packet flags
7
+ export const FLAGS_REPLY = 0x80;
8
+
9
+ // Command Sets
10
+ export const enum CommandSet {
11
+ VirtualMachine = 1,
12
+ ReferenceType = 2,
13
+ ClassType = 3,
14
+ ArrayType = 4,
15
+ InterfaceType = 5,
16
+ Method = 6,
17
+ Field = 8,
18
+ ObjectReference = 9,
19
+ StringReference = 10,
20
+ ThreadReference = 11,
21
+ ThreadGroupReference = 12,
22
+ ArrayReference = 13,
23
+ ClassLoaderReference = 14,
24
+ EventRequest = 15,
25
+ StackFrame = 16,
26
+ ClassObjectReference = 17,
27
+ ModuleReference = 18,
28
+ Event = 64,
29
+ }
30
+
31
+ // VirtualMachine commands
32
+ export const enum VMCommand {
33
+ Version = 1,
34
+ ClassesBySignature = 2,
35
+ AllClasses = 3,
36
+ AllThreads = 4,
37
+ TopLevelThreadGroups = 5,
38
+ Dispose = 6,
39
+ IDSizes = 7,
40
+ Suspend = 8,
41
+ Resume = 9,
42
+ Exit = 10,
43
+ CreateString = 11,
44
+ Capabilities = 12,
45
+ ClassPaths = 13,
46
+ DisposeObjects = 14,
47
+ HoldEvents = 15,
48
+ ReleaseEvents = 16,
49
+ CapabilitiesNew = 17,
50
+ RedefineClasses = 18,
51
+ SetDefaultStratum = 19,
52
+ AllClassesWithGeneric = 20,
53
+ InstanceCounts = 21,
54
+ AllModules = 22,
55
+ }
56
+
57
+ // ReferenceType commands
58
+ export const enum ReferenceTypeCommand {
59
+ Signature = 1,
60
+ ClassLoader = 2,
61
+ Modifiers = 3,
62
+ Fields = 4,
63
+ Methods = 5,
64
+ GetValues = 6,
65
+ SourceFile = 7,
66
+ NestedTypes = 8,
67
+ Status = 9,
68
+ Interfaces = 10,
69
+ ClassObject = 11,
70
+ SourceDebugExtension = 12,
71
+ SignatureWithGeneric = 13,
72
+ FieldsWithGeneric = 14,
73
+ MethodsWithGeneric = 15,
74
+ Instances = 16,
75
+ ClassFileVersion = 17,
76
+ ConstantPool = 18,
77
+ Module = 19,
78
+ }
79
+
80
+ // Method commands
81
+ export const enum MethodCommand {
82
+ LineTable = 1,
83
+ VariableTable = 2,
84
+ Bytecodes = 3,
85
+ IsObsolete = 4,
86
+ VariableTableWithGeneric = 5,
87
+ }
88
+
89
+ // ThreadReference commands
90
+ export const enum ThreadCommand {
91
+ Name = 1,
92
+ Suspend = 2,
93
+ Resume = 3,
94
+ Status = 4,
95
+ ThreadGroup = 5,
96
+ Frames = 6,
97
+ FrameCount = 7,
98
+ OwnedMonitors = 8,
99
+ CurrentContendedMonitor = 9,
100
+ Stop = 10,
101
+ Interrupt = 11,
102
+ SuspendCount = 12,
103
+ OwnedMonitorsStackDepthInfo = 13,
104
+ ForceEarlyReturn = 14,
105
+ }
106
+
107
+ // StackFrame commands
108
+ export const enum StackFrameCommand {
109
+ GetValues = 1,
110
+ SetValues = 2,
111
+ ThisObject = 3,
112
+ PopFrames = 4,
113
+ }
114
+
115
+ // EventRequest commands
116
+ export const enum EventRequestCommand {
117
+ Set = 1,
118
+ Clear = 2,
119
+ ClearAllBreakpoints = 3,
120
+ }
121
+
122
+ // StringReference commands
123
+ export const enum StringReferenceCommand {
124
+ Value = 1,
125
+ }
126
+
127
+ // ObjectReference commands
128
+ export const enum ObjectReferenceCommand {
129
+ ReferenceType = 1,
130
+ GetValues = 2,
131
+ SetValues = 3,
132
+ MonitorInfo = 5,
133
+ InvokeMethod = 6,
134
+ DisableCollection = 7,
135
+ EnableCollection = 8,
136
+ IsCollected = 9,
137
+ ReferringObjects = 10,
138
+ }
139
+
140
+ // ArrayReference commands
141
+ export const enum ArrayReferenceCommand {
142
+ Length = 1,
143
+ GetValues = 2,
144
+ SetValues = 3,
145
+ }
146
+
147
+ // Event kinds
148
+ export const enum EventKind {
149
+ SingleStep = 1,
150
+ Breakpoint = 2,
151
+ FramePop = 3,
152
+ Exception = 4,
153
+ UserDefined = 5,
154
+ ThreadStart = 6,
155
+ ThreadDeath = 7,
156
+ ClassPrepare = 8,
157
+ ClassUnload = 9,
158
+ ClassLoad = 10,
159
+ FieldAccess = 20,
160
+ FieldModification = 21,
161
+ ExceptionCatch = 30,
162
+ MethodEntry = 40,
163
+ MethodExit = 41,
164
+ MethodExitWithReturnValue = 42,
165
+ MonitorContendedEnter = 43,
166
+ MonitorContendedEntered = 44,
167
+ MonitorWait = 45,
168
+ MonitorWaited = 46,
169
+ VMStart = 90,
170
+ VMDeath = 99,
171
+ }
172
+
173
+ // Suspend policy
174
+ export const enum SuspendPolicy {
175
+ None = 0,
176
+ EventThread = 1,
177
+ All = 2,
178
+ }
179
+
180
+ // Step size
181
+ export const enum StepSize {
182
+ Min = 0,
183
+ Line = 1,
184
+ }
185
+
186
+ // Step depth
187
+ export const enum StepDepth {
188
+ Into = 0,
189
+ Over = 1,
190
+ Out = 2,
191
+ }
192
+
193
+ // Type tags
194
+ export const enum TypeTag {
195
+ Class = 1,
196
+ Interface = 2,
197
+ Array = 3,
198
+ }
199
+
200
+ // Tag values for primitive/object types
201
+ export const enum Tag {
202
+ Array = 91, // '['
203
+ Byte = 66, // 'B'
204
+ Char = 67, // 'C'
205
+ Object = 76, // 'L'
206
+ Float = 70, // 'F'
207
+ Double = 68, // 'D'
208
+ Int = 73, // 'I'
209
+ Long = 74, // 'J'
210
+ Short = 83, // 'S'
211
+ Void = 86, // 'V'
212
+ Boolean = 90, // 'Z'
213
+ String = 115, // 's'
214
+ Thread = 116, // 't'
215
+ ThreadGroup = 103, // 'g'
216
+ ClassLoader = 108, // 'l'
217
+ ClassObject = 99, // 'c'
218
+ Null = 110, // 'n'
219
+ }
220
+
221
+ // Thread status
222
+ export const enum ThreadStatus {
223
+ Zombie = 0,
224
+ Running = 1,
225
+ Sleeping = 2,
226
+ Monitor = 3,
227
+ Wait = 4,
228
+ }
229
+
230
+ // Suspend status
231
+ export const enum SuspendStatus {
232
+ Suspended = 1,
233
+ }
234
+
235
+ // Event modifier kinds
236
+ export const enum ModKind {
237
+ Count = 1,
238
+ Conditional = 2,
239
+ ThreadOnly = 3,
240
+ ClassOnly = 4,
241
+ ClassMatch = 5,
242
+ ClassExclude = 6,
243
+ LocationOnly = 7,
244
+ ExceptionOnly = 8,
245
+ FieldOnly = 9,
246
+ Step = 10,
247
+ InstanceOnly = 11,
248
+ SourceNameMatch = 12,
249
+ }
250
+
251
+ // JDWP error codes
252
+ export const enum JDWPError {
253
+ None = 0,
254
+ InvalidThread = 10,
255
+ InvalidThreadGroup = 11,
256
+ InvalidPriority = 12,
257
+ ThreadNotSuspended = 13,
258
+ ThreadSuspended = 14,
259
+ ThreadNotAlive = 15,
260
+ InvalidObject = 20,
261
+ InvalidClass = 21,
262
+ ClassNotPrepared = 22,
263
+ InvalidMethodid = 23,
264
+ InvalidLocation = 24,
265
+ InvalidFieldid = 25,
266
+ InvalidFrameid = 30,
267
+ NoMoreFrames = 31,
268
+ OpaqueFrame = 32,
269
+ NotCurrentFrame = 33,
270
+ TypeMismatch = 34,
271
+ InvalidSlot = 35,
272
+ Duplicate = 40,
273
+ NotFound = 41,
274
+ InvalidMonitor = 50,
275
+ NotMonitorOwner = 51,
276
+ Interrupt = 52,
277
+ InvalidClassFormat = 60,
278
+ CircularClassDefinition = 61,
279
+ FailsVerification = 62,
280
+ AddMethodNotImplemented = 63,
281
+ SchemaChangeNotImplemented = 64,
282
+ InvalidTypestate = 65,
283
+ HierarchyChangeNotImplemented = 66,
284
+ DeleteMethodNotImplemented = 67,
285
+ UnsupportedVersion = 68,
286
+ NamesMismatch = 69,
287
+ ClassModifiersChangeNotImplemented = 70,
288
+ MethodModifiersChangeNotImplemented = 71,
289
+ NotImplemented = 99,
290
+ NullPointer = 100,
291
+ AbsentInformation = 101,
292
+ InvalidEventType = 102,
293
+ IllegalArgument = 103,
294
+ OutOfMemory = 110,
295
+ AccessDenied = 111,
296
+ VmDead = 112,
297
+ Internal = 113,
298
+ UnattachedThread = 115,
299
+ InvalidTag = 500,
300
+ AlreadyInvoking = 502,
301
+ InvalidIndex = 503,
302
+ InvalidLength = 504,
303
+ InvalidString = 506,
304
+ InvalidClassLoader = 507,
305
+ InvalidArray = 508,
306
+ TransportLoad = 509,
307
+ TransportInit = 510,
308
+ NativeMethod = 511,
309
+ InvalidCount = 512,
310
+ }
@@ -0,0 +1,326 @@
1
+ import { FLAGS_REPLY, Tag } from "./constants.js";
2
+
3
+ // ID sizes (set after IDSizes command)
4
+ export interface IDSizes {
5
+ fieldIDSize: number;
6
+ methodIDSize: number;
7
+ objectIDSize: number;
8
+ referenceTypeIDSize: number;
9
+ frameIDSize: number;
10
+ }
11
+
12
+ const defaultIDSizes: IDSizes = {
13
+ fieldIDSize: 8,
14
+ methodIDSize: 8,
15
+ objectIDSize: 8,
16
+ referenceTypeIDSize: 8,
17
+ frameIDSize: 8,
18
+ };
19
+
20
+ // Packet structures
21
+ export interface CommandPacket {
22
+ id: number;
23
+ flags: number;
24
+ commandSet: number;
25
+ command: number;
26
+ data: Buffer;
27
+ }
28
+
29
+ export interface ReplyPacket {
30
+ id: number;
31
+ flags: number;
32
+ errorCode: number;
33
+ data: Buffer;
34
+ }
35
+
36
+ // Buffer writer for building JDWP data
37
+ export class JDWPWriter {
38
+ private buffers: Buffer[] = [];
39
+ private idSizes: IDSizes;
40
+
41
+ constructor(idSizes: IDSizes = defaultIDSizes) {
42
+ this.idSizes = idSizes;
43
+ }
44
+
45
+ writeByte(value: number): this {
46
+ const buf = Buffer.alloc(1);
47
+ buf.writeInt8(value, 0);
48
+ this.buffers.push(buf);
49
+ return this;
50
+ }
51
+
52
+ writeBoolean(value: boolean): this {
53
+ return this.writeByte(value ? 1 : 0);
54
+ }
55
+
56
+ writeShort(value: number): this {
57
+ const buf = Buffer.alloc(2);
58
+ buf.writeInt16BE(value, 0);
59
+ this.buffers.push(buf);
60
+ return this;
61
+ }
62
+
63
+ writeInt(value: number): this {
64
+ const buf = Buffer.alloc(4);
65
+ buf.writeInt32BE(value, 0);
66
+ this.buffers.push(buf);
67
+ return this;
68
+ }
69
+
70
+ writeLong(value: bigint): this {
71
+ const buf = Buffer.alloc(8);
72
+ buf.writeBigInt64BE(value, 0);
73
+ this.buffers.push(buf);
74
+ return this;
75
+ }
76
+
77
+ writeID(value: bigint, size: number): this {
78
+ const buf = Buffer.alloc(size);
79
+ // Write big-endian, right-aligned
80
+ for (let i = size - 1; i >= 0; i--) {
81
+ buf[i] = Number(value & 0xffn);
82
+ value >>= 8n;
83
+ }
84
+ this.buffers.push(buf);
85
+ return this;
86
+ }
87
+
88
+ writeObjectID(value: bigint): this {
89
+ return this.writeID(value, this.idSizes.objectIDSize);
90
+ }
91
+
92
+ writeReferenceTypeID(value: bigint): this {
93
+ return this.writeID(value, this.idSizes.referenceTypeIDSize);
94
+ }
95
+
96
+ writeMethodID(value: bigint): this {
97
+ return this.writeID(value, this.idSizes.methodIDSize);
98
+ }
99
+
100
+ writeFieldID(value: bigint): this {
101
+ return this.writeID(value, this.idSizes.fieldIDSize);
102
+ }
103
+
104
+ writeFrameID(value: bigint): this {
105
+ return this.writeID(value, this.idSizes.frameIDSize);
106
+ }
107
+
108
+ writeThreadID(value: bigint): this {
109
+ return this.writeObjectID(value);
110
+ }
111
+
112
+ writeString(value: string): this {
113
+ const strBuf = Buffer.from(value, "utf-8");
114
+ this.writeInt(strBuf.length);
115
+ this.buffers.push(strBuf);
116
+ return this;
117
+ }
118
+
119
+ writeLocation(typeTag: number, classID: bigint, methodID: bigint, index: bigint): this {
120
+ this.writeByte(typeTag);
121
+ this.writeReferenceTypeID(classID);
122
+ this.writeMethodID(methodID);
123
+ this.writeLong(index);
124
+ return this;
125
+ }
126
+
127
+ toBuffer(): Buffer {
128
+ return Buffer.concat(this.buffers);
129
+ }
130
+ }
131
+
132
+ // Buffer reader for parsing JDWP data
133
+ export class JDWPReader {
134
+ private buffer: Buffer;
135
+ private offset: number = 0;
136
+ private idSizes: IDSizes;
137
+
138
+ constructor(buffer: Buffer, idSizes: IDSizes = defaultIDSizes) {
139
+ this.buffer = buffer;
140
+ this.idSizes = idSizes;
141
+ }
142
+
143
+ get remaining(): number {
144
+ return this.buffer.length - this.offset;
145
+ }
146
+
147
+ readByte(): number {
148
+ const value = this.buffer.readInt8(this.offset);
149
+ this.offset += 1;
150
+ return value;
151
+ }
152
+
153
+ readBoolean(): boolean {
154
+ return this.readByte() !== 0;
155
+ }
156
+
157
+ readShort(): number {
158
+ const value = this.buffer.readInt16BE(this.offset);
159
+ this.offset += 2;
160
+ return value;
161
+ }
162
+
163
+ readInt(): number {
164
+ const value = this.buffer.readInt32BE(this.offset);
165
+ this.offset += 4;
166
+ return value;
167
+ }
168
+
169
+ readLong(): bigint {
170
+ const value = this.buffer.readBigInt64BE(this.offset);
171
+ this.offset += 8;
172
+ return value;
173
+ }
174
+
175
+ readID(size: number): bigint {
176
+ let value = 0n;
177
+ for (let i = 0; i < size; i++) {
178
+ value = (value << 8n) | BigInt(this.buffer[this.offset + i]);
179
+ }
180
+ this.offset += size;
181
+ return value;
182
+ }
183
+
184
+ readObjectID(): bigint {
185
+ return this.readID(this.idSizes.objectIDSize);
186
+ }
187
+
188
+ readReferenceTypeID(): bigint {
189
+ return this.readID(this.idSizes.referenceTypeIDSize);
190
+ }
191
+
192
+ readMethodID(): bigint {
193
+ return this.readID(this.idSizes.methodIDSize);
194
+ }
195
+
196
+ readFieldID(): bigint {
197
+ return this.readID(this.idSizes.fieldIDSize);
198
+ }
199
+
200
+ readFrameID(): bigint {
201
+ return this.readID(this.idSizes.frameIDSize);
202
+ }
203
+
204
+ readThreadID(): bigint {
205
+ return this.readObjectID();
206
+ }
207
+
208
+ readString(): string {
209
+ const length = this.readInt();
210
+ const value = this.buffer.toString("utf-8", this.offset, this.offset + length);
211
+ this.offset += length;
212
+ return value;
213
+ }
214
+
215
+ readLocation(): { typeTag: number; classID: bigint; methodID: bigint; index: bigint } {
216
+ const typeTag = this.readByte();
217
+ const classID = this.readReferenceTypeID();
218
+ const methodID = this.readMethodID();
219
+ const index = this.readLong();
220
+ return { typeTag, classID, methodID, index };
221
+ }
222
+
223
+ readTaggedObjectID(): { tag: number; objectID: bigint } {
224
+ const tag = this.readByte();
225
+ const objectID = this.readObjectID();
226
+ return { tag, objectID };
227
+ }
228
+
229
+ readValue(tag: number): JDWPValue {
230
+ switch (tag) {
231
+ case Tag.Byte:
232
+ return { tag, value: this.readByte() };
233
+ case Tag.Boolean:
234
+ return { tag, value: this.readBoolean() };
235
+ case Tag.Char:
236
+ return { tag, value: String.fromCharCode(this.readShort() & 0xffff) };
237
+ case Tag.Short:
238
+ return { tag, value: this.readShort() };
239
+ case Tag.Int:
240
+ return { tag, value: this.readInt() };
241
+ case Tag.Long:
242
+ return { tag, value: this.readLong() };
243
+ case Tag.Float: {
244
+ const buf = this.buffer.subarray(this.offset, this.offset + 4);
245
+ this.offset += 4;
246
+ return { tag, value: buf.readFloatBE(0) };
247
+ }
248
+ case Tag.Double: {
249
+ const buf = this.buffer.subarray(this.offset, this.offset + 8);
250
+ this.offset += 8;
251
+ return { tag, value: buf.readDoubleBE(0) };
252
+ }
253
+ case Tag.Void:
254
+ return { tag, value: null };
255
+ case Tag.Null:
256
+ return { tag, value: null };
257
+ case Tag.String:
258
+ case Tag.Object:
259
+ case Tag.Array:
260
+ case Tag.Thread:
261
+ case Tag.ThreadGroup:
262
+ case Tag.ClassLoader:
263
+ case Tag.ClassObject:
264
+ return { tag, value: this.readObjectID() };
265
+ default:
266
+ return { tag, value: this.readObjectID() };
267
+ }
268
+ }
269
+
270
+ readUntaggedValue(tag: number): JDWPValue {
271
+ return this.readValue(tag);
272
+ }
273
+ }
274
+
275
+ export interface JDWPValue {
276
+ tag: number;
277
+ value: number | bigint | boolean | string | null;
278
+ }
279
+
280
+ // Build a command packet
281
+ export function buildCommandPacket(
282
+ id: number,
283
+ commandSet: number,
284
+ command: number,
285
+ data: Buffer = Buffer.alloc(0),
286
+ ): Buffer {
287
+ const length = 11 + data.length;
288
+ const header = Buffer.alloc(11);
289
+ header.writeInt32BE(length, 0);
290
+ header.writeInt32BE(id, 4);
291
+ header.writeUInt8(0, 8); // flags
292
+ header.writeUInt8(commandSet, 9);
293
+ header.writeUInt8(command, 10);
294
+ return Buffer.concat([header, data]);
295
+ }
296
+
297
+ // Parse a reply packet from buffer
298
+ export function parseReplyPacket(buffer: Buffer): ReplyPacket | null {
299
+ if (buffer.length < 11) return null;
300
+ const length = buffer.readInt32BE(0);
301
+ if (buffer.length < length) return null;
302
+
303
+ return {
304
+ id: buffer.readInt32BE(4),
305
+ flags: buffer.readUInt8(8),
306
+ errorCode: buffer.readUInt16BE(9),
307
+ data: buffer.subarray(11, length),
308
+ };
309
+ }
310
+
311
+ // Check if buffer has a complete packet
312
+ export function hasCompletePacket(buffer: Buffer): boolean {
313
+ if (buffer.length < 4) return false;
314
+ const length = buffer.readInt32BE(0);
315
+ return buffer.length >= length;
316
+ }
317
+
318
+ export function getPacketLength(buffer: Buffer): number {
319
+ if (buffer.length < 4) return -1;
320
+ return buffer.readInt32BE(0);
321
+ }
322
+
323
+ export function isReplyPacket(buffer: Buffer): boolean {
324
+ if (buffer.length < 9) return false;
325
+ return (buffer.readUInt8(8) & FLAGS_REPLY) !== 0;
326
+ }