1//===-- ThreadKDP.cpp -----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ThreadKDP.h"
10
11#include "lldb/Host/SafeMachO.h"
12
13#include "lldb/Breakpoint/Watchpoint.h"
14#include "lldb/Target/Process.h"
15#include "lldb/Target/RegisterContext.h"
16#include "lldb/Target/StopInfo.h"
17#include "lldb/Target/Target.h"
18#include "lldb/Target/Unwind.h"
19#include "lldb/Utility/ArchSpec.h"
20#include "lldb/Utility/DataExtractor.h"
21#include "lldb/Utility/State.h"
22#include "lldb/Utility/StreamString.h"
23
24#include "Plugins/Process/Utility/StopInfoMachException.h"
25#include "ProcessKDP.h"
26#include "ProcessKDPLog.h"
27#include "RegisterContextKDP_arm.h"
28#include "RegisterContextKDP_arm64.h"
29#include "RegisterContextKDP_x86_64.h"
30
31#include <memory>
32
33using namespace lldb;
34using namespace lldb_private;
35
36// Thread Registers
37
38ThreadKDP::ThreadKDP(Process &process, lldb::tid_t tid)
39 : Thread(process, tid), m_thread_name(), m_dispatch_queue_name(),
40 m_thread_dispatch_qaddr(LLDB_INVALID_ADDRESS) {
41 Log *log = GetLog(mask: KDPLog::Thread);
42 LLDB_LOG(log, "this = {0}, tid = {1:x}", this, GetID());
43}
44
45ThreadKDP::~ThreadKDP() {
46 Log *log = GetLog(mask: KDPLog::Thread);
47 LLDB_LOG(log, "this = {0}, tid = {1:x}", this, GetID());
48 DestroyThread();
49}
50
51const char *ThreadKDP::GetName() {
52 if (m_thread_name.empty())
53 return nullptr;
54 return m_thread_name.c_str();
55}
56
57const char *ThreadKDP::GetQueueName() { return nullptr; }
58
59void ThreadKDP::RefreshStateAfterStop() {
60 // Invalidate all registers in our register context. We don't set "force" to
61 // true because the stop reply packet might have had some register values
62 // that were expedited and these will already be copied into the register
63 // context by the time this function gets called. The KDPRegisterContext
64 // class has been made smart enough to detect when it needs to invalidate
65 // which registers are valid by putting hooks in the register read and
66 // register supply functions where they check the process stop ID and do the
67 // right thing.
68 const bool force = false;
69 lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext());
70 if (reg_ctx_sp)
71 reg_ctx_sp->InvalidateIfNeeded(force);
72}
73
74bool ThreadKDP::ThreadIDIsValid(lldb::tid_t thread) { return thread != 0; }
75
76void ThreadKDP::Dump(Log *log, uint32_t index) {}
77
78bool ThreadKDP::ShouldStop(bool &step_more) { return true; }
79lldb::RegisterContextSP ThreadKDP::GetRegisterContext() {
80 if (!m_reg_context_sp)
81 m_reg_context_sp = CreateRegisterContextForFrame(frame: nullptr);
82 return m_reg_context_sp;
83}
84
85lldb::RegisterContextSP
86ThreadKDP::CreateRegisterContextForFrame(StackFrame *frame) {
87 lldb::RegisterContextSP reg_ctx_sp;
88 uint32_t concrete_frame_idx = 0;
89
90 if (frame)
91 concrete_frame_idx = frame->GetConcreteFrameIndex();
92
93 if (concrete_frame_idx == 0) {
94 ProcessSP process_sp(CalculateProcess());
95 if (process_sp) {
96 switch (static_cast<ProcessKDP *>(process_sp.get())
97 ->GetCommunication()
98 .GetCPUType()) {
99 case llvm::MachO::CPU_TYPE_ARM:
100 reg_ctx_sp =
101 std::make_shared<RegisterContextKDP_arm>(args&: *this, args&: concrete_frame_idx);
102 break;
103 case llvm::MachO::CPU_TYPE_ARM64:
104 reg_ctx_sp = std::make_shared<RegisterContextKDP_arm64>(
105 args&: *this, args&: concrete_frame_idx);
106 break;
107 case llvm::MachO::CPU_TYPE_X86_64:
108 reg_ctx_sp = std::make_shared<RegisterContextKDP_x86_64>(
109 args&: *this, args&: concrete_frame_idx);
110 break;
111 default:
112 llvm_unreachable("Add CPU type support in KDP");
113 }
114 }
115 } else {
116 reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
117 }
118 return reg_ctx_sp;
119}
120
121bool ThreadKDP::CalculateStopInfo() {
122 ProcessSP process_sp(GetProcess());
123 if (process_sp) {
124 if (m_cached_stop_info_sp) {
125 SetStopInfo(m_cached_stop_info_sp);
126 } else {
127 SetStopInfo(StopInfo::CreateStopReasonWithSignal(thread&: *this, SIGSTOP));
128 }
129 return true;
130 }
131 return false;
132}
133
134void ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION(
135 const DataExtractor &exc_reply_packet) {
136 lldb::offset_t offset = 0;
137 uint8_t reply_command = exc_reply_packet.GetU8(offset_ptr: &offset);
138 if (reply_command == CommunicationKDP::KDP_EXCEPTION) {
139 offset = 8;
140 const uint32_t count = exc_reply_packet.GetU32(offset_ptr: &offset);
141 if (count >= 1) {
142 // const uint32_t cpu = exc_reply_packet.GetU32 (&offset);
143 offset += 4; // Skip the useless CPU field
144 const uint32_t exc_type = exc_reply_packet.GetU32(offset_ptr: &offset);
145 const uint32_t exc_code = exc_reply_packet.GetU32(offset_ptr: &offset);
146 const uint32_t exc_subcode = exc_reply_packet.GetU32(offset_ptr: &offset);
147 // We have to make a copy of the stop info because the thread list will
148 // iterate through the threads and clear all stop infos..
149
150 // Let the StopInfoMachException::CreateStopReasonWithMachException()
151 // function update the PC if needed as we might hit a software breakpoint
152 // and need to decrement the PC (i386 and x86_64 need this) and KDP
153 // doesn't do this for us.
154 const bool pc_already_adjusted = false;
155 const bool adjust_pc_if_needed = true;
156
157 m_cached_stop_info_sp =
158 StopInfoMachException::CreateStopReasonWithMachException(
159 thread&: *this, exc_type, exc_data_count: 2, exc_code, exc_sub_code: exc_subcode, exc_sub_sub_code: 0, pc_already_adjusted,
160 adjust_pc_if_needed);
161 }
162 }
163}
164

source code of lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp