* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*/
#ifdef MS_DEBUGGER
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/LinuxProcMaps.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
#define private public
#define protected public
#include "Plugins/Process/Linux/AscendProcessLinux.h"
#include "Plugins/Process/Linux/AscendThreadLinux.h"
#undef private
#undef protected
#include "TestingSupport/Plugins/AscendProcessLinuxTestUtils.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "llvm/Testing/Support/Error.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_linux;
using namespace lldb_private::process_gdb_remote;
using namespace ::testing;
class FakeDeviceContext : public DeviceContext {
public:
FakeDeviceContext() : DeviceContext(0, 0) {
m_drv_fd = 3;
}
Status Init() override { return Status(); }
bool StartListenThread() override { return true; }
Status EnableDebugMode() override { return Status(); }
Status CheckRegisterAddr(CoreType core_type, uint64_t addr) const override {
return Status();
}
SocType GetSocType() override { return SocType::SOC_END; }
MemType GetStackMemType() const override { return MemType::OUT_MEM; }
size_t ReadGlobalMemory(lldb::addr_t addr, size_t size, void *data) override {
DebugInfo debug_info = {0, 1000, 0, 0};
DmaParam *param = (DmaParam*)debug_info.data;
std::vector<uint8_t> tmpData(size, 0);
param->host_addr = (uint64_t)&tmpData[0];
param->device_addr = addr;
param->size = size;
param->direction = DEVDRV_DMA_DEVICE_TO_HOST;
int32_t rtn = ioctl(m_drv_fd, CMD_GM_COPY, &debug_info);
if (rtn != 0) return 0;
std::copy(tmpData.begin(), tmpData.end(), static_cast<uint8_t*>(data));
return size;
}
size_t WriteGlobalMemory(lldb::addr_t addr, size_t size,
const void *data) override {
DebugInfo debug_info = {0, 1000, 0, 0};
DmaParam *param = (DmaParam*)debug_info.data;
uint8_t *data_ptr = static_cast<uint8_t *>(const_cast<void *>(data));
std::vector<uint8_t> tmpData(data_ptr, data_ptr + size);
param->host_addr = (uint64_t)&tmpData[0];
param->device_addr = addr;
param->size = size;
param->direction = DEVDRV_DMA_HOST_TO_DEVICE;
int32_t rtn = ioctl(m_drv_fd, CMD_GM_COPY, &debug_info);
if (rtn != 0) return 0;
return size;
}
Status InvalidInstrCache(const lldb::addr_t &addr,
const InterruptPosInfo &pos_info,
uint8_t redirect_ifu = 0) const override {
return Status();
}
};
class AscendProcessLinuxTest : public testing::Test {
public:
virtual void SetUp() {
fake_system_func.reset(new FakeSystemCallFunc());
EXPECT_CALL(*fake_system_func, open(_, _)).WillRepeatedly(__real_open);
EXPECT_CALL(*fake_system_func, ioctl(_, _, _)).WillRepeatedly(__real_ioctl);
}
virtual void TearDown() {
fake_system_func.reset();
}
static std::unique_ptr<FakeSystemCallFunc> fake_system_func;
};
std::unique_ptr<FakeSystemCallFunc> AscendProcessLinuxTest::fake_system_func;
extern "C"
{
int __wrap_open(const char* a, int b) {
if (AscendProcessLinuxTest::fake_system_func) {
return AscendProcessLinuxTest::fake_system_func->open(a, b);
} else {
return __real_open(a, b);
}
}
int __wrap_ioctl(int a, unsigned long int b, DebugInfo &c) {
if (AscendProcessLinuxTest::fake_system_func) {
return AscendProcessLinuxTest::fake_system_func->ioctl(a, b, c);
} else {
return __real_ioctl(a, b, c);
}
}
}
TEST_F(AscendProcessLinuxTest, HandleStubMessage) {
HostInfo::Initialize();
MainLoop mainloop;
NativeProcessLinux::Manager manager(mainloop);
GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager);
int terminal_fd = 3;
::pid_t pid = 11111;
ArchSpec arch = ArchSpec("hiipu64");
llvm::ArrayRef<::pid_t> tids;
auto process = std::make_unique<AscendProcessLinux>(
pid, terminal_fd, gdb_server,
arch, manager, tids);
std::string deviceMsg = "device_id:0;tgid:0;soc_version:test;";
Status status = process->m_parser.ParseMessage(deviceMsg);
ASSERT_TRUE(status.Success() || status.GetError() != 0);
}
int read_trap_opcodes(int a, unsigned long int b, DebugInfo &c) {
DmaParam *param = (DmaParam*)c.data;
uint8_t* tmpdata = (uint8_t*)param->host_addr;
uint8_t trap_code[4] = {0x00, 0x00, 0x80, 0x41};
for(int i = 0; i < 4; ++i) {
tmpdata[i] = trap_code[i];
}
return 0;
}
TEST_F(AscendProcessLinuxTest, SetBreakpoint) {
HostInfo::Initialize();
MainLoop mainloop;
NativeProcessLinux::Manager manager(mainloop);
GDBRemoteCommunicationServerLLGS gdb_server(mainloop, manager);
int terminal_fd = 3;
::pid_t pid = 11111;
ArchSpec arch = ArchSpec("hiipu64");
llvm::ArrayRef<::pid_t> tids;
auto process = std::make_unique<AscendProcessLinux>(
pid, terminal_fd, gdb_server,
arch, manager, tids);
std::string deviceMsg = "device_id:0;tgid:0;soc_version:test;";
process->m_parser.ParseMessage(deviceMsg);
std::string kernelMsg = "kernel_name:test;kernel_hash:0;pc_base_addr:47;";
process->m_parser.ParseMessage(kernelMsg);
process->m_device_context = std::make_shared<FakeDeviceContext>();
EXPECT_CALL(*fake_system_func, ioctl(_, CMD_GM_COPY, _))
.WillOnce(Return(0)).WillOnce(Return(0))
.WillOnce(read_trap_opcodes);
EXPECT_CALL(*fake_system_func, ioctl(_, CMD_SQ_SEND, _)).WillRepeatedly(Return(0));
EXPECT_CALL(*fake_system_func, ioctl(_, CMD_CQ_RECV, _)).WillRepeatedly(Return(0));
lldb::addr_t addr = 0x47;
uint32_t size = 8;
EXPECT_THAT_ERROR(process->SetBreakpoint(addr, size, llvm::Triple::ArchType::hiipu64, false).
ToError(), llvm::Succeeded());
}
#endif