* Copyright (c) Huawei Technologies Co., Ltd. 2023-2026. All rights reserved.
*/
#ifdef MS_DEBUGGER
#include "AscendProcessLinux.h"
#include <fcntl.h>
#include "AscendThreadLinux.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/RegisterValue.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
using namespace llvm;
const std::string DEVICE_INFO_HEADER{"device_id:"};
const std::string KERNEL_INFO_HEADER{"kernel_name:"};
constexpr uint32_t VEC_SIZE = 4;
static std::condition_variable g_pause_cv;
static std::mutex g_pause_mutex;
static bool g_paused = false;
enum ASCEND_PROCESS_ERROR_CODE {
OPEN_KO_ERR = 0x20200,
SET_BREAKPOINT_ERR = 0x20201,
INIT_DEBUG_MODE_ERR = 0x20202,
INTERNAL_DEBUGGER_ERR = 0x20203,
UNSUPPORTED_SOC_TYPE_ERR = 0x20204
};
AscendProcessLinux::AscendProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
const ArchSpec &arch, Manager &manager,
llvm::ArrayRef<::pid_t> tids, const std::string& socket_path)
: NativeProcessLinux(pid, terminal_fd, delegate, arch, manager, tids) {
Status status;
RegisterParsers();
if (m_server == nullptr) {
static constexpr size_t MAX_CLIENT_NUM = 1024;
m_server = std::make_shared<AscendCommunicationServer>(MAX_CLIENT_NUM, socket_path);
auto func = std::bind(&AscendProcessLinux::HandleMsg, this, std::placeholders::_1, std::placeholders::_2);
m_server->SetMsgHandlerHook(func);
m_server->Start();
}
m_pos_info.Reset();
m_device_context.reset();
m_stop = false;
m_cores_info.clear();
m_kernel_name.clear();
for (const auto &tid : tids) {
AscendThreadLinux &thread = AddThread(tid, false);
ThreadWasCreated(thread);
}
if (!tids.empty()) {
SetCurrentThreadID(tids[0]);
}
SetState(StateType::eStateStopped, false);
}
AscendProcessLinux::~AscendProcessLinux() {
m_stop = true;
m_server->Close();
}
Status AscendProcessLinux::InitDeviceContext(const int device_id, const std::string &soc_version, const ::pid_t tgid) {
Log *log = GetLog(POSIXLog::Process);
Status error;
LLDB_LOG(log, "Start create device context");
m_device_context = DeviceContext::Factory::GetDeviceContext(soc_version, tgid, device_id);
if (!m_device_context) {
error.SetError(ASCEND_PROCESS_ERROR_CODE::UNSUPPORTED_SOC_TYPE_ERR, lldb::eErrorTypeGeneric);
error.SetErrorStringWithFormatv("Get device context failed: soc_version={0}\n", soc_version);
return error;
}
error = m_device_context->Init();
if (error.Fail()) {
error.SetError(ASCEND_PROCESS_ERROR_CODE::OPEN_KO_ERR, lldb::eErrorTypeGeneric);
error.SetErrorStringWithFormatv("Init device context failed: {0}", error);
return error;
}
m_device_context->SetBreakpointCallback([this](const DebugRecvInfo &info) {HandleProcessState(info);});
error = m_device_context->EnableDebugMode();
if (error.Fail()) {
error.SetError(ASCEND_PROCESS_ERROR_CODE::INIT_DEBUG_MODE_ERR, lldb::eErrorTypeGeneric);
error.SetErrorStringWithFormatv("Enable debug mode failed: {0}", error);
return error;
}
if (!m_device_context->StartListenThread()) {
error.SetError(ASCEND_PROCESS_ERROR_CODE::INTERNAL_DEBUGGER_ERR, lldb::eErrorTypeGeneric);
error.SetErrorStringWithFormatv("Start listen thread failed");
return error;
}
return error;
}
HandleResult AscendProcessLinux::HandleStubDeviceInfo(const DeviceInfoMsg& device_info_msg) {
Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "Process device id");
Status error;
m_socket_device_pid[m_client_socket] = std::make_pair(device_info_msg.device_id, device_info_msg.tgid);
m_tgid = device_info_msg.tgid;
m_device_ids.insert(device_info_msg.device_id);
if (m_device_context) {
LLDB_LOG(log, "device context has been constructed");
return error;
}
if (m_client_device_id == -1) {
LLDB_LOG(log, "client do not set device id, use the first device id: {0}", device_info_msg.device_id);
error = InitDeviceContext(device_info_msg.device_id, device_info_msg.soc_version, m_tgid);
} else if (m_client_device_id == device_info_msg.device_id) {
LLDB_LOG(log, "client set device id, and it is matched, use {0} to init device context", m_client_device_id);
error = InitDeviceContext(m_client_device_id, device_info_msg.soc_version, m_tgid);
} else {
LLDB_LOG(log, "device id do not match, client device id: {0}, set device id: {1}", m_client_device_id,
device_info_msg.device_id);
}
if (error.Success()) {
error.SetExpressionErrorWithFormat(ExpressionResults::eExpressionCompleted, "Debugger focus on device %d", device_info_msg.device_id);
}
return error;
}
HandleResult AscendProcessLinux::HandleStubKernelInfo(const KernelInfoMsg& kernel_info_msg) {
Log *log = GetLog(POSIXLog::Process);
Status final_error;
do {
if (m_device_context == nullptr) {
LLDB_LOG(log, "{0} device context is not initialized!", __FUNCTION__);
break;
}
auto it = m_socket_device_pid.find(m_client_socket);
if (it == m_socket_device_pid.end()) {
LLDB_LOG(log, "cannot find on which device the kernel {0} should be launched.",
kernel_info_msg.kernel_name.c_str());
break;
}
auto device_id = it->second.first;
auto tgid = it->second.second;
if (!m_device_context->IsDeviceIdMatched(device_id)) {
LLDB_LOG(log, "device id {0} from client {1} is not matched",
device_id, m_client_socket);
break;
}
LLDB_LOG(log, "device id matched. device id:{0} client:{1}", device_id, m_client_socket);
m_kernel_name = kernel_info_msg.kernel_name;
m_stream_id = kernel_info_msg.stream_id;
LLDB_LOG(log, "update kernel_name to {0}, stream_id to {1}", m_kernel_name, m_stream_id);
if (!kernel_info_msg.elf.empty()) {
DeviceBinaryInfo binary_info;
binary_info.pc_base_addr = kernel_info_msg.pc_base_addr;
binary_info.binary = kernel_info_msg.elf;
if (!m_device_context->IsTgidMatched(tgid)) {
binary_info.reset_all_device_binary = 1U;
m_device_context->UpdateTgid(tgid);
} else {
binary_info.reset_all_device_binary = 0U;
}
m_device_binary_info_que.push(binary_info);
LLDB_LOG(log, "success get base_pc={0:x}, kernel_hash={1}", kernel_info_msg.pc_base_addr,
kernel_info_msg.kernel_hash);
for (const auto &thread_up : m_threads) {
AscendThreadLinux *thread = GetThreadByID(thread_up->GetID());
if (!thread) {
continue;
}
if (thread_up->GetID() != GetID()) {
thread->SetStopped(false);
continue;
}
LLDB_LOG(log, "Fake internel-breakpoint process state, pid = {0}", thread->GetID());
thread->SetStoppedByInternalBreakpoint();
m_pending_notification_tid = thread->GetID();
m_current_thread_id = thread->GetID();
SetState(StateType::eStateStopped, false);
m_delegate.ProcessStateChanged(this, StateType::eStateStopped);
m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
}
m_internal_break_done = false;
m_device_context->SetCanRun(false);
while(!m_internal_break_done && !m_stop);
LLDB_LOG(log, "process internal fake break point done");
}
} while (0);
return final_error;
}
void AscendProcessLinux::RegisterParsers() {
m_parser.Register(
DEVICE_INFO_HEADER,
std::make_shared<DeviceHandler>([this](const DeviceInfoMsg& msg) {
return HandleStubDeviceInfo(msg);
})
);
m_parser.Register(
KERNEL_INFO_HEADER,
std::make_shared<KernelHandler>([this](const KernelInfoMsg& msg) {
return HandleStubKernelInfo(msg);
})
);
}
void AscendProcessLinux::HandleMsg(Socket *client_socket, const std::string &msg) {
Log *log = GetLog(POSIXLog::Process);
constexpr int display_length = 1024;
llvm::StringRef display_msg(msg.data(), msg.length());
if (display_msg.size() > display_length) {
display_msg = display_msg.slice(0, display_length);
}
auto it = m_socket_device_pid.find(client_socket);
if (it == m_socket_device_pid.end()) {
LLDB_LOG(log, "receive this device id for the first time, message is: {0}, original length is {1}",
display_msg, msg.length());
} else {
LLDB_LOG(log, "receive message for device id: {0}, pid: {1}, message is: {2}",
it->second.first, it->second.second, display_msg, msg.length());
}
std::lock_guard<std::mutex> guard(m_socket_mutex);
m_client_socket = client_socket;
HandleResult result = m_parser.ParseMessage(msg);
std::string reply = "$ok;";
if (result.Fail()) {
StreamString temp;
temp.Printf("$fail:%x;", result.GetError());
reply = temp.GetString().data();
} else if (result.GetMessage().length()) {
reply += result.GetMessage();
reply += ";";
}
size_t send_bytes = reply.size();
if (client_socket->Write(reply.data(), send_bytes).Fail()) {
LLDB_LOG(log, "reply failed");
}
}
AscendThreadLinux &AscendProcessLinux::AddThread(lldb::tid_t thread_id,
bool resume) {
Log *log = GetLog(POSIXLog::Thread);
LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
assert(!HasThreadNoLock(thread_id) &&
"attempted to add a thread by id that already exists");
if (m_threads.empty())
SetCurrentThreadID(thread_id);
m_threads.push_back(std::make_unique<AscendThreadLinux>(*this, thread_id));
AscendThreadLinux &thread =
static_cast<AscendThreadLinux &>(*m_threads.back());
Status tracing_error = NotifyTracersOfNewThread(thread.GetID());
if (tracing_error.Fail()) {
thread.SetStoppedByProcessorTrace(tracing_error.AsCString());
StopRunningThreads(thread.GetID());
} else if (resume)
ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
else
thread.SetStoppedBySignal(SIGSTOP);
return thread;
}
Status AscendProcessLinux::SetBreakpoint(lldb::addr_t addr, uint32_t size,
llvm::Triple::ArchType arch_type, bool hardware) {
Log *log = GetLog(LLDBLog::Breakpoints);
LLDB_LOG(log, "AscendProcessLinux::{0} addr = {1:x}", __FUNCTION__, addr);
if (arch_type == llvm::Triple::hiipu64) {
if (hardware) {
return SetDeviceHardwareBreakpoint(addr);
} else {
return SetDeviceSoftwareBreakpoint(addr);
}
} else {
return NativeProcessLinux::SetBreakpoint(addr, size, hardware);
}
}
Status AscendProcessLinux::RemoveBreakpoint(
lldb::addr_t addr, llvm::Triple::ArchType arch_type, bool hardware) {
if (arch_type == llvm::Triple::hiipu64) {
if (hardware) {
return RemoveDeviceHardwareBreakpoint(addr);
} else {
return RemoveDeviceSoftwareBreakpoint(addr);
}
}
return NativeProcessLinux::RemoveBreakpoint(addr);
}
Status AscendProcessLinux::RemoveDeviceHardwareBreakpoint(lldb::addr_t addr) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
AscendThreadLinux *thread = GetThreadByID(GetID());
ThreadStopInfo stop_info{};
std::string description;
if (thread) {
thread->GetStopReason(stop_info, description);
}
if (!stop_info.still_break_in_device || stop_info.internal_break) {
LLDB_LOG(log, "save lazy call for {0} with addr = {1:x}", __FUNCTION__, addr);
auto func = [this, addr]() -> Status { return RemoveDeviceHardwareBreakpoint(addr); };
m_lazy_calls.push_back(func);
return Status();
}
Status error = m_device_context->RemoveHardwareBreakpoint(addr, m_stream_id, m_pos_info);
if (error.Fail()) {
return error;
}
size_t result = m_hw_breakpoints_map.erase(addr);
if (result == 0) {
error.SetErrorString("erase in m_hw_breakpoints_map failed, addr does not exist");
}
return error;
}
Status AscendProcessLinux::RemoveDeviceSoftwareBreakpoint(lldb::addr_t addr) {
Log *log = GetLog(LLDBLog::Breakpoints);
Status error;
LLDB_LOG(log, "addr = {0:x}", addr);
auto it = m_software_breakpoints.find(addr);
if (it == m_software_breakpoints.end())
return Status("Breakpoint not found.");
assert(it->second.ref_count > 0);
if (--it->second.ref_count > 0)
return Status();
if (m_device_context->SupportDirectlySetSwBp()) {
m_device_context->RemoveSoftwareBreakpoint(addr);
} else {
error = RemoveSwBpByMemory(addr, it->second);
if (error.Fail()) {
return error;
}
}
m_software_breakpoints.erase(it);
return error;
}
Status AscendProcessLinux::Resume(const ResumeActionList &resume_actions) {
std::lock_guard<std::mutex> guard(m_status_mtx);
std::shared_ptr<void> defer(nullptr, [this](std::nullptr_t &) {
if (m_state == lldb::eStateRunning) {
m_device_context->SetCanRun(true);
m_internal_break_done = true;
}
});
if (!IsDeviceBreak()) {
return NativeProcessLinux::Resume(resume_actions);
}
Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "{0} pid {1}", __FUNCTION__, GetID());
const auto &thread = GetCurrentThread();
if (!thread) {
return Status("AscendProcessLinux::%s (): can not get current thread.",
__FUNCTION__);
}
const ResumeAction *const action =
resume_actions.GetActionForThread(thread->GetID(), true);
if (!action) {
return Status("AscendProcessLinux::%s (): can not get action.",
__FUNCTION__);
}
switch (action->state) {
case eStateRunning:
case eStateStepping: {
const int signo = action->signal;
ResumeThread(static_cast<NativeThreadLinux &>(*thread), action->state,
signo);
break;
}
case eStateSuspended:
case eStateStopped:
break;
default:
return Status("AscendProcessLinux::%s (): unexpected state %d",
__FUNCTION__, action->state);
}
return Status();
}
Status AscendProcessLinux::SetDeviceHardwareBreakpoint(lldb::addr_t addr) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
AscendThreadLinux *thread = GetThreadByID(GetID());
ThreadStopInfo stop_info{};
std::string description;
if (thread) {
thread->GetStopReason(stop_info, description);
}
if (!stop_info.still_break_in_device || stop_info.internal_break) {
LLDB_LOG(log, "save lazy call for {0} with addr = {1:x}", __FUNCTION__, addr);
auto func = [this, addr]() -> Status { return SetDeviceHardwareBreakpoint(addr); };
m_lazy_calls.push_back(func);
return Status();
}
constexpr size_t bp_size = 4;
auto error = m_device_context->SetHardwareBreakpoint(addr, m_stream_id, m_pos_info);
if (error.Success()) {
m_hw_breakpoints_map[addr] = {addr, bp_size};
}
return error;
}
AscendThreadLinux *AscendProcessLinux::GetThreadByID(lldb::tid_t tid) {
return static_cast<AscendThreadLinux *>(
NativeProcessProtocol::GetThreadByID(tid));
}
AscendThreadLinux *AscendProcessLinux::GetCurrentThread() {
return static_cast<AscendThreadLinux *>(
NativeProcessProtocol::GetCurrentThread());
}
Status AscendProcessLinux::SetDeviceSoftwareBreakpoint(lldb::addr_t addr) {
Log *log = GetLog(LLDBLog::Breakpoints);
LLDB_LOG(log, "addr = {0:x}", addr);
auto it = m_software_breakpoints.find(addr);
if (it != m_software_breakpoints.end()) {
++it->second.ref_count;
return Status();
}
auto expected_bkpt = EnableDeviceSoftwareBreakpoint(addr);
if (!expected_bkpt)
return Status(expected_bkpt.takeError());
m_software_breakpoints.emplace(addr, std::move(*expected_bkpt));
return Status();
}
llvm::Expected<NativeProcessProtocol::SoftwareBreakpoint> AscendProcessLinux::EnableDeviceSoftwareBreakpoint(
lldb::addr_t addr) {
Log *log = GetLog(LLDBLog::Breakpoints);
Status error;
if (m_device_context == nullptr) {
error.SetErrorString("device context is null!");
return error.ToError();
}
static const uint8_t g_ascend_opcode[] = {0x0, 0x0, 0x80, 0x41};
ArrayRef<uint8_t> expected_trap = llvm::ArrayRef(g_ascend_opcode);
llvm::SmallVector<uint8_t, VEC_SIZE> saved_opcode_bytes(expected_trap.size(), 0);
if (m_device_context->SupportDirectlySetSwBp()) {
error = m_device_context->SetSoftwareBreakpoint(addr);
} else {
error = SetSwBpByMemory(addr, expected_trap, saved_opcode_bytes);
}
if (error.Fail()) {
return error.ToError();
}
LLDB_LOG(log, "addr = {0:x}: SUCCESS", addr);
return SoftwareBreakpoint{1, saved_opcode_bytes, expected_trap};
}
Status AscendProcessLinux::ReadDeviceMemory(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
bytes_read = m_device_context->ReadGlobalMemory(addr, size, buf);
if (bytes_read < size) {
return Status("addr=0x%" PRIx64
": tried to read device %zu bytes but only read %zu",
addr, size, bytes_read);
}
return Status();
}
Status AscendProcessLinux::SetSwBpByMemory(lldb::addr_t addr,
ArrayRef<uint8_t> expected_trap,
SmallVector<uint8_t, VEC_SIZE> &saved_opcode_bytes) {
Log *log = GetLog(LLDBLog::Breakpoints);
LLDB_LOG(log, "{0}", __FUNCTION__);
size_t bytes_read = 0;
Status error;
if (m_device_context == nullptr) {
error.SetErrorString("device context is null!");
return error;
}
error = ReadDeviceMemory(addr, saved_opcode_bytes.data(), saved_opcode_bytes.size(), bytes_read);
if (error.Fail()) {
error.SetErrorStringWithFormat(
"while attempting to set device breakpoint, got error: %s", error.AsCString());
return error;
}
LLDB_LOG(log, "Overwriting bytes at device addr {0:x}: {1:@[x]}", addr,
llvm::make_range(saved_opcode_bytes.begin(), saved_opcode_bytes.end()));
size_t bytes_written = 0;
error = WriteDeviceMemory(addr, expected_trap.data(), expected_trap.size(), bytes_written);
if (error.Fail()) {
error.SetErrorStringWithFormat(
"while attempting to set device breakpoint, got error: %s", error.AsCString());
return error;
}
llvm::SmallVector<uint8_t, VEC_SIZE> verify_bp_opcode_bytes(expected_trap.size(), 0);
size_t verify_bytes_read = 0;
error = ReadDeviceMemory(addr, verify_bp_opcode_bytes.data(),
verify_bp_opcode_bytes.size(), verify_bytes_read);
if (error.Fail()) {
error.SetErrorStringWithFormat(
"while attempting to verify device breakpoint, got error: %s", error.AsCString());
return error;
}
if (llvm::ArrayRef(verify_bp_opcode_bytes.data(), verify_bytes_read) != expected_trap) {
error.SetErrorStringWithFormat("Verification of software breakpoint "
"writing failed - trap opcodes not successfully read back "
"after writing when setting breakpoint at %#lx", addr);
return error;
}
return m_device_context->InvalidInstrCache(addr, m_pos_info, 1);
}
Status AscendProcessLinux::RemoveSwBpByMemory(lldb::addr_t addr, const SoftwareBreakpoint &bp) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
LLDB_LOG(log, "{0}", __FUNCTION__);
Status error;
if (m_device_context == nullptr) {
error.SetErrorString("device context is null!");
return error;
}
llvm::SmallVector<uint8_t, VEC_SIZE> curr_break_op(bp.breakpoint_opcodes.size(), 0);
size_t bytes_read = 0;
error = ReadDeviceMemory(addr, curr_break_op.data(), curr_break_op.size(), bytes_read);
if (error.Fail()) {
return error;
}
const auto &saved = bp.saved_opcodes;
size_t verify_bytes_read = 0;
if (ArrayRef(curr_break_op) != bp.breakpoint_opcodes) {
if (curr_break_op != bp.saved_opcodes)
return Status("Original breakpoint trap is no longer in memory.");
LLDB_LOG(log, "Saved device opcodes ({0:@[x]}) have already been restored at {1:x}.",
llvm::make_range(saved.begin(), saved.end()), addr);
} else {
size_t bytes_written = 0;
error = WriteDeviceMemory(addr, saved.data(), saved.size(), bytes_written);
if (error.Fail()) {
return error;
}
error = m_device_context->InvalidInstrCache(addr, m_pos_info, 1);
if (error.Fail()) {
return error;
}
llvm::SmallVector<uint8_t, VEC_SIZE> verify_opcode(saved.size(), 0);
error = ReadDeviceMemory(addr, verify_opcode.data(), verify_opcode.size(), verify_bytes_read);
if (error.Fail()) {
error.SetErrorStringWithFormat("when verify, got error: %s", error.AsCString());
return error;
}
if (verify_opcode != saved)
LLDB_LOG(log, "Restoring device bytes at {0:x}: {1:@[x]}", addr, llvm::make_range(saved.begin(), saved.end()));
}
return Status();
}
Status AscendProcessLinux::WriteDeviceMemory(lldb::addr_t addr, const void *buf,
size_t size, size_t &bytes_written) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
bytes_written = m_device_context->WriteGlobalMemory(addr, size, buf);
if (bytes_written < size) {
return Status("addr=0x%" PRIx64
": tried to write device %zu bytes but only wrote %zu",
addr, size, bytes_written);
}
return Status();
}
void AscendProcessLinux::TryUpdateThreadIndex(InterruptEvent &event) {
uint8_t thread_in_warp = m_pos_info.thread_info.thread_id % 32;
uint8_t warp_id = m_pos_info.thread_info.thread_id / 32;
std::vector<WarpInfo> warps_info;
Status error = GetWarpsInfo(warps_info);
if (error.Fail() || warps_info.empty()) {
return;
}
WarpInfo warp_info{};
bool has_warp = false;
for (auto warp : warps_info) {
if (warp.warp_id == warp_id) {
warp_info = warp;
has_warp = true;
break;
}
}
if (!has_warp) {
return;
}
bool active = (warp_info.exec_mask & (1U << thread_in_warp)) != 0;
bool single_core_run = m_pos_info.single_core_run;
if (active && single_core_run) {
event.thread_info = m_pos_info.thread_info;
}
return;
}
void AscendProcessLinux::FixSimdPC(uint64_t &pc) {
constexpr uint64_t low18bit = (1U << 18) - 1;
if (m_latest_vf_start_pc) {
pc &= low18bit;
if ((pc & low18bit) < (m_latest_vf_start_pc & low18bit)) {
pc |= (m_latest_vf_start_pc & (~low18bit)) + (1u << 18);
} else {
pc |= m_latest_vf_start_pc & (~low18bit);
}
}
}
void AscendProcessLinux::HandleProcessState(const DebugRecvInfo &info) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
Status error;
if (info.cmd_type == CmdType::INTERRUPT_EVENT) {
const InterruptEvent *param = (const InterruptEvent*)info.recv_msg;
InterruptEvent event = *param;
if (param->pos_type == InterruptPosType::VEC_INTERRUPT_SIMD) {
LLDB_LOG(log, "latest vf start pc={0:x}", m_latest_vf_start_pc);
FixSimdPC(event.pc);
}
LLDB_LOGF(log, "pc=%#lx,core_id=%u,core_status=%d,core_type=%u,pos_type=%u,thread_dim=(%u,%u,%u),thread_id=%u,before_fix_pc=%#lx",
event.pc, param->core_id, int(param->status), param->core_type,
(uint8_t)param->pos_type, param->thread_info.thread_dim_x, param->thread_info.thread_dim_y, param->thread_info.thread_dim_z,
param->thread_info.thread_id, param->pc);
std::lock_guard<std::mutex> guard(m_status_mtx);
if (event.pos_type == InterruptPosType::VEC_INTERRUPT_SIMT) {
TryUpdateThreadIndex(event);
}
if (param->status == CoreStatus::BRKPT) {
MonitorBreakpoint(event);
} else if (param->status == CoreStatus::SINGLE_STEP) {
MonitorTrace(event);
} else if (param->status == CoreStatus::TASK_KILLED) {
MonitorSignal(event);
}
}
}
void AscendProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
LLDB_LOG(log, "received host breakpoint event, pid = {0}", thread.GetID());
ThreadStopInfo stop_info;
std::string description;
if (thread.GetStopReason(stop_info, description) && stop_info.still_break_in_device && !stop_info.internal_break) {
LLDB_LOG(log, "warn: current device process is debugging, ignore host breakpoint event.");
return;
}
if (stop_info.internal_break) {
stop_info.internal_break = false;
m_internal_break_done = true;
}
NativeProcessLinux::MonitorBreakpoint(thread);
if (m_device_context && thread.GetState() == lldb::eStateStopped) {
m_device_context->SetCanRun(false);
} else {
LLDB_LOG(log, "Can not stop device context detect: after host MonitorBreakpoint, "
"thread state {0}", thread.GetState());
}
}
void AscendProcessLinux::MonitorBreakpoint(const InterruptEvent ¶m) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
m_pos_info.Update(param);
m_cores_info.clear();
for (const auto &thread_up : m_threads) {
AscendThreadLinux *thread = GetThreadByID(thread_up->GetID());
if (!thread) {
continue;
}
if (thread_up->GetID() != GetID()) {
thread->SetStopped(false);
continue;
}
LLDB_LOG(log, "Handle breakpoint process state, pid = {0}", thread->GetID());
thread->SetStoppedByDeviceBreakpoint(param);
for (const auto &func: m_lazy_calls) {
auto error = func();
if (error.Fail()) {
LLDB_LOG(log, "Lazy call failed: reason: {0}", error);
}
}
m_lazy_calls.clear();
m_pending_notification_tid = thread->GetID();
auto &stepping_breakpoint = GetThreadsSteppingWithBreakpoint();
stepping_breakpoint.clear();
m_current_thread_id = thread->GetID();
SetState(StateType::eStateStopped, false);
m_delegate.ProcessStateChanged(this, StateType::eStateStopped);
m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
}
}
void AscendProcessLinux::MonitorTrace(const InterruptEvent ¶m) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Breakpoints);
m_pos_info.Update(param);
m_cores_info.clear();
for (const auto &thread_up : m_threads) {
AscendThreadLinux *thread = GetThreadByID(thread_up->GetID());
if (!thread) {
continue;
}
if (thread_up->GetID() != GetID()) {
thread->SetStopped(false);
continue;
}
LLDB_LOG(log, "Handle single step process state, pid = {0}", thread->GetID());
((AscendThreadLinux*)thread)->SetDeviceStoppedByTrace(param);
SetState(StateType::eStateStopped, false);
m_delegate.ProcessStateChanged(this, StateType::eStateStopped);
}
}
void AscendProcessLinux::ResumeDevice() {
Log *log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "{0}", __FUNCTION__);
if (m_device_context == nullptr) {
LLDB_LOG(log, "{0} device context is null!", __FUNCTION__);
return;
}
m_device_context->Resume(m_pos_info);
m_pos_info.pc = -1;
}
Status AscendProcessLinux::SingleStep() {
Status error;
Log *log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "{0}", __FUNCTION__);
if (m_device_context == nullptr) {
return Status("device context is null!");
}
return m_device_context->SingleStep(m_pos_info);
return error;
}
void AscendProcessLinux::SetAicOnFocus(const uint32_t &core_id) {
m_pos_info.core_id = core_id;
m_pos_info.core_type = CoreType::AIC;
}
void AscendProcessLinux::SetAivOnFocus(const uint32_t &core_id) {
m_pos_info.core_id = core_id;
m_pos_info.core_type = CoreType::AIV;
}
void AscendProcessLinux::SetThreadOnFocus(const uint32_t &linear_idx) {
m_pos_info.thread_info.thread_id = linear_idx;
uint16_t dim_x = m_pos_info.thread_info.thread_dim_x;
uint16_t dim_y = m_pos_info.thread_info.thread_dim_y;
m_pos_info.thread_pos.x = linear_idx % dim_x;
m_pos_info.thread_pos.y = (linear_idx / dim_x) % dim_y;
m_pos_info.thread_pos.z = linear_idx / (dim_x * dim_y);
for (const auto &thread_up : m_threads) {
AscendThreadLinux *thread = GetThreadByID(thread_up->GetID());
if (!thread) {
continue;
}
if (thread_up->GetID() != GetID()) {
continue;
}
thread->SetStopThreadIdx(m_pos_info.thread_pos.x,
m_pos_info.thread_pos.y,
m_pos_info.thread_pos.z);
}
}
void AscendProcessLinux::SetSingleCoreRunFlag(bool isSingleCoreRun) {
m_pos_info.single_core_run = isSingleCoreRun;
}
bool AscendProcessLinux::ConsumeKernelBinary(DeviceBinaryInfo &info) {
if (m_device_binary_info_que.empty()) {
return false;
}
info = std::move(m_device_binary_info_que.front());
m_device_binary_info_que.pop();
return true;
}
void AscendProcessLinux::SetClientDeviceId(const int32_t device_id) {
m_client_device_id = device_id;
}
void AscendProcessLinux::SetVFStartPC(uint64_t start_pc) {
m_latest_vf_start_pc = start_pc;
}
Status AscendProcessLinux::GetDeviceInfo(DeviceInfo &info) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
Status error = m_device_context->GetDeviceInfo(info);
info.device_ids = m_device_ids;
return error;
}
Status AscendProcessLinux::GetCoresInfo(std::vector<CoreInfo> &info) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
Status error = m_device_context->GetCoresInfo(info);
if (error.Fail()) {
return error;
}
for (auto &core_info: info) {
if (core_info.pos_type == InterruptPosType::VEC_INTERRUPT_SIMD) {
FixSimdPC(core_info.pc);
}
}
m_cores_info = info;
return error;
}
Status AscendProcessLinux::GetCoreInfo(const uint32_t &idx, CoreInfo &info, bool flush_cache) {
Status error;
if (m_cores_info.empty() || flush_cache) {
error = GetCoresInfo(m_cores_info);
if (error.Fail()) {
return error;
}
}
if (idx >= m_cores_info.size()) {
error.SetErrorStringWithFormatv("out of index: idx={0}, size={1}",
idx, m_cores_info.size());
return error;
}
info = m_cores_info[idx];
return error;
}
Status AscendProcessLinux::GetWarpsInfo(std::vector<WarpInfo> &warps_info) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
return m_device_context->GetWarpsInfo(warps_info, m_pos_info);
}
Status AscendProcessLinux::GetStoppedCorePC(addr_t &pc) {
Status error;
if (m_cores_info.empty()) {
error = GetCoresInfo(m_cores_info);
if (error.Fail()) {
return error;
}
}
for (const auto &core_info: m_cores_info) {
if (core_info.core_id == m_pos_info.core_id && core_info.core_type == m_pos_info.core_type) {
pc = core_info.pc;
return error;
}
}
error.SetErrorStringWithFormatv("get pc failed: core_id={0}, size={1}",
m_pos_info.core_id, m_cores_info.size());
return error;
}
Status AscendProcessLinux::GetKernelInfo(KernelInfo &info) {
Status error;
size_t size;
if (m_kernel_name.size() >= sizeof(info.name) - 1) {
size = sizeof(info.name) - 1;
} else {
size = m_kernel_name.size();
}
m_kernel_name.copy(info.name, size, 0);
info.name[size] = '\0';
return error;
}
Status AscendProcessLinux::ReadDeviceRegisterValue(const RegisterInfo *reg_info, RegisterValue &value) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
if (m_pos_info.pc == UINT64_MAX) {
return Status("Current not stop in device");
}
Status error;
if (reg_info->kinds[lldb::eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) {
if (m_pos_info.pc != -1 &&
m_pos_info.first_stop_core_type == m_pos_info.core_type &&
m_pos_info.first_stop_core_id == m_pos_info.core_id) {
value.SetUInt64(m_pos_info.pc);
return error;
}
uint64_t pc = 0;
error = GetStoppedCorePC(pc);
if (error.Fail()) {
return error;
}
value.SetUInt64(pc);
return error;
}
return m_device_context->ReadRegister(reg_info, m_pos_info, value);
}
Status AscendProcessLinux::ReadDeviceRegisterList(std::vector<std::string> ®_list) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
return Status("Unsupport read device register list");
}
Status AscendProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
size_t &bytes_read, const MemoryReaderParamForServer ¶m) {
if (param.arch_type == llvm::Triple::hiipu64) {
if (m_device_context == nullptr) {
return Status("device context is null!");
}
Status status;
Log *log = GetLog(LLDBLog::Process);
if ((m_pos_info.core_type == CoreType::UNKNOWN_CORE_TYPE) &&
(param.address_class != DeviceAddressClass::GM)) {
LLDB_LOG(log,
"AscendProcessLinux::{0}, Core type is unknown. "
"only GM is allowed to be read. address_class={1}",
__FUNCTION__, static_cast<int32_t>(param.address_class));
status.SetErrorString("Core type is unknown, read memory from ascend device failed.");
return status;
} else if ((m_pos_info.core_type == CoreType::UNKNOWN_CORE_TYPE) &&
(param.address_class == DeviceAddressClass::GM)) {
bytes_read = m_device_context->ReadGlobalMemory(addr, size, buf);
if (bytes_read != size) {
status.SetErrorString("ReadGlobalMemory failed.");
}
return status;
}
MemoryTypeInfo memory_type_info{};
memory_type_info.address_class = param.address_class;
memory_type_info.element_size = param.element_size;
bytes_read = m_device_context->ReadMemory(addr, size, memory_type_info, m_pos_info, buf);
if (bytes_read != size) {
status.SetErrorString("Read memory from ascend device failed.");
}
return status;
}
return NativeProcessLinux::ReadMemoryWithoutTrap(addr, buf, size, bytes_read);
}
void AscendProcessLinux::MonitorSignal(const InterruptEvent ¶m) {
Log *log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "AscendProcessLinux::{0}, stream_id: {1}", __FUNCTION__, m_stream_id);
m_pos_info.Update(param);
m_cores_info.clear();
LLDB_LOG(log, "AscendProcessLinux::{0}, core_id: {1}, core_type: {2}",
__FUNCTION__, param.core_id, param.core_type);
for (const auto &thread_up : m_threads) {
AscendThreadLinux *thread = GetThreadByID(thread_up->GetID());
if (thread && thread_up->GetID() == GetID()) {
thread->SetStoppedByDeviceCtrlC(param);
std::unique_lock<std::mutex> lk(g_pause_mutex);
g_paused = true;
g_pause_cv.notify_all();
}
}
}
Status AscendProcessLinux::TaskKill() {
Status status;
Log *log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "AscendProcessLinux::{0}, stream_id: {1}",
__FUNCTION__, m_stream_id);
if (m_device_context == nullptr) {
status.SetErrorString("device context is null!");
return status;
}
status = m_device_context->TaskKill(m_stream_id);
if (status.Fail()) {
return status;
}
std::unique_lock<std::mutex> lk(g_pause_mutex);
if (g_pause_cv.wait_for(lk, std::chrono::seconds(1), [=](){return g_paused;})) {
LLDB_LOG(log, "Paused in device success");
} else {
status.SetErrorString("Paused in device failed, timeout!");
}
return status;
}
#endif