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.
- package/LICENSE +21 -0
- package/README.md +123 -2
- package/bin/run-with-log.ps1 +173 -0
- package/bin/run-with-log.sh +136 -0
- package/cordis.patch.yml +25 -0
- package/lib/client-codemirror.js +29822 -0
- package/lib/client.js +10772 -0
- package/lib/debug/engine.js +537 -0
- package/lib/debug/vendor/LICENSE +21 -0
- package/lib/debug/vendor/README.md +36 -0
- package/lib/debug/vendor/UPSTREAM_COMMIT +1 -0
- package/lib/debug/vendor/jdwp/client.js +1104 -0
- package/lib/debug/vendor/jdwp/constants.js +309 -0
- package/lib/debug/vendor/jdwp/protocol.js +253 -0
- package/lib/debug/vendor/src/jdwp/client.ts +1368 -0
- package/lib/debug/vendor/src/jdwp/constants.ts +310 -0
- package/lib/debug/vendor/src/jdwp/protocol.ts +326 -0
- package/lib/index.js +6112 -0
- package/lib/standalone/vendor/react-dom.js +267 -0
- package/lib/standalone/vendor/react.js +31 -0
- package/lib/standalone/window.html +248 -0
- package/package.json +96 -4
- package/skills/dsh-ris-ide-debug/SKILL.md +158 -0
- package/test/client-viewer.test.mjs +3557 -0
- package/test/debug-engine.test.mjs +351 -0
- package/test/harness.test.mjs +93 -0
- package/test/host-nogit.test.mjs +48 -0
- package/test/host-tail.test.mjs +2846 -0
- package/test/host-window.test.mjs +119 -0
|
@@ -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
|
+
}
|