|
43 | 43 | #include "lldb/Host/common/NativeRegisterContext.h"
|
44 | 44 | #include "lldb/Host/common/NativeProcessProtocol.h"
|
45 | 45 | #include "lldb/Host/common/NativeThreadProtocol.h"
|
| 46 | +#include "lldb/Utility/JSON.h" |
46 | 47 |
|
47 | 48 | // Project includes
|
48 | 49 | #include "Utility/StringExtractorGDBRemote.h"
|
@@ -161,6 +162,8 @@ GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers()
|
161 | 162 | &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo);
|
162 | 163 | RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo,
|
163 | 164 | &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo);
|
| 165 | + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, |
| 166 | + &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); |
164 | 167 | RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
|
165 | 168 | &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
|
166 | 169 | RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read,
|
@@ -455,6 +458,83 @@ WriteRegisterValueInHexFixedWidth (StreamString &response,
|
455 | 458 | }
|
456 | 459 | }
|
457 | 460 |
|
| 461 | +static JSONObject::SP |
| 462 | +GetRegistersAsJSON(NativeThreadProtocol &thread) |
| 463 | +{ |
| 464 | + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); |
| 465 | + |
| 466 | + NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext (); |
| 467 | + if (! reg_ctx_sp) |
| 468 | + return nullptr; |
| 469 | + |
| 470 | + JSONObject::SP register_object_sp = std::make_shared<JSONObject>(); |
| 471 | + // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. |
| 472 | + const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); |
| 473 | + if (! reg_set_p) |
| 474 | + return nullptr; |
| 475 | + |
| 476 | + for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) |
| 477 | + { |
| 478 | + const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex(*reg_num_p); |
| 479 | + if (reg_info_p == nullptr) |
| 480 | + { |
| 481 | + if (log) |
| 482 | + log->Printf("%s failed to get register info for register index %" PRIu32, |
| 483 | + __FUNCTION__, *reg_num_p); |
| 484 | + continue; |
| 485 | + } |
| 486 | + |
| 487 | + if (reg_info_p->value_regs != nullptr) |
| 488 | + continue; // Only expedite registers that are not contained in other registers. |
| 489 | + |
| 490 | + RegisterValue reg_value; |
| 491 | + Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); |
| 492 | + if (error.Fail()) |
| 493 | + { |
| 494 | + if (log) |
| 495 | + log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, |
| 496 | + reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, |
| 497 | + error.AsCString ()); |
| 498 | + continue; |
| 499 | + } |
| 500 | + |
| 501 | + StreamString stream; |
| 502 | + WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, ®_value); |
| 503 | + |
| 504 | + register_object_sp->SetObject(std::to_string(*reg_num_p), |
| 505 | + std::make_shared<JSONString>(stream.GetString())); |
| 506 | + } |
| 507 | + |
| 508 | + return register_object_sp; |
| 509 | +} |
| 510 | + |
| 511 | +static const char * |
| 512 | +GetStopReasonString(StopReason stop_reason) |
| 513 | +{ |
| 514 | + switch (stop_reason) |
| 515 | + { |
| 516 | + case eStopReasonTrace: |
| 517 | + return "trace"; |
| 518 | + case eStopReasonBreakpoint: |
| 519 | + return "breakpoint"; |
| 520 | + case eStopReasonWatchpoint: |
| 521 | + return "watchpoint"; |
| 522 | + case eStopReasonSignal: |
| 523 | + return "signal"; |
| 524 | + case eStopReasonException: |
| 525 | + return "exception"; |
| 526 | + case eStopReasonExec: |
| 527 | + return "exec"; |
| 528 | + case eStopReasonInstrumentation: |
| 529 | + case eStopReasonInvalid: |
| 530 | + case eStopReasonPlanComplete: |
| 531 | + case eStopReasonThreadExiting: |
| 532 | + case eStopReasonNone: |
| 533 | + break; // ignored |
| 534 | + } |
| 535 | + return nullptr; |
| 536 | +} |
| 537 | + |
458 | 538 | GDBRemoteCommunication::PacketResult
|
459 | 539 | GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
|
460 | 540 | {
|
@@ -595,34 +675,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
|
595 | 675 | }
|
596 | 676 | }
|
597 | 677 |
|
598 |
| - const char* reason_str = nullptr; |
599 |
| - switch (tid_stop_info.reason) |
600 |
| - { |
601 |
| - case eStopReasonTrace: |
602 |
| - reason_str = "trace"; |
603 |
| - break; |
604 |
| - case eStopReasonBreakpoint: |
605 |
| - reason_str = "breakpoint"; |
606 |
| - break; |
607 |
| - case eStopReasonWatchpoint: |
608 |
| - reason_str = "watchpoint"; |
609 |
| - break; |
610 |
| - case eStopReasonSignal: |
611 |
| - reason_str = "signal"; |
612 |
| - break; |
613 |
| - case eStopReasonException: |
614 |
| - reason_str = "exception"; |
615 |
| - break; |
616 |
| - case eStopReasonExec: |
617 |
| - reason_str = "exec"; |
618 |
| - break; |
619 |
| - case eStopReasonInstrumentation: |
620 |
| - case eStopReasonInvalid: |
621 |
| - case eStopReasonPlanComplete: |
622 |
| - case eStopReasonThreadExiting: |
623 |
| - case eStopReasonNone: |
624 |
| - break; |
625 |
| - } |
| 678 | + const char* reason_str = GetStopReasonString(tid_stop_info.reason); |
626 | 679 | if (reason_str != nullptr)
|
627 | 680 | {
|
628 | 681 | response.Printf ("reason:%s;", reason_str);
|
@@ -2637,6 +2690,92 @@ GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemo
|
2637 | 2690 | return SendStopReplyPacketForThread (tid);
|
2638 | 2691 | }
|
2639 | 2692 |
|
| 2693 | +GDBRemoteCommunication::PacketResult |
| 2694 | +GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo (StringExtractorGDBRemote &) |
| 2695 | +{ |
| 2696 | + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); |
| 2697 | + |
| 2698 | + // Ensure we have a debugged process. |
| 2699 | + if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) |
| 2700 | + return SendErrorResponse (50); |
| 2701 | + |
| 2702 | + if (log) |
| 2703 | + log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64, |
| 2704 | + __FUNCTION__, m_debugged_process_sp->GetID()); |
| 2705 | + |
| 2706 | + JSONArray threads_array; |
| 2707 | + |
| 2708 | + // Ensure we can get info on the given thread. |
| 2709 | + uint32_t thread_idx = 0; |
| 2710 | + for ( NativeThreadProtocolSP thread_sp; |
| 2711 | + (thread_sp = m_debugged_process_sp->GetThreadAtIndex(thread_idx)) != nullptr; |
| 2712 | + ++thread_idx) |
| 2713 | + { |
| 2714 | + |
| 2715 | + JSONObject::SP thread_obj_sp = std::make_shared<JSONObject>(); |
| 2716 | + |
| 2717 | + lldb::tid_t tid = thread_sp->GetID(); |
| 2718 | + |
| 2719 | + // Grab the reason this thread stopped. |
| 2720 | + struct ThreadStopInfo tid_stop_info; |
| 2721 | + std::string description; |
| 2722 | + if (!thread_sp->GetStopReason (tid_stop_info, description)) |
| 2723 | + return SendErrorResponse (52); |
| 2724 | + |
| 2725 | + const int signum = tid_stop_info.details.signal.signo; |
| 2726 | + if (log) |
| 2727 | + { |
| 2728 | + log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, |
| 2729 | + __FUNCTION__, |
| 2730 | + m_debugged_process_sp->GetID (), |
| 2731 | + tid, |
| 2732 | + signum, |
| 2733 | + tid_stop_info.reason, |
| 2734 | + tid_stop_info.details.exception.type); |
| 2735 | + } |
| 2736 | + |
| 2737 | + thread_obj_sp->SetObject("tid", std::make_shared<JSONNumber>(tid)); |
| 2738 | + if (signum != LLDB_INVALID_SIGNAL_NUMBER) |
| 2739 | + thread_obj_sp->SetObject("signal", std::make_shared<JSONNumber>(uint64_t(signum))); |
| 2740 | + |
| 2741 | + const std::string thread_name = thread_sp->GetName (); |
| 2742 | + if (! thread_name.empty()) |
| 2743 | + thread_obj_sp->SetObject("name", std::make_shared<JSONString>(thread_name)); |
| 2744 | + |
| 2745 | + if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp)) |
| 2746 | + thread_obj_sp->SetObject("registers", registers_sp); |
| 2747 | + |
| 2748 | + if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) |
| 2749 | + thread_obj_sp->SetObject("reason", std::make_shared<JSONString>(stop_reason_str)); |
| 2750 | + |
| 2751 | + if (! description.empty()) |
| 2752 | + thread_obj_sp->SetObject("description", std::make_shared<JSONString>(description)); |
| 2753 | + |
| 2754 | + if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) |
| 2755 | + { |
| 2756 | + thread_obj_sp->SetObject("metype", |
| 2757 | + std::make_shared<JSONNumber>(tid_stop_info.details.exception.type)); |
| 2758 | + |
| 2759 | + JSONArray::SP medata_array_sp = std::make_shared<JSONArray>(); |
| 2760 | + for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) |
| 2761 | + { |
| 2762 | + medata_array_sp->AppendObject(std::make_shared<JSONNumber>( |
| 2763 | + tid_stop_info.details.exception.data[i])); |
| 2764 | + } |
| 2765 | + thread_obj_sp->SetObject("medata", medata_array_sp); |
| 2766 | + } |
| 2767 | + |
| 2768 | + threads_array.AppendObject(thread_obj_sp); |
| 2769 | + } |
| 2770 | + // TODO: Expedite interesting regions of inferior memory |
| 2771 | + |
| 2772 | + StreamString response; |
| 2773 | + threads_array.Write(response); |
| 2774 | + StreamGDBRemote escaped_response; |
| 2775 | + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); |
| 2776 | + return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize()); |
| 2777 | +} |
| 2778 | + |
2640 | 2779 | GDBRemoteCommunication::PacketResult
|
2641 | 2780 | GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet)
|
2642 | 2781 | {
|
|
0 commit comments