* Copyright (c) Huawei Technologies Co., Ltd. 2023-2026. All rights reserved.
*/
#ifdef MS_DEBUGGER
#include <thread>
#include "AscendThreadLinux.h"
#include "AscendProcessLinux.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "lldb/Host/HostNativeThread.h"
#include "lldb/Host/linux/Ptrace.h"
#include "lldb/Utility/LLDBLog.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
AscendThreadLinux::AscendThreadLinux(AscendProcessLinux &process,
lldb::tid_t tid)
: NativeThreadLinux(*static_cast<NativeProcessLinux*>(&process), tid) {}
Status AscendThreadLinux::Resume(uint32_t signo) {
Log *const log = GetLog(POSIXLog::Thread);
LLDB_LOG(log, "AscendThreadLinux::{0}, tid: {1}", __FUNCTION__, GetID());
if (GetStopInfo().still_break_in_device) {
const StateType new_state = StateType::eStateRunning;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_info.reason = StopReason::eStopReasonNone;
m_stop_info.still_break_in_device = false;
m_stop_description.clear();
if (m_stop_info.internal_break) {
m_stop_info.internal_break = false;
LLDB_LOG(log, "internal_break, just let it go");
return Status();
}
LLDB_LOG(log, "Use AscendProcessLinux ResumeDevice");
AscendProcessLinux &process = AscendThreadLinux::GetProcess();
siginfo_t info;
const auto info_err = NativeProcessLinux::PtraceWrapper(PTRACE_GETSIGINFO, GetID(), nullptr, &info);
Status res;
if (info_err.Success()) {
res = NativeThreadLinux::Resume(signo);
}
process.ResumeDevice();
return res;
}
return NativeThreadLinux::Resume(signo);
}
NativeRegisterContextLinux & AscendThreadLinux::GetRegisterContext() {
if (m_stop_info.still_break_in_device) {
if (!m_device_reg_context_up) {
auto soc_type = GetProcess().GetSocType();
if (soc_type == SocType::SOC_END) {
return NativeThreadLinux::GetRegisterContext();
}
m_device_reg_context_up =
NativeRegisterContextLinux::CreateDeviceNativeRegisterContextLinux(
ArchSpec("hiipu64"), soc_type, *static_cast<NativeThreadLinux*>(this));
}
return *m_device_reg_context_up;
}
return NativeThreadLinux::GetRegisterContext();
}
AscendProcessLinux &AscendThreadLinux::GetProcess() {
return static_cast<AscendProcessLinux &>(m_process);
}
const AscendProcessLinux &AscendThreadLinux::GetProcess() const {
return static_cast<const AscendProcessLinux &>(m_process);
}
void AscendThreadLinux::SetStopInfoDetails(ThreadStopInfo &stop_info, const InterruptEvent &event) {
stop_info.details.device.break_addr = event.pc;
stop_info.details.device.core_id = event.core_id;
stop_info.details.device.core_type = event.core_type;
stop_info.details.device.pos_type = static_cast<uint8_t>(event.pos_type);
InterruptPosInfo pos;
pos.Update(event);
stop_info.details.device.thread_x = pos.thread_pos.x;
stop_info.details.device.thread_y = pos.thread_pos.y;
stop_info.details.device.thread_z = pos.thread_pos.z;
}
void AscendThreadLinux::SetStoppedByDeviceBreakpoint(const InterruptEvent &event) {
if (m_state == StateType::eStateStepping)
m_step_workaround.reset();
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_description.clear();
SetStopInfoDetails(m_stop_info, event);
m_stop_info.reason = StopReason::eStopReasonDeviceBreakpoint;
m_stop_info.signo = SIGTRAP;
m_stop_info.still_break_in_device = true;
}
void AscendThreadLinux::SetStoppedByInternalBreakpoint() {
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_description.clear();
m_stop_info.reason = StopReason::eStopReasonTrace;
m_stop_info.internal_break = true;
m_stop_info.signo = SIGTRAP;
m_stop_info.still_break_in_device = true;
}
Status AscendThreadLinux::SingleStep(uint32_t signo) {
AscendProcessLinux &process = GetProcess();
if (process.IsDeviceBreak() && process.GetID() == GetID()) {
return GetProcess().SingleStep();
}
return NativeThreadLinux::SingleStep(signo);
}
Status AscendThreadLinux::RequestStop() {
if (!GetStopInfo().still_break_in_device) {
return NativeThreadLinux::RequestStop();
}
Log *log = GetLog(LLDBLog::Thread);
LLDB_LOGF(log,
"AscendThreadLinux::%s requesting thread stop",
__FUNCTION__);
return Status();
}
void AscendThreadLinux::SetStopThreadIdx(uint16_t x, uint16_t y, uint16_t z) {
m_stop_info.details.device.thread_x = x;
m_stop_info.details.device.thread_y = y;
m_stop_info.details.device.thread_z = z;
}
void AscendThreadLinux::SetStopped(bool use_reg) {
if (m_state == StateType::eStateStepping)
m_step_workaround.reset();
if (use_reg) {
GetRegisterContext().InvalidateAllRegisters();
}
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange(new_state);
m_state = new_state;
m_stop_description.clear();
}
void AscendThreadLinux::SetDeviceStoppedByTrace(const InterruptEvent ¶m) {
SetStopped();
SetStopInfoDetails(m_stop_info, param);
m_stop_info.reason = StopReason::eStopReasonTrace;
m_stop_info.signo = SIGTRAP;
}
void AscendThreadLinux::SetStoppedByDeviceCtrlC(const InterruptEvent &event) {
Log *log = GetLog(LLDBLog::Thread);
LLDB_LOGF(log, "AscendThreadLinux::%s called", __FUNCTION__);
SetStopInfoDetails(m_stop_info, event);
m_stop_info.reason = StopReason::eStopReasonSignal;
m_stop_info.signo = SIGSTOP;
m_stop_info.still_break_in_device = true;
}
void AscendThreadLinux::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) {
Log *log = GetLog(LLDBLog::Thread);
LLDB_LOGF(log, "AscendThreadLinux::%s called with signal 0x%02" PRIx32,
__FUNCTION__, signo);
NativeThreadLinux::SetStoppedBySignal(signo, info);
if (signo != SIGSTOP) {
return;
}
Status error;
AscendProcessLinux &process = GetProcess();
if (process.GetID() == GetID() && info) {
error = process.TaskKill();
if (error.Fail()) {
LLDB_LOG(log, "AscendThreadLinux::{0} error={1}", __FUNCTION__, error);
return;
}
}
}
#endif