AstTyped *result = (AstTyped *) polymorphic_proc_lookup(pp, PPLM_By_Function_Type, ft->partial_function_type, pp->token);
// If the result is not ready (NULL, yield flag, no type, or `type_auto_return` as return type), wait.
- if (result
- && result->type == NULL
- || (result->type->kind == Type_Kind_Function && result->type->Function.return_type == &type_auto_return)) {
+ if (result && (
+ result->type == NULL
+ || (result->type->kind == Type_Kind_Function && result->type->Function.return_type == &type_auto_return)))
+ {
doing_nested_polymorph_lookup = 1;
result = NULL;
}
bool debug_info_lookup_file(debug_info_t *info, u32 file_id, debug_file_info_t *out);
bool debug_info_lookup_file_by_name(debug_info_t *info, char *name, debug_file_info_t *out);
bool debug_info_lookup_func(debug_info_t *info, u32 func_id, debug_func_info_t *out);
+i32 debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32 line);
//
// This builder is used in conjunction with code builder to output
debug_exec_state_t state;
struct ovm_state_t *ovm_state;
+ // This flag signals if the thread has done
+ // ANY execution. When a thread first starts
+ // the thread signals a `paused` event, with
+ // an `entry` reason. When the thread pauses
+ // later on, it should be a `step` reason.
+ b32 started;
+
i32 run_count;
sem_t wait_semaphore;
i32 extra_frames_since_last_pause;
debug_pause_reason_t pause_reason;
- bh_arr(debug_breakpoint_t) breakpoints;
u32 last_breakpoint_hit;
u32 state_change_write_fd;
u32 next_thread_id;
u32 next_breakpoint_id;
+ bh_arr(debug_breakpoint_t) breakpoints;
pthread_t debug_thread;
bool debug_thread_running;
new_thread->run_count = 0; // Start threads in stopped state.
sem_init(&new_thread->wait_semaphore, 0, 0);
- new_thread->breakpoints = NULL;
- bh_arr_new(debug->alloc, new_thread->breakpoints, 8);
-
u32 id = debug->next_thread_id++;
new_thread->id = id;
return true;
}
+i32 debug_info_lookup_instr_by_file_line(debug_info_t *info, char *filename, u32 line) {
+ if (!info || !info->has_debug_info) return 0;
+
+ debug_file_info_t file_info;
+ bool file_found = debug_info_lookup_file_by_name(info, filename, &file_info);
+ if (!file_found) {
+ return -1;
+ }
+
+ if (line > file_info.line_count) {
+ return -1;
+ }
+
+ u32 instr;
+ while ((instr = info->line_to_instruction[file_info.line_buffer_offset + line]) == 0) {
+ line += 1;
+
+ if (line > file_info.line_count) {
+ return -1;
+ }
+ }
+
+ return instr;
+}
+
//
// For now, this is going to compare the strings exactly. In the future, it might be a good
// to do a levenschtein distance or something, so the full path isn't needed.
char *filename = parse_string(debug, ctx);
unsigned int line = parse_int(debug, ctx);
- //
- // TODO: This translation logic will have to be abstracted
- debug_file_info_t file_info;
- bool file_found = debug_info_lookup_file_by_name(debug->info, filename, &file_info);
- if (!file_found) {
- goto brk_send_error;
- }
-
- if (line > file_info.line_count) {
- goto brk_send_error;
- }
-
- u32 instr;
- while ((instr = debug->info->line_to_instruction[file_info.line_buffer_offset + line]) == 0) {
- line += 1;
-
- if (line > file_info.line_count) {
- goto brk_send_error;
- }
- }
+ i32 instr = debug_info_lookup_instr_by_file_line(debug->info, filename, line);
+ if (instr < 0) goto brk_send_error;
printf("[INFO ] Setting breakpoint at %s:%d (%x)\n", filename, line, instr);
+
+ debug_file_info_t file_info;
+ debug_info_lookup_file_by_name(debug->info, filename, &file_info);
debug_breakpoint_t bp;
bp.id = debug->next_breakpoint_id++;
bp.instr = instr;
bp.file_id = file_info.file_id;
bp.line = line;
- bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
- bh_arr_push((*thread)->breakpoints, bp);
- }
+ bh_arr_push(debug->breakpoints, bp);
send_response_header(debug, msg_id);
send_bool(debug, true);
- send_int(debug, bp.id); // TODO: This should be a unique breakpoint ID
+ send_int(debug, bp.id);
send_int(debug, line);
break;
goto clr_brk_send_error;
}
- bh_arr_each(debug_thread_state_t *, thread, debug->threads) {
- bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) {
- if (bp->file_id == file_info.file_id) {
- // This is kind of hacky but it does successfully delete
- // a single element from the array and move the iterator.
- bh_arr_fastdelete((*thread)->breakpoints, bp - (*thread)->breakpoints);
- bp--;
- }
+ bh_arr_each(debug_breakpoint_t, bp, debug->breakpoints) {
+ if (bp->file_id == file_info.file_id) {
+ // This is kind of hacky but it does successfully delete
+ // a single element from the array and move the iterator.
+ bh_arr_fastdelete(debug->breakpoints, bp - debug->breakpoints);
+ bp--;
}
}
(*thread)->state = debug_state_paused;
i32 instr = -1, bp_id = (*thread)->last_breakpoint_hit;
- bh_arr_each(debug_breakpoint_t, bp, (*thread)->breakpoints) {
+ bh_arr_each(debug_breakpoint_t, bp, debug->breakpoints) {
if (bp->id == bp_id) {
instr = bp->instr;
break;
if (state->debug) {
if (state->debug->run_count == 0) {
state->debug->state = debug_state_pausing;
- state->debug->pause_reason = debug_pause_entry; // This is not always due to entry...
+
+ if (state->debug->started) {
+ state->debug->pause_reason = debug_pause_step;
+ } else {
+ state->debug->pause_reason = debug_pause_entry;
+ state->debug->started = 1;
+ }
+
goto should_wait;
}
}
}
- bh_arr_each(debug_breakpoint_t, bp, state->debug->breakpoints) {
+ ovm_assert(engine->debug);
+ bh_arr_each(debug_breakpoint_t, bp, engine->debug->breakpoints) {
if (bp->instr == (u32) state->pc) {
state->debug->state = debug_state_hit_breakpoint;
state->debug->last_breakpoint_hit = bp->id;
this.sendEvent(new debugadapter_1.StoppedEvent("breakpoint", ev.threadId));
});
this.debugger.on("paused", (ev) => {
+ if (ev.reason == "entry") {
+ this.sendEvent(new debugadapter_1.ThreadEvent("started", ev.thread_id));
+ if (!this.stopOnEntry) {
+ this.debugger.resume(ev.thread_id);
+ return;
+ }
+ }
this.sendEvent(new debugadapter_1.StoppedEvent(ev.reason, ev.threadId));
});
this.debugger.on("terminated", () => {
});
}
attachRequest(response, args, request) {
+ var _a;
return __awaiter(this, void 0, void 0, function* () {
yield this._configurationDone.wait(1000);
yield this.debugger.connect(args.socketPath);
this._clientConnected = true;
this._clientConnectedNotifier.notify();
+ this.stopOnEntry = (_a = args.stopOnEntry) !== null && _a !== void 0 ? _a : false;
this.sendResponse(response);
- this.sendEvent(new debugadapter_1.ThreadEvent("started", 1));
- if (!args.stopOnEntry) {
- this.debugger.resume();
- }
});
}
pauseRequest(response, args, request) {
private _variableReferences = new Handles<IVariableReference>();
private _frameReferences = new Handles<IFrameReference>();
+ private stopOnEntry: boolean;
+
public constructor() {
super("ovm-debug-log.txt");
});
this.debugger.on("paused", (ev) => {
+ if (ev.reason == "entry") {
+ this.sendEvent(new ThreadEvent("started", ev.thread_id));
+
+ if (!this.stopOnEntry) {
+ this.debugger.resume(ev.thread_id);
+ return;
+ }
+ }
+
this.sendEvent(new StoppedEvent(ev.reason, ev.threadId));
});
this._clientConnected = true;
this._clientConnectedNotifier.notify();
- this.sendResponse(response);
- this.sendEvent(new ThreadEvent("started", 1));
+ this.stopOnEntry = args.stopOnEntry ?? false;
- if (!args.stopOnEntry) {
- this.debugger.resume();
- }
+ this.sendResponse(response);
+ // this.sendEvent(new ThreadEvent("started", 1));
}
protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments, request?: DebugProtocol.Request): void {