added structured output to debug variables
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 19 Sep 2022 02:48:37 +0000 (21:48 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 19 Sep 2022 02:48:37 +0000 (21:48 -0500)
interpreter/include/ovm_debug.h
interpreter/src/debug/debug_runtime_values.c
interpreter/src/debug/debug_thread.c
misc/vscode/onyx-0.0.4.vsix [new file with mode: 0644]
misc/vscode/out/ovmDebug.js
misc/vscode/ovmDebug.ts
misc/vscode/package.json

index ac112c2e0a9f48bbb802a189898b76fd17bd4859..37eecea2276c41339321d2053dd0779018c12a45 100644 (file)
@@ -30,6 +30,7 @@ typedef struct debug_file_info_t {
 } debug_file_info_t;
 
 typedef enum debug_sym_loc_kind_t {
+    debug_sym_loc_unknown  = 0,
     debug_sym_loc_register = 1,
     debug_sym_loc_stack    = 2,
     debug_sym_loc_global   = 3
@@ -292,12 +293,33 @@ typedef struct debug_runtime_value_builder_t {
     debug_func_info_t func_info;
     debug_file_info_t file_info;
     debug_loc_info_t loc_info;
-    debug_sym_info_t sym_info;
+    
+    // "base_" refers to the top symbol. In a layered
+    // query, this information is not outputted, only
+    // used to lookup the values inside of it.
+    debug_sym_loc_kind_t base_loc_kind;
+    u32 base_loc;
+    u32 base_type;
+
+    // "it_" refers to the current symbol to be output.
+    u32 max_index;
+    u32 it_index;
+
+    debug_sym_loc_kind_t it_loc_kind;
+    u32 it_loc;
+    u32 it_type;
+    char *it_name;
+    bool it_has_children; 
+
 } debug_runtime_value_builder_t;
 
 void debug_runtime_value_build_init(debug_runtime_value_builder_t *builder, bh_allocator alloc);
-void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder);
+void debug_runtime_value_build_set_location(debug_runtime_value_builder_t *builder, debug_sym_loc_kind_t loc_kind, u32 loc, u32 type, char *name);
+void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u32 index);
+bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder);
 void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder);
+void debug_runtime_value_build_clear(debug_runtime_value_builder_t *builder);
+void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder);
 
 void *__debug_thread_entry(void *);
 
index 2edde56633ff26b43bded1be869a85cd32f7fa15..a1ebb063e62817513c2ee0d04c1ee0ef9163a4f7 100644 (file)
@@ -26,6 +26,16 @@ static bool lookup_register_in_frame(ovm_state_t *state, ovm_stack_frame_t *fram
     return true;
 }
 
+static bool lookup_stack_pointer(debug_runtime_value_builder_t *builder, u32 *out) {
+    ovm_value_t stack_ptr;
+    if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->func_info.stack_ptr_idx, &stack_ptr)) {
+        return false;
+    }
+
+    *out = stack_ptr.u32;    
+    return true;
+}
+
 static void append_value_from_memory_with_type(debug_runtime_value_builder_t *builder, void *base, u32 type_id) {
     debug_type_info_t *type = &builder->info->types[type_id];
 
@@ -205,18 +215,23 @@ static void append_ovm_value_with_type(debug_runtime_value_builder_t *builder, o
             break;
         }
 
+        case debug_type_kind_structure: {
+            append_ovm_value_with_type(builder, value, type->structure.members[0].type);
+            break;
+        }
+
         default: WRITE("(unknown)"); break;
     }
 }
 
 static void append_value_from_stack(debug_runtime_value_builder_t *builder, u32 offset, u32 type_id) {
-    ovm_value_t stack_ptr;
-    if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->func_info.stack_ptr_idx, &stack_ptr)) {
+    u32 stack_ptr;
+    if (!lookup_stack_pointer(builder, &stack_ptr)) {
         WRITE("(no stack ptr)");
         return;
     }
 
-    void *base = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr.u32 + offset);
+    void *base = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + offset);
 
     append_value_from_memory_with_type(builder, base, type_id);
 }
@@ -253,6 +268,27 @@ static void append_value_from_register(debug_runtime_value_builder_t *builder, u
     append_ovm_value_with_type(builder, value, type_id);
 }
 
+static u32 get_subvalues_for_type(debug_runtime_value_builder_t *builder, u32 type) {
+    debug_type_info_t *t = &builder->info->types[type];
+    switch (t->kind) {
+        case debug_type_kind_primitive: return 0;
+        case debug_type_kind_function: return 0;
+
+        case debug_type_kind_modifier:
+            if (t->modifier.modifier_kind == debug_type_modifier_kind_pointer) return 1;
+            return 0;
+        
+        case debug_type_kind_alias:
+            return get_subvalues_for_type(builder, t->alias.aliased_type);
+
+        case debug_type_kind_structure:
+            return t->structure.member_count;
+        
+        // TEMPORARY this will be the array elements
+        case debug_type_kind_array: return 0;
+    }
+}
+
 
 
 
@@ -260,20 +296,162 @@ void debug_runtime_value_build_init(debug_runtime_value_builder_t *builder, bh_a
     bh_buffer_init(&builder->output, alloc, 1024);
 }
 
-void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder) {
-    bh_buffer_free(&builder->output);
+void debug_runtime_value_build_set_location(debug_runtime_value_builder_t *builder,
+    debug_sym_loc_kind_t loc_kind, u32 loc, u32 type, char *name) {
+    builder->base_loc_kind = loc_kind;
+    builder->base_loc = loc;
+    builder->base_type = type;
+
+    builder->max_index = get_subvalues_for_type(builder, type);
+    builder->it_index = 0;
+    builder->it_name = name;
+    builder->it_loc = loc;
+    builder->it_type = type;
+    builder->it_loc_kind = loc_kind;
+    builder->it_has_children = builder->max_index > 0;
+}
+
+void debug_runtime_value_build_descend(debug_runtime_value_builder_t *builder, u32 index) {
+    builder->it_index = 0;
+
+    debug_type_info_t *type = &builder->info->types[builder->base_type];
+    if (type->kind == debug_type_kind_modifier && type->modifier.modifier_kind == debug_type_modifier_kind_pointer) {
+        if (index > 0) {
+            goto bad_case;
+        }
+
+        builder->base_type = type->modifier.modified_type;
+        type = &builder->info->types[builder->base_type];
+
+        builder->max_index = get_subvalues_for_type(builder, builder->base_type);
+        builder->it_index = 0;
+
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            ovm_value_t value;
+            if (!lookup_register_in_frame(builder->ovm_state, builder->ovm_frame, builder->base_loc, &value)) {
+                goto bad_case;
+            }
+
+            builder->base_loc_kind = debug_sym_loc_global;
+            builder->base_loc = value.u32;
+        }
+
+        else if (builder->base_loc_kind == debug_sym_loc_stack) {
+            u32 stack_ptr;
+            if (!lookup_stack_pointer(builder, &stack_ptr)) {
+                goto bad_case;
+            }    
+
+            u32 *ptr_loc = bh_pointer_add(builder->state->ovm_engine->memory, stack_ptr + builder->base_loc);
+            builder->base_loc = *ptr_loc;
+            builder->base_loc_kind = debug_sym_loc_global;
+        }
+
+        else if (builder->base_loc_kind == debug_sym_loc_global) {
+            u32 *ptr_loc = bh_pointer_add(builder->state->ovm_engine->memory, builder->base_loc);
+            builder->base_loc = *ptr_loc;
+        }
+
+        return;
+    }
+
+    if (type->kind == debug_type_kind_structure) {
+        if (index >= type->structure.member_count) {
+            goto bad_case;
+        }
+
+        debug_type_structure_member_t *mem = &type->structure.members[index];
+        builder->base_type = mem->type;
+        builder->max_index = get_subvalues_for_type(builder, builder->base_type);
+        builder->it_name = mem->name;
+
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            builder->base_loc += index;
+        }
+
+        else if (builder->base_loc_kind == debug_sym_loc_stack || builder->base_loc_kind == debug_sym_loc_global) {
+            builder->base_loc += mem->offset;
+        }
+
+        return;
+    }
+
+  bad_case:
+    builder->base_loc_kind = debug_sym_loc_unknown;
+    return;        
+}
+
+bool debug_runtime_value_build_step(debug_runtime_value_builder_t *builder) {
+    if (builder->it_index >= builder->max_index) return false;
+
+    debug_type_info_t *type = &builder->info->types[builder->base_type];
+
+    if (type->kind == debug_type_kind_modifier && type->modifier.modifier_kind == debug_type_modifier_kind_pointer) {
+        // Double buffering here so if there are multiple
+        // pointer descentions, the names don't get mangled.
+        static char name_buffer[2048];
+        static char tmp_buffer[2048];
+        snprintf(tmp_buffer, 2048, "*%s", builder->it_name);
+        strncpy(name_buffer, tmp_buffer, 2048);
+
+        builder->it_loc_kind = builder->base_loc_kind;
+        builder->it_loc = builder->base_loc;
+        builder->it_name = name_buffer;
+        builder->it_type = type->modifier.modified_type;
+        builder->it_has_children = get_subvalues_for_type(builder, builder->it_type) > 0;
+    }
+
+    if (type->kind == debug_type_kind_structure) {
+        debug_type_structure_member_t *mem = &type->structure.members[builder->it_index];
+        builder->it_name = mem->name;
+        builder->it_has_children = get_subvalues_for_type(builder, mem->type) > 0;
+        builder->it_type = mem->type;
+
+        if (builder->base_loc_kind == debug_sym_loc_register) {
+            builder->it_loc_kind = debug_sym_loc_register;
+            builder->it_loc = builder->base_loc + builder->it_index;
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_stack) {
+            builder->it_loc_kind = debug_sym_loc_stack;
+            builder->it_loc = builder->base_loc + mem->offset;
+        }
+
+        if (builder->base_loc_kind == debug_sym_loc_global) {
+            builder->it_loc_kind = debug_sym_loc_global;
+            builder->it_loc = builder->base_loc + mem->offset;
+        }
+    }
+
+
+    builder->it_index++;
+    return true;
 }
 
 void debug_runtime_value_build_string(debug_runtime_value_builder_t *builder) {
-    if (builder->sym_info.loc_kind == debug_sym_loc_register) {
-        append_value_from_register(builder, builder->sym_info.loc, builder->sym_info.type);
+    if (builder->it_loc_kind == debug_sym_loc_register) {
+        append_value_from_register(builder, builder->it_loc, builder->it_type);
         return;
     }
 
-    if (builder->sym_info.loc_kind == debug_sym_loc_stack) {
-        append_value_from_stack(builder, builder->sym_info.loc, builder->sym_info.type);
+    if (builder->it_loc_kind == debug_sym_loc_stack) {
+        append_value_from_stack(builder, builder->it_loc, builder->it_type);
+        return;
+    }
+
+    if (builder->it_loc_kind == debug_sym_loc_global) {
+        void *base = bh_pointer_add(builder->state->ovm_engine->memory, builder->it_loc);
+        append_value_from_memory_with_type(builder, base, builder->it_type);
         return;
     }
 
     WRITE("(location unknown)");
 }
+
+void debug_runtime_value_build_clear(debug_runtime_value_builder_t *builder) {
+    bh_buffer_clear(&builder->output);
+}
+
+void debug_runtime_value_build_free(debug_runtime_value_builder_t *builder) {
+    bh_buffer_free(&builder->output);
+}
index 5d52312c453f25c14f992552d5cc72e93729ce29..d8e2dcef482ca72c69ec6587a875055ee4e17065 100644 (file)
@@ -344,6 +344,7 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
         case CMD_VARS: {
             i32 stack_frame = parse_int(debug, ctx);
             u32 thread_id   = parse_int(debug, ctx);
+            u32 layers      = parse_int(debug, ctx);
 
             ON_THREAD(thread_id) {
                 bh_arr(ovm_stack_frame_t) frames = (*thread)->ovm_state->stack_frames;
@@ -361,40 +362,90 @@ static void process_command(debug_state_t *debug, struct msg_parse_ctx_t *ctx) {
 
                 send_response_header(debug, msg_id);
 
+                debug_runtime_value_builder_t builder;
+                builder.state = debug;
+                builder.info = debug->info;
+                builder.ovm_state = (*thread)->ovm_state;
+                builder.ovm_frame = frame;
+                builder.func_info = func_info;
+                builder.file_info = file_info;
+                builder.loc_info = loc_info;
+                debug_runtime_value_build_init(&builder, bh_heap_allocator());
+
+                //
+                // The first layer specified is the symbol id to drill into.
+                // Therefore, the first layer is peeled off here before the
+                // following while loop. This makes the assumption that no
+                // symbol will have the id 0xffffffff. This is probably safe
+                // to assume, especially since just one more symbol and this
+                // whole system crashes...
+                u32 sym_id_to_match = 0xffffffff;
+                if (layers > 0) {
+                    sym_id_to_match = parse_int(debug, ctx);
+                    layers--;
+                }
+
                 i32 symbol_scope = loc_info.symbol_scope;
                 while (symbol_scope != -1) {
                     debug_sym_scope_t sym_scope = debug->info->symbol_scopes[symbol_scope];
+                    builder.sym_scope = sym_scope;
 
                     bh_arr_each(u32, sym_id, sym_scope.symbols) {
                         debug_sym_info_t *sym = &debug->info->symbols[*sym_id];
-
-                        send_int(debug, 0);
-                        send_string(debug, sym->name);
-
-                        debug_runtime_value_builder_t builder;
-                        builder.state = debug;
-                        builder.info = debug->info;
-                        builder.ovm_state = (*thread)->ovm_state;
-                        builder.ovm_frame = frame;
-                        builder.sym_scope = sym_scope;
-                        builder.func_info = func_info;
-                        builder.file_info = file_info;
-                        builder.loc_info = loc_info;
-                        builder.sym_info = *sym;
-
-                        debug_runtime_value_build_init(&builder, bh_heap_allocator());
-                        debug_runtime_value_build_string(&builder);
-                        send_bytes(debug, builder.output.data, builder.output.length);
-                        debug_runtime_value_build_free(&builder);
-
-                        debug_type_info_t *type = &debug->info->types[sym->type];
-                        send_string(debug, type->name);
+                        debug_runtime_value_build_set_location(&builder, sym->loc_kind, sym->loc, sym->type, sym->name);
+
+                        //
+                        // If we are drilling to a particular symbol, and this is that symbol,
+                        // we have to do the generation a little differently. We first have to
+                        // pull the other layer queries in, and descend into those layers.
+                        // Then, we loop through each value at that layer and print their values.
+                        if (sym->sym_id == sym_id_to_match && sym_id_to_match != 0xffffffff) {
+                            while (layers--) {
+                                u32 desc = parse_int(debug, ctx);
+                                debug_runtime_value_build_descend(&builder, desc);
+                            }
+
+                            while (debug_runtime_value_build_step(&builder)) {
+                                debug_runtime_value_build_string(&builder);
+                                debug_type_info_t *type = &debug->info->types[builder.it_type];
+
+                                send_int(debug, 0);
+                                send_string(debug, builder.it_name);
+                                send_bytes(debug, builder.output.data, builder.output.length);
+                                send_string(debug, type->name);
+                                send_int(debug, builder.it_index - 1); // CLEANUP This should be 0 indexed, but because this is after the while loop condition, it is 1 indexed.
+                                send_bool(debug, builder.it_has_children);
+
+                                debug_runtime_value_build_clear(&builder);
+                            }
+                            
+                            // This is important, as when doing a layered query, only one symbol
+                            // should be considered, and once found, should immediate stop.
+                            goto syms_done;
+
+                        } else if (sym_id_to_match == 0xffffffff) {
+                            // Otherwise, we simply print the value of the symbol as is.
+                            debug_type_info_t *type = &debug->info->types[sym->type];
+
+                            debug_runtime_value_build_string(&builder);
+
+                            send_int(debug, 0);
+                            send_string(debug, sym->name);
+                            send_bytes(debug, builder.output.data, builder.output.length);
+                            send_string(debug, type->name);
+                            send_int(debug, sym->sym_id);
+                            send_bool(debug, builder.it_has_children);
+
+                            debug_runtime_value_build_clear(&builder);
+                        }
                     }
 
                     symbol_scope = sym_scope.parent;
                 }
                 
+              syms_done:
                 send_int(debug, 1);
+                debug_runtime_value_build_free(&builder);
                 return;
             }
 
diff --git a/misc/vscode/onyx-0.0.4.vsix b/misc/vscode/onyx-0.0.4.vsix
new file mode 100644 (file)
index 0000000..6f7437f
Binary files /dev/null and b/misc/vscode/onyx-0.0.4.vsix differ
index 5fdde9ed53f76a5cda50df25b9487ff022be3a9f..6a3f2d7c0558ba58a854bf583b9054ce150e95a4 100644 (file)
@@ -137,6 +137,8 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
     stackTraceRequest(response, args, request) {
         return __awaiter(this, void 0, void 0, function* () {
             let frames = yield this.debugger.trace(args.threadId);
+            this._frameReferences.reset();
+            this._variableReferences.reset();
             response.body = {
                 stackFrames: frames.map((f, i) => {
                     let source = new debugadapter_1.Source(this.fileNameToShortName(f.filename), this.convertDebuggerPathToClient(f.filename), undefined, undefined, "ovm-debug-src");
@@ -166,7 +168,7 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
     scopesRequest(response, args, request) {
         let frameId = args.frameId;
         let frameRef = this._frameReferences.get(frameId);
-        let varRef = this._variableReferences.create(frameRef);
+        let varRef = this._variableReferences.create(Object.assign(Object.assign({}, frameRef), { variableChain: [] }));
         response.body = {
             scopes: [
                 new debugadapter_1.Scope("Locals", varRef, false),
@@ -176,11 +178,14 @@ class OVMDebugSession extends debugadapter_1.LoggingDebugSession {
     }
     variablesRequest(response, args, request) {
         return __awaiter(this, void 0, void 0, function* () {
-            const frameRef = this._variableReferences.get(args.variablesReference, { frameIndex: 0, threadId: 0 });
-            let vs = (yield this.debugger.variables(frameRef.frameIndex, frameRef.threadId))
+            const frameRef = this._variableReferences.get(args.variablesReference, { frameIndex: 0, threadId: 0, variableChain: [] });
+            let vs = (yield this.debugger.variables(frameRef.frameIndex, frameRef.threadId, frameRef.variableChain))
                 .map(v => {
                 let nv = new debugadapter_1.Variable(v.name, v.value);
                 nv.type = v.type;
+                if (v.hasChildren) {
+                    nv.variablesReference = this._variableReferences.create(Object.assign(Object.assign({}, frameRef), { variableChain: frameRef.variableChain.concat([v.symId]) }));
+                }
                 return nv;
             });
             response.body = { variables: vs };
@@ -406,16 +411,20 @@ class OVMDebugger extends EventEmitter {
         this.pending_responses[cmd_id] = OVMCommand.THREADS;
         return this.preparePromise(cmd_id);
     }
-    variables(frame_index, thread_id) {
+    variables(frame_index, thread_id, descention) {
         if (this.client == null)
             return Promise.resolve([]);
-        let data = new ArrayBuffer(16);
+        let data = new ArrayBuffer(20 + 4 * descention.length);
         let view = new DataView(data);
         let cmd_id = this.next_command_id;
         view.setUint32(0, cmd_id, true);
         view.setUint32(4, OVMCommand.VARS, true);
         view.setUint32(8, frame_index, true);
         view.setUint32(12, thread_id, true);
+        view.setUint32(16, descention.length, true);
+        for (let i = 0; i < descention.length; i++) {
+            view.setUint32(20 + i * 4, descention[i], true);
+        }
         this.client.write(new Uint8Array(data));
         this.pending_responses[cmd_id] = OVMCommand.VARS;
         return this.preparePromise(cmd_id);
@@ -515,7 +524,9 @@ class OVMDebugger extends EventEmitter {
                     let name = parser.parseString();
                     let value = parser.parseString();
                     let type = parser.parseString();
-                    result.push({ name, value, type });
+                    let symId = parser.parseUint32();
+                    let hasChildren = parser.parseBool();
+                    result.push({ name, value, type, symId, hasChildren });
                 }
                 this.resolvePromise(msg_id, result);
                 break;
@@ -581,7 +592,7 @@ class DataParser {
     }
     parseBool() {
         if (this.offset >= this.data.length)
-            return 0;
+            return false;
         this.offset += 1;
         return this.view.getUint8(this.offset - 1) != 0;
     }
index f646927f8f1fb0e35a9dac9c8f48c2ffbf9eebcd..0fa1c54f40bab9ae676e1f6d8185ae07689d4788 100644 (file)
@@ -32,6 +32,12 @@ interface IFrameReference {
        threadId: number;
 }
 
+interface IVariableReference {
+       frameIndex: number;
+       threadId: number;
+       variableChain: number[];
+}
+
 export class OVMDebugSession extends LoggingDebugSession {
 
        private debugger: OVMDebugger;
@@ -43,7 +49,7 @@ export class OVMDebugSession extends LoggingDebugSession {
 
        private _loadedSources: Map<string, Source>;
 
-       private _variableReferences = new Handles<IFrameReference>();
+       private _variableReferences = new Handles<IVariableReference>();
        private _frameReferences = new Handles<IFrameReference>();
 
     public constructor() {
@@ -197,6 +203,9 @@ export class OVMDebugSession extends LoggingDebugSession {
        protected async stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments, request?: DebugProtocol.Request): Promise<void> {
                let frames = await this.debugger.trace(args.threadId);
 
+               this._frameReferences.reset();
+               this._variableReferences.reset();
+
                response.body = {
                        stackFrames: frames.map((f, i) => {
                                let source = new Source(
@@ -236,7 +245,10 @@ export class OVMDebugSession extends LoggingDebugSession {
                let frameId = args.frameId;
 
                let frameRef = this._frameReferences.get(frameId);
-               let varRef   = this._variableReferences.create(frameRef);
+               let varRef   = this._variableReferences.create({
+                       ...frameRef,
+                       variableChain: []
+               });
 
                response.body = {
                        scopes: [
@@ -247,11 +259,19 @@ export class OVMDebugSession extends LoggingDebugSession {
        }
 
        protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments, request?: DebugProtocol.Request): Promise<void> {
-               const frameRef = this._variableReferences.get(args.variablesReference, {frameIndex: 0, threadId: 0});
-               let vs: Variable[] = (await this.debugger.variables(frameRef.frameIndex, frameRef.threadId))
+               const frameRef = this._variableReferences.get(args.variablesReference, {frameIndex:0, threadId:0, variableChain:[]});
+
+               let vs: Variable[] = (await this.debugger.variables(frameRef.frameIndex, frameRef.threadId, frameRef.variableChain))
                        .map(v => {
                                let nv = new Variable(v.name, v.value) as DebugProtocol.Variable;
                                nv.type = v.type;
+                               if (v.hasChildren) {
+                                       nv.variablesReference = this._variableReferences.create({
+                                               ...frameRef,
+                                               variableChain: frameRef.variableChain.concat([v.symId]),
+                                       });
+                               }
+
                                return nv;
                        });
 
@@ -363,6 +383,8 @@ interface IVariableInfo {
        name: string;
        value: string;
        type: string;
+       symId: number;
+       hasChildren: boolean;
 }
 
 enum OVMCommand {
@@ -556,10 +578,10 @@ class OVMDebugger extends EventEmitter {
                return this.preparePromise(cmd_id);
        }
 
-       variables(frame_index: number, thread_id: number): Promise<IVariableInfo[]> {
+       variables(frame_index: number, thread_id: number, descention: number[]): Promise<IVariableInfo[]> {
                if (this.client == null) return Promise.resolve([]);
 
-        let data = new ArrayBuffer(16);
+        let data = new ArrayBuffer(20 + 4 * descention.length);
         let view = new DataView(data);
 
         let cmd_id = this.next_command_id;
@@ -568,6 +590,11 @@ class OVMDebugger extends EventEmitter {
         view.setUint32(4, OVMCommand.VARS, true);
         view.setUint32(8, frame_index, true);
         view.setUint32(12, thread_id, true);
+               view.setUint32(16, descention.length, true);
+
+               for (let i=0; i<descention.length; i++) {
+                       view.setUint32(20 + i * 4, descention[i], true);
+               }
 
         this.client.write(new Uint8Array(data));
 
@@ -693,7 +720,9 @@ class OVMDebugger extends EventEmitter {
                                        let name  = parser.parseString();
                                        let value = parser.parseString();
                                        let type  = parser.parseString();
-                                       result.push({name, value, type});
+                                       let symId    = parser.parseUint32();
+                                       let hasChildren = parser.parseBool();
+                                       result.push({name, value, type, symId, hasChildren});
                                }
 
                                this.resolvePromise(msg_id, result);
@@ -776,7 +805,7 @@ class DataParser {
     }
 
     parseBool() {
-               if (this.offset >= this.data.length) return 0;
+               if (this.offset >= this.data.length) return false;
 
         this.offset += 1;
         return this.view.getUint8(this.offset - 1) != 0;
index 7bbd3ff0f2cffe782dd465a7d12dc288a16a06af..83d5e27658b1c673701d5037906e5fc08bcca2f0 100644 (file)
@@ -2,7 +2,7 @@
     "name": "onyx",
     "displayName": "Onyx",
     "description": "Onyx syntax highlighting.",
-    "version": "0.0.3",
+    "version": "0.0.4",
     "publisher": "brendanfh",
     "license": "BSD-2-Clause",
     "engines": {