Skip to content

Commit 0cba670

Browse files
author
kr-2003
committed
debugging breakpoint hits
1 parent 90df737 commit 0cba670

File tree

3 files changed

+277
-21
lines changed

3 files changed

+277
-21
lines changed

include/xeus-cpp/xdebugger.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ namespace xcpp
5151
nl::json configuration_done_request(const nl::json& message);
5252
nl::json set_breakpoints_request(const nl::json& message);
5353
nl::json dump_cell_request(const nl::json& message);
54+
nl::json rich_inspect_variables_request(const nl::json& message);
55+
nl::json copy_to_globals_request(const nl::json& message);
5456

5557
nl::json variables_request_impl(const nl::json& message) override;
5658

@@ -80,6 +82,8 @@ namespace xcpp
8082

8183
std::unordered_map<std::string, std::vector<std::string>> m_hash_to_sequential;
8284
std::unordered_map<std::string, std::string> m_sequential_to_hash;
85+
86+
bool m_copy_to_globals_available;
8387
};
8488

8589
XEUS_CPP_API

src/xdebugger.cpp

Lines changed: 257 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,24 @@ namespace xcpp
5151
, m_lldb_host("127.0.0.1")
5252
, m_lldb_port("")
5353
, m_debugger_config(debugger_config)
54-
, m_is_running(false)
5554
{
5655
// Register request handlers
5756
register_request_handler(
5857
"inspectVariables",
5958
std::bind(&debugger::inspect_variables_request, this, _1),
6059
false
6160
);
62-
register_request_handler("stackTrace", std::bind(&debugger::stack_trace_request, this, _1), false);
6361
register_request_handler("attach", std::bind(&debugger::attach_request, this, _1), true);
6462
register_request_handler(
6563
"configurationDone",
6664
std::bind(&debugger::configuration_done_request, this, _1),
6765
true
6866
);
67+
register_request_handler("richInspectVariables", std::bind(&debugger::rich_inspect_variables_request, this, _1), true);
6968
register_request_handler("setBreakpoints", std::bind(&debugger::set_breakpoints_request, this, _1), true);
7069
register_request_handler("dumpCell", std::bind(&debugger::dump_cell_request, this, _1), true);
70+
register_request_handler("copyToGlobals", std::bind(&debugger::copy_to_globals_request, this, _1), true);
71+
register_request_handler("stackTrace", std::bind(&debugger::stack_trace_request, this, _1), true);
7172

7273
m_interpreter = reinterpret_cast<xcpp::interpreter*>(
7374
debugger_config["interpreter_ptr"].get<std::uintptr_t>()
@@ -98,7 +99,12 @@ namespace xcpp
9899
log << m_debugger_config.dump(4) << '\n';
99100
}
100101

101-
std::vector<std::string> lldb_args = {"lldb-dap", "--port", m_lldb_port};
102+
// std::vector<std::string> lldb_args = {"/Users/abhinavkumar/Desktop/Coding/CERN_HSF_COMPILER_RESEARCH/llvm-project-lldb/build/bin/lldb-dap", "--connection", "listen://localhost:" + m_lldb_port};
103+
std::vector<std::string> lldb_args = {
104+
"lldb-dap",
105+
"--port",
106+
m_lldb_port
107+
};
102108

103109
std::string log_dir = xeus::get_temp_directory_path() + "/xcpp_debug_logs_"
104110
+ std::to_string(xeus::get_current_pid());
@@ -148,6 +154,7 @@ namespace xcpp
148154
return false;
149155
}
150156
m_is_running = true;
157+
m_copy_to_globals_available = true;
151158
return true;
152159
}
153160
else
@@ -173,7 +180,7 @@ namespace xcpp
173180

174181
std::string lldb_endpoint = "tcp://" + m_lldb_host + ":" + m_lldb_port;
175182
std::thread client(
176-
&xdebuglldb_client::start_debugger,
183+
&xdap_tcp_client::start_debugger,
177184
p_debuglldb_client,
178185
lldb_endpoint,
179186
publisher_end_point,
@@ -198,15 +205,21 @@ namespace xcpp
198205
{"type", "request"},
199206
{"command", "attach"},
200207
{"arguments",
201-
{{"pid", jit_process_pid}, {"initCommands", {"settings set plugin.jit-loader.gdb.enable on"}}}}
208+
{
209+
{"pid", jit_process_pid},
210+
{"stopOnEntry", true},
211+
{"initCommands", {"settings set plugin.jit-loader.gdb.enable on"}}
212+
}
213+
}
202214
};
215+
log_debug("[debugger::attach_request] Attach request sent:\n" + attach_request.dump(4));
203216
nl::json reply = forward_message(attach_request);
204217
return reply;
205218
}
206219

207220
nl::json debugger::inspect_variables_request(const nl::json& message)
208221
{
209-
log_debug("[debugger] Inspect variable not implemented.");
222+
log_debug("[debugger::inspect_variables_request] Inspect variable not implemented.");
210223
nl::json inspect_request = {
211224
{"seq", message["seq"]},
212225
{"type", "request"},
@@ -227,37 +240,99 @@ namespace xcpp
227240
m_breakpoint_list.insert(std::make_pair(std::move(source), std::move(bp_list)));
228241
nl::json mod_message = message;
229242
mod_message["arguments"]["source"]["path"] = sequential_source;
230-
log_debug("Set breakpoints request received:\n" + mod_message.dump(4));
243+
log_debug("[debugger::set_breakpoints_request] Set breakpoints request sent:\n" + mod_message.dump(4));
231244
nl::json breakpoint_reply = forward_message(mod_message);
232-
log_debug("Set breakpoints reply sent:\n" + breakpoint_reply.dump(4));
245+
if (breakpoint_reply.contains("body") && breakpoint_reply["body"].contains("breakpoints"))
246+
{
247+
for (auto& bp : breakpoint_reply["body"]["breakpoints"])
248+
{
249+
if (bp.contains("source") && bp["source"].contains("path"))
250+
{
251+
std::string seq_path = bp["source"]["path"].get<std::string>();
252+
if (m_sequential_to_hash.find(seq_path) != m_sequential_to_hash.end())
253+
{
254+
bp["source"]["path"] = m_sequential_to_hash[seq_path];
255+
}
256+
}
257+
}
258+
}
259+
log_debug("[debugger::set_breakpoints_request] Set breakpoints reply received:\n" + breakpoint_reply.dump(4));
233260
return breakpoint_reply;
234261
}
235262

236-
nl::json debugger::stack_trace_request(const nl::json& message)
263+
// nl::json debugger::stack_trace_request(const nl::json& message)
264+
// {
265+
// log_debug("Stack trace request received:\n" + message.dump(4));
266+
// nl::json reply = {
267+
// {"type", "response"},
268+
// {"request_seq", message["seq"]},
269+
// {"success", false},
270+
// {"command", message["command"]},
271+
// {"message", "stackTrace not implemented"},
272+
// {"body", {{"stackFrames", {}}}}
273+
// };
274+
// return reply;
275+
// }
276+
277+
nl::json debugger::copy_to_globals_request(const nl::json& message)
237278
{
238-
log_debug("Stack trace request received:\n" + message.dump(4));
239-
nl::json reply = {
240-
{"type", "response"},
241-
{"request_seq", message["seq"]},
242-
{"success", false},
243-
{"command", message["command"]},
244-
{"message", "stackTrace not implemented"},
245-
{"body", {{"stackFrames", {}}}}
279+
// This request cannot be processed if the version of debugpy is lower than 1.6.5.
280+
log_debug("[debugger::copy_to_globals_request] Copy to globals request received:\n" + message.dump(4));
281+
if (!m_copy_to_globals_available)
282+
{
283+
nl::json reply = {
284+
{"type", "response"},
285+
{"request_seq", message["seq"]},
286+
{"success", false},
287+
{"command", message["command"]},
288+
{"body", "The debugpy version must be greater than or equal 1.6.5 to allow copying a variable to the global scope."}
289+
};
290+
return reply;
291+
}
292+
293+
std::string src_var_name = message["arguments"]["srcVariableName"].get<std::string>();
294+
std::string dst_var_name = message["arguments"]["dstVariableName"].get<std::string>();
295+
int src_frame_id = message["arguments"]["srcFrameId"].get<int>();
296+
297+
// It basically runs a setExpression in the globals dictionary of Python.
298+
int seq = message["seq"].get<int>();
299+
std::string expression = "globals()['" + dst_var_name + "']";
300+
nl::json request = {
301+
{"type", "request"},
302+
{"command", "setExpression"},
303+
{"seq", seq+1},
304+
{"arguments", {
305+
{"expression", expression},
306+
{"value", src_var_name},
307+
{"frameId", src_frame_id}
308+
}}
246309
};
247-
return reply;
310+
return forward_message(request);
248311
}
249312

313+
250314
nl::json debugger::configuration_done_request(const nl::json& message)
251315
{
252-
log_debug("Configuration done request received:\n" + message.dump(4));
316+
log_debug("[debugger::configuration_done_request] Configuration done request received:\n" + message.dump(4));
253317
nl::json reply = forward_message(message);
254-
log_debug("Configuration done reply sent:\n" + reply.dump(4));
318+
log_debug("[debugger::configuration_done_request] Configuration done reply sent:\n" + reply.dump(4));
319+
// send continue reauest on thread that is stopped
320+
auto stopped_threads = base_type::get_stopped_threads();
321+
nl::json continue_request = {
322+
{"type", "request"},
323+
{"command", "continue"},
324+
{"seq", message["seq"].get<int>() + 1},
325+
{"arguments", {{"threadId", *stopped_threads.begin()}}}
326+
};
327+
log_debug("[debugger::configuration_done_request] Sending continue request:\n" + continue_request.dump(4));
328+
nl::json continue_reply = forward_message(continue_request);
329+
log_debug("[debugger::configuration_done_request] Continue reply received:\n" + continue_reply.dump(4));
255330
return reply;
256331
}
257332

258333
nl::json debugger::variables_request_impl(const nl::json& message)
259334
{
260-
log_debug("Variables request received:\n" + message.dump(4));
335+
log_debug("[debugger::variables_request_impl] Variables request received:\n" + message.dump(4));
261336
nl::json reply = {
262337
{"type", "response"},
263338
{"request_seq", message["seq"]},
@@ -269,6 +344,165 @@ namespace xcpp
269344
return reply;
270345
}
271346

347+
nl::json debugger::rich_inspect_variables_request(const nl::json& message)
348+
{
349+
log_debug("[debugger::rich_inspect_variables_request] Rich inspect variables request received:\n" + message.dump(4));
350+
return {};
351+
// nl::json reply = {
352+
// {"type", "response"},
353+
// {"request_seq", message["seq"]},
354+
// {"success", false},
355+
// {"command", message["command"]}
356+
// };
357+
358+
// std::string var_name = message["arguments"]["variableName"].get<std::string>();
359+
// py::str py_var_name = py::str(var_name);
360+
// bool valid_name = PyUnicode_IsIdentifier(py_var_name.ptr()) == 1;
361+
// if (!valid_name)
362+
// {
363+
// reply["body"] = {
364+
// {"data", {}},
365+
// {"metadata", {}}
366+
// };
367+
// if (var_name == "special variables" || var_name == "function variables")
368+
// {
369+
// reply["success"] = true;
370+
// }
371+
// return reply;
372+
// }
373+
374+
// std::string var_repr_data = var_name + "_repr_data";
375+
// std::string var_repr_metadata = var_name + "_repr_metada";
376+
377+
// if (base_type::get_stopped_threads().empty())
378+
// {
379+
// // The code did not hit a breakpoint, we use the interpreter
380+
// // to get the rich representation of the variable
381+
// std::string code = "from IPython import get_ipython;";
382+
// code += var_repr_data + ',' + var_repr_metadata + "= get_ipython().display_formatter.format(" + var_name + ")";
383+
// py::gil_scoped_acquire acquire;
384+
// exec(py::str(code));
385+
// }
386+
// else
387+
// {
388+
// // The code has stopped on a breakpoint, we use the setExpression request
389+
// // to get the rich representation of the variable
390+
// std::string code = "get_ipython().display_formatter.format(" + var_name + ")";
391+
// int frame_id = message["arguments"]["frameId"].get<int>();
392+
// int seq = message["seq"].get<int>();
393+
// nl::json request = {
394+
// {"type", "request"},
395+
// {"command", "evaluate"},
396+
// {"seq", seq+1},
397+
// {"arguments", {
398+
// {"expression", code},
399+
// {"frameId", frame_id},
400+
// {"context", "clipboard"}
401+
// }}
402+
// };
403+
// nl::json request_reply = forward_message(request);
404+
// std::string result = request_reply["body"]["result"];
405+
406+
// py::gil_scoped_acquire acquire;
407+
// std::string exec_code = var_repr_data + ',' + var_repr_metadata + "= eval(str(" + result + "))";
408+
// exec(py::str(exec_code));
409+
// }
410+
411+
// py::gil_scoped_acquire acquire;
412+
// py::object variables = py::globals();
413+
// py::object repr_data = variables[py::str(var_repr_data)];
414+
// py::object repr_metadata = variables[py::str(var_repr_metadata)];
415+
// nl::json body = {
416+
// {"data", {}},
417+
// {"metadata", {}}
418+
// };
419+
// for (const py::handle& key : repr_data)
420+
// {
421+
// std::string data_key = py::str(key);
422+
// body["data"][data_key] = repr_data[key];
423+
// if (repr_metadata.contains(key))
424+
// {
425+
// body["metadata"][data_key] = repr_metadata[key];
426+
// }
427+
// }
428+
// PyDict_DelItem(variables.ptr(), py::str(var_repr_data).ptr());
429+
// PyDict_DelItem(variables.ptr(), py::str(var_repr_metadata).ptr());
430+
// reply["body"] = body;
431+
// reply["success"] = true;
432+
// return reply;
433+
}
434+
435+
nl::json debugger::stack_trace_request(const nl::json& message)
436+
{
437+
int requested_thread_id = message["arguments"]["threadId"];
438+
439+
auto stopped_threads = base_type::get_stopped_threads();
440+
441+
if (stopped_threads.empty()) {
442+
nl::json error_reply = {
443+
{"command", "stackTrace"},
444+
{"request_seq", message["seq"]},
445+
{"seq", message["seq"]},
446+
{"success", false},
447+
{"message", "No threads are currently stopped"},
448+
{"type", "response"}
449+
};
450+
return error_reply;
451+
}
452+
453+
int actual_thread_id;
454+
nl::json modified_message = message;
455+
456+
if (requested_thread_id == 1 && !stopped_threads.empty()) {
457+
actual_thread_id = *stopped_threads.begin();
458+
modified_message["arguments"]["threadId"] = actual_thread_id;
459+
std::clog << "XDEBUGGER: Mapping client thread 1 to actual thread " << actual_thread_id << std::endl;
460+
}
461+
else if (stopped_threads.find(requested_thread_id) != stopped_threads.end()) {
462+
actual_thread_id = requested_thread_id;
463+
}
464+
else {
465+
actual_thread_id = *stopped_threads.begin();
466+
modified_message["arguments"]["threadId"] = actual_thread_id;
467+
std::clog << "XDEBUGGER: Thread " << requested_thread_id
468+
<< " not found in stopped threads, using " << actual_thread_id << std::endl;
469+
}
470+
471+
for(auto x : stopped_threads)
472+
{
473+
log_debug("Stopped thread ID: " + std::to_string(x));
474+
}
475+
476+
log_debug("[debugger::stack_trace_request]:\n" + modified_message.dump(4));
477+
478+
nl::json reply = forward_message(modified_message);
479+
480+
if (!reply.contains("body") || !reply["body"].contains("stackFrames")) {
481+
return reply;
482+
}
483+
484+
auto& stack_frames = reply["body"]["stackFrames"];
485+
for (auto it = stack_frames.begin(); it != stack_frames.end(); ++it) {
486+
if (it->contains("source") && (*it)["source"].contains("path") &&
487+
(*it)["source"]["path"] == "<string>") {
488+
stack_frames.erase(it);
489+
break;
490+
}
491+
}
492+
493+
#ifdef WIN32
494+
for (auto& frame : stack_frames) {
495+
if (frame.contains("source") && frame["source"].contains("path")) {
496+
std::string path = frame["source"]["path"];
497+
std::replace(path.begin(), path.end(), '\\', '/');
498+
frame["source"]["path"] = path;
499+
}
500+
}
501+
#endif
502+
503+
return reply;
504+
}
505+
272506
void debugger::stop()
273507
{
274508
std::string controller_end_point = xeus::get_controller_end_point("debugger");
@@ -279,6 +513,7 @@ namespace xcpp
279513
xeus::xdebugger_info debugger::get_debugger_info() const
280514
{
281515
// Placeholder debugger info
516+
log_debug("[debugger::get_debugger_info] Returning debugger info");
282517
return xeus::xdebugger_info(
283518
xeus::get_tmp_hash_seed(),
284519
get_tmp_prefix(),
@@ -291,6 +526,7 @@ namespace xcpp
291526

292527
nl::json debugger::dump_cell_request(const nl::json& message)
293528
{
529+
log_debug("[debugger::dump_cell_request] Dump cell request received:\n" + message.dump(4));
294530
std::string code;
295531
try
296532
{

0 commit comments

Comments
 (0)