Files
BusyRabbit/Content/Lua/Debugger/debugger_lib/libpdebug.cpp
2025-07-09 01:08:35 +08:00

1108 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Tencent is pleased to support the open source community by making LuaPanda available.
// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
// https://opensource.org/licenses/BSD-3-Clause
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
#include "libpdebug.h"
#include <ctime>
#include <list>
#include <map>
#include <string>
//using namespace std;
static int cur_run_state = 0; //当前运行状态, c 和 lua 都可能改变这个状态,要保持同步
static int cur_hook_state = 0; //当前hook状态 c 和 lua 都可能改变这个状态
static int logLevel = 1; //日志等级从lua同步
static int pathCaseSensitivity = 1; //大小写敏感标志位从lua同步
//static int autoPathMode = 0; //自动路径标是否开启志位
static int BPhit = 0; //BP命中标志位
static int stackdeep_counter = 0; //step用的栈深度计数器
static char hookLog[1024] = { 0 };
const char* debug_file_path; //debugger的文件路径
int debug_file_path_len;
const char* tools_file_path; //tools的文件路径
int tools_file_path_len;
char config_ext[32] = ""; //后缀从lua同步
const char* config_cwd = ""; //cwd(从lua同步)
const char* config_tempfile_path = "";
time_t recvMsgSeconds = 0;
const char* last_source;
int ar_current_line = 0;
int ar_def_line = 0;
int ar_lastdef_line = 0;
int bp_twice_check_res = 1;
int lua_debugger_ver = 0; // luapanda.lua的版本便于做向下兼容
struct path_transfer_node;
struct breakpoint;
// 路径缓存队列 getinfo -> format
std::list<path_transfer_node*> getinfo_to_format_cache;
// 存放断点mapkey为source
std::map<std::string, std::map<int, breakpoint> > all_breakpoint_map;
enum run_state
{
DISCONNECT = 0,
WAIT_CMD = 1,
STOP_ON_ENTRY = 2,
RUN = 3,
STEPOVER = 4,
STEPIN = 5,
STEPOUT = 6,
STEPOVER_STOP = 7,
STEPIN_STOP = 8,
STEPOUT_STOP = 9,
HIT_BREAKPOINT = 10
};
enum hook_state
{
DISCONNECT_HOOK = 0,
LITE_HOOK = 1, //全局无断点
MID_HOOK = 2, //全局有断点,本文件无断点
ALL_HOOK = 3,
};
enum hook_event
{
CALL = 0,
RETURN =1,
LINE =2,
TAILRET=4
};
enum breakpoint_type
{
CONDITION_BREAKPOINT = 0,
LOG_POINT,
LINE_BREAKPOINT
};
//用来缓存路径的结构体
struct path_transfer_node{
std::string src;
std::string dst;
path_transfer_node(std::string _src, std::string _dst){
src = _src;
dst = _dst;
}
};
// 断点信息
struct breakpoint {
breakpoint_type type;
std::string info;
};
struct debug_auto_stack {
explicit debug_auto_stack(lua_State* l) {
this->L = l;
this->top = lua_gettop(L);
}
~debug_auto_stack() {
lua_settop(this->L, this->top);
}
lua_State* L;
int top;
};
//内部方法声明
void debug_hook_c(lua_State *L, lua_Debug *ar);
void check_hook_state(lua_State *L, const char* source, int current_line, int def_line, int last_line, int event = -1);
void print_to_vscode(lua_State *L, const char* msg, int level = 0);
void load(lua_State* L);
//打印断点信息
void print_all_breakpoint_map(lua_State *L, int print_level = 0) {
if (print_level < logLevel) {
return;
}
std::map<std::string, std::map<int, breakpoint> >::iterator iter1;
std::map<int, breakpoint>::iterator iter2;
std::string log_message = "[breakpoints in chook:]\n";
for (iter1 = all_breakpoint_map.begin(); iter1 != all_breakpoint_map.end(); ++iter1) {
log_message += iter1->first;
log_message += '\n';
for (iter2 = iter1->second.begin(); iter2 != iter1->second.end(); ++iter2) {
log_message += std::string(" line: ");
log_message += std::to_string(iter2->first);
log_message += std::string(" type: ");
switch (iter2->second.type) {
case CONDITION_BREAKPOINT:
log_message += std::string("condition breakpoint info: ");
log_message += iter2->second.info;
break;
case LOG_POINT:
log_message += std::string("log point info: ");
log_message += iter2->second.info;
break;
case LINE_BREAKPOINT:
log_message += std::string("line breakpoint info: ");
log_message += iter2->second.info;
break;
default:
log_message += std::string("Invalid breakpoint type!");
log_message += std::to_string(iter2->second.type);
break;
}
log_message += '\n';
}
}
print_to_vscode(L, log_message.c_str(), print_level);
}
//push_arg Template
template <typename T>
void push_arg(lua_State *L, T value);
template <>
void push_arg(lua_State *L, int value){
lua_pushnumber(L, value);
}
template <>
void push_arg(lua_State *L, double value){
lua_pushnumber(L, value);
}
template <>
void push_arg(lua_State *L, const char * value){
lua_pushstring(L, value);
}
void push_args(lua_State *L){}
//push_arg Template End
template <typename T>
void push_arg(lua_State *L, T value){
push_arg<T>(L, value);
}
template <typename T, typename ... ARGS>
void push_args(lua_State *L, T value ,ARGS... args){
push_arg<T>(L, value);
push_args(L, std::forward<ARGS>(args) ...);
}
//push_args End
template <typename ... ARGS>
int call_lua_function(lua_State *L, const char * lua_function_name, int retCount , ARGS... args){
lua_getglobal(L, LUA_DEBUGGER_NAME);
if (!lua_istable(L, -1)) {
const char *err_msg = "[C Module Error]:call_lua_function Get LUA_DEBUGGER_NAME error.\n";
print_to_vscode(L, err_msg, 2);
return -1;
}
lua_getfield(L, -1, lua_function_name);
if (!lua_isfunction(L, -1)) {
char err_msg[100];
snprintf(err_msg, sizeof(err_msg), "[C Module Error]:call_lua_function Get lua function '%s' error\n.", lua_function_name);
print_to_vscode(L, err_msg, 2);
return -1;
}
push_args(L, args...);
int err_code = lua_pcall(L, sizeof...(args), retCount, 0);
if (err_code) {
char err_msg[1024];
const char *lua_error = lua_tostring(L, -1);
snprintf(err_msg, sizeof(err_msg), "[C Module Error]:call_lua_function Call '%s' error. ErrorCode: %d, ErrorMessage: %s.\n", lua_function_name, err_code, lua_error);
print_to_vscode(L, err_msg, 2);
lua_pop(L, 1);
return err_code;
}
return 0;
}
//------------Lua同步数据接口------------
//lua层主动清除路径缓存
extern "C" int clear_pathcache(lua_State *L)
{
getinfo_to_format_cache.clear();
return 0;
}
//lua主动调用从c获取current_hook_state状态
extern "C" int get_libhook_state(lua_State *L)
{
lua_pushnumber(L, cur_hook_state);
return 1;
}
//lua主动调用从c获取last_source
extern "C" int get_last_source(lua_State *L)
{
lua_pushstring(L, last_source);
return 1;
}
//同步luapanda.lua的版本号
extern "C" int sync_lua_debugger_ver(lua_State *L)
{
lua_debugger_ver = static_cast<int>(luaL_checkinteger(L, 1));
return 0;
}
//同步断点命中标识
extern "C" int sync_bp_hit(lua_State *L) {
if(cur_hook_state == DISCONNECT_HOOK){
//返回参数个数
return 0;
}
BPhit = static_cast<int>(luaL_checkinteger(L, 1));
return 0;
}
//同步设置 -- 日志等级, 是否debug代码段, 是否使用忽略大小写
extern "C" int sync_config(lua_State *L) {
logLevel = static_cast<int>(luaL_checkinteger(L, 1));
pathCaseSensitivity = static_cast<int>(luaL_checkinteger(L, 2));
// autoPathMode = static_cast<int>(luaL_optinteger(L, 3, 0));
return 0;
}
//同步临时文件路径
extern "C" int sync_tempfile_path(lua_State *L) {
config_tempfile_path = luaL_checkstring(L, 1);
return 0;
}
//同步临时文件路径
extern "C" int set_bp_twice_check_res(lua_State *L) {
bp_twice_check_res = luaL_checknumber(L, 1);
return 0;
}
//lua 获取版本号
extern "C" int sync_getLibVersion(lua_State *L) {
lua_pushstring(L, HOOK_LIB_VERSION);
lua_pushnumber(L, LUA_VERSION_NUM);
return 2;
}
//同步文件后缀
extern "C" int sync_file_ext(lua_State *L) {
const char *ext = luaL_checkstring(L, 1);
snprintf(config_ext, sizeof(config_ext), ".%s", ext);
return 0;
}
//debugger路径
extern "C" int sync_debugger_path(lua_State *L) {
debug_file_path = luaL_checkstring(L, 1);
debug_file_path_len = strlen(debug_file_path);
return 0;
}
//tools路径
extern "C" int sync_tools_path(lua_State *L) {
tools_file_path = luaL_checkstring(L, 1);
tools_file_path_len = strlen(tools_file_path);
return 0;
}
//cwd
extern "C" int sync_cwd(lua_State *L) {
config_cwd = luaL_checkstring(L, 1);
return 0;
}
//同步运行状态给Lua C->lua
void sync_runstate_toLua(lua_State *L, int state) {
debug_auto_stack _tt(L);
cur_run_state = state;
call_lua_function(L, "changeRunState", 0, state, 1);
return;
}
//这个接口给lua调用用来同步状态 lua->C
extern "C" int lua_set_runstate(lua_State *L) {
cur_run_state = static_cast<int>(luaL_checkinteger(L, 1));
return 0;
}
//根据运行状态修改hook状态
void sethookstate(lua_State *L, int state){
cur_hook_state = state;
switch(state){
case DISCONNECT_HOOK:
lua_sethook(L, debug_hook_c, LUA_MASKRET , 1000000);
break;
case LITE_HOOK:
lua_sethook(L, debug_hook_c, LUA_MASKRET , 0);
break;
case MID_HOOK:
lua_sethook(L, debug_hook_c, LUA_MASKCALL | LUA_MASKRET , 0);
break;
case ALL_HOOK:
lua_sethook(L, debug_hook_c, LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 0);
break;
}
}
//这个接口给lua调用用来同步hook状态 lua->C
extern "C" int lua_set_hookstate(lua_State *L) {
cur_hook_state = static_cast<int>(luaL_checkinteger(L, 1));
sethookstate(L, cur_hook_state);
return 0;
}
void print_to_vscode(lua_State *L, const char* msg, int level) {
if ( DISCONNECT != cur_run_state && level >= logLevel) {
//打印
call_lua_function(L, "printToVSCode", 0, msg, level);
}
}
//获取路径(带缓存)
const char* getPath(lua_State *L,const char* source){
debug_auto_stack _tt(L);
if(source == nullptr){
print_to_vscode(L, "[C Module Error]: getPath Exception: source == nullptr", 2);
return "";
}
//检查缓存
for(auto iter = getinfo_to_format_cache.begin();iter != getinfo_to_format_cache.end();iter++)
{
if(!strcmp((*iter)->src.c_str(), source)){
return (*iter)->dst.c_str();
}
}
//若缓存中没有到lua中转换
int lua_ret = call_lua_function(L, "getPath", 1 , source);
if (lua_ret != 0) {
return "";
}
const char* retSource = lua_tostring(L, -1);
//加入缓存,返回
path_transfer_node *nd = new path_transfer_node(source, retSource );
getinfo_to_format_cache.push_back(nd);
return retSource;
}
// 向 lua 中 checkRealHitBreakpoint 查询是否在缓存中,以判断是否真正命中断点
const int checkRealHitBreakpoint(lua_State *L,const char* source, int line){
debug_auto_stack _tt(L);
if(source == nullptr){
print_to_vscode(L, "[C Module Error]: checkRealHitBreakpoint Exception: source == nullptr", 2);
return 0;
}
//若缓存中没有到lua中转换
int lua_ret = call_lua_function(L, "checkRealHitBreakpoint", 1 , source, line);
if (lua_ret != 0) {
return 0;
}
int realHit = lua_toboolean(L, -1);
return realHit;
}
//供lua调用,把断点列表同步给c端
extern "C" int sync_breakpoints(lua_State *L) {
debug_auto_stack _tt(L);
//取数组
lua_getglobal(L, LUA_DEBUGGER_NAME); //-1 LuaPanda
if (!lua_istable(L, -1)) {
print_to_vscode(L, "[C Module Error] debug_ishit_bk get LUA_DEBUGGER_NAME error", 2);
return -1;
}
lua_getfield(L, -1, "breaks");
if (!lua_istable(L, -1)) {
print_to_vscode(L, "[C Module Error] debug_ishit_bk get breaks error", 2);
return -1;
}
//遍历breaks
all_breakpoint_map.clear();
lua_pushnil(L);//breaks nil
while (lua_next(L, -2)) {
//breaks kstring v(table)
const char* source = luaL_checkstring(L, -2);
std::map<int, breakpoint> file_breakpoint_map;
lua_pushnil(L);//kv, nil
while (lua_next(L, -2)) {
if(lua_debugger_ver >= 30150){
lua_pushnil(L);//kv, nil
while (lua_next(L, -2)) {
//k,v,k,v
lua_getfield(L, -1, "line"); //k,v,k,v,line
int line = (int)lua_tointeger(L, -1);
lua_pop(L, 1); // line
lua_getfield(L, -1, "type");
int type = (int)lua_tointeger(L, -1);
lua_pop(L, 1); // type
struct breakpoint bp;
switch (type) {
case CONDITION_BREAKPOINT: {
bp.type = CONDITION_BREAKPOINT;
lua_getfield(L, -1, "condition");
const char* condition = luaL_checkstring(L, -1);
lua_pop(L, 1); // condition
bp.info = condition;
break;
}
case LOG_POINT: {
bp.type = LOG_POINT;
lua_getfield(L, -1, "logMessage");
const char* log_message = luaL_checkstring(L, -1);
lua_pop(L, 1); // logMessage
bp.info = log_message;
break;
}
case LINE_BREAKPOINT:
bp.type = LINE_BREAKPOINT;
bp.info = std::to_string(line);
break;
default:
print_to_vscode(L, "[C Module Error] Invalid breakpoint type!", 2);
return -1;
}
file_breakpoint_map[line] = bp;
lua_pop(L, 1);//value
//k,v,k
}
lua_pop(L, 1);//value
}else{
// 兼容 < 3.1.5 版本的luapanda.lua
//k,v,k,v
lua_getfield(L, -1, "line"); //k,v,k,v,line
int line = (int)lua_tointeger(L, -1);
lua_pop(L, 1); // line
lua_getfield(L, -1, "type");
int type = (int)lua_tointeger(L, -1);
lua_pop(L, 1); // type
struct breakpoint bp;
switch (type) {
case CONDITION_BREAKPOINT: {
bp.type = CONDITION_BREAKPOINT;
lua_getfield(L, -1, "condition");
const char* condition = luaL_checkstring(L, -1);
lua_pop(L, 1); // condition
bp.info = condition;
break;
}
case LOG_POINT: {
bp.type = LOG_POINT;
lua_getfield(L, -1, "logMessage");
const char* log_message = luaL_checkstring(L, -1);
lua_pop(L, 1); // logMessage
bp.info = log_message;
break;
}
case LINE_BREAKPOINT:
bp.type = LINE_BREAKPOINT;
bp.info = std::to_string(line);
break;
default:
print_to_vscode(L, "[C Module Error] Invalid breakpoint type!", 2);
return -1;
}
file_breakpoint_map[line] = bp;
lua_pop(L, 1);//value
}
}
all_breakpoint_map[std::string(source)] = file_breakpoint_map;
//k,v
lua_pop(L, 1);//外部每次循环
//k
}
lua_pop(L, 1);//外部每次循环
print_all_breakpoint_map(L);
check_hook_state(L, last_source, ar_current_line ,ar_def_line, ar_lastdef_line);
return 0;
}
//断点命中判断
int debug_ishit_bk(lua_State *L, const char * curPath, int current_line) {
debug_auto_stack _tt(L);
// 获取标准路径[文件名.后缀]
const char *standardPath = getPath(L, curPath);
// 判断是否存在同名文件
std::map<std::string, std::map<int, struct breakpoint> >::const_iterator const_iter1 = all_breakpoint_map.find(std::string(standardPath));
if (const_iter1 == all_breakpoint_map.end()) {
return 0;
}
// c++ all_breakpoint_map 的数据结构保持不变和lua不一样
// 根据是否存在相同行号
std::map<int, struct breakpoint>::const_iterator const_iter2 = const_iter1->second.find(current_line);
if (const_iter2 == const_iter1->second.end()) {
return 0;
}
if(lua_debugger_ver >= 30160){
// luapanda.lua >= 3.1.6 才会调用
// 初步命中到lua层中检测是否真正命中以及断点类型
int lua_ret = call_lua_function(L, "isHitBreakpoint", 1, standardPath, curPath, current_line);
if (lua_ret != 0) {
// 调用出错时,按命中处理
return 1;
}
int realHit = lua_toboolean(L, -1);
return realHit;
}else{
// 兼容旧版本
// 条件断点
if (const_iter2->second.type == CONDITION_BREAKPOINT) {
std::string condition = const_iter2->second.info;
int lua_ret = call_lua_function(L, "IsMeetCondition", 1, condition.c_str());
if (lua_ret != 0) {
return 0;
}
// if (!lua_isboolean(L, -1)) {
// print_to_vscode(L, "[Debug Lib Error] debug_ishit_bk process condition expression result error!", 2);
// return 0;
// }
int is_meet_condition = lua_toboolean(L, -1);
lua_pop(L, 1);
return is_meet_condition;
}
// 记录点
if (const_iter2->second.type == LOG_POINT) {
std::string log_message = "[log point output]: ";
log_message.append(const_iter2->second.info);
print_to_vscode(L, log_message.c_str() , 1);
return 0;
}
return 1;
}
}
//判断字符串是否匹配[string "
int isCodeSection(char *str) {
if (strlen(str) > 9) {
if (str[0] == '[' && str[7] == ' ' && str[8] == '"') {
return 1;
}
}
return 0;
}
//断点命中判断 retuen : is_hit
int breakpoint_process(lua_State *L, lua_Debug *ar){
int is_hit = 0;
if (ar->event == LINE) {
is_hit = debug_ishit_bk(L, ar->source, ar->currentline);
// 同名文件可能会命中假断点 folder1/a.lua 和 folder2/a.lua 截取文件名都是 a.lua, 可能导致命中混淆
if(is_hit && lua_debugger_ver >= 30160){
// luapanda.lua >= 3.1.6 版本才会调用
is_hit = checkRealHitBreakpoint(L, ar->source, ar->currentline);
}
if (is_hit == 1 || BPhit) {
print_to_vscode(L, "[C Module] Breakpoint hit!");
int record_stackdeep_counter = stackdeep_counter;
int record_cur_run_state = cur_run_state;
stackdeep_counter = 0;
sync_runstate_toLua(L, HIT_BREAKPOINT);
bp_twice_check_res = 1;
//c层掌握 STEPOVER 计数器状态机放在lua层c主要去读毕竟C作为lua的扩展
//通知lua层,lua层阻塞发消息
if(BPhit){
BPhit = 0;
call_lua_function(L, "SendMsgWithStack", 0, "stopOnCodeBreakpoint");
}else{
call_lua_function(L, "SendMsgWithStack", 0, "stopOnBreakpoint");
if( bp_twice_check_res == 0 ){
is_hit = 0;
stackdeep_counter = record_stackdeep_counter;
sync_runstate_toLua(L, record_cur_run_state);
}
}
}
}
return is_hit;
}
//单步处理
void step_process(lua_State *L, lua_Debug *ar){
//目前没有判断jump flag
if (cur_run_state == STEPOVER) {
if (ar->event == LINE && stackdeep_counter <= 0) {
sync_runstate_toLua(L, STEPOVER_STOP);
call_lua_function(L, "SendMsgWithStack", 0,"stopOnStep");
}
else if (ar->event == CALL) {
stackdeep_counter++;
}
//5.3 的tailcall暂时不需要处理。
else if (ar->event == RETURN) {
if (stackdeep_counter != 0) {
stackdeep_counter--;
}
}
}
else if (cur_run_state == STEPIN) {
if (ar->event == LINE) {
sync_runstate_toLua(L, STEPIN_STOP);
call_lua_function(L, "SendMsgWithStack", 0,"stopOnStepIn");
}
}
else if (cur_run_state == STEPOUT) {
if (ar->event == LINE) {
if (stackdeep_counter <= -1) {
stackdeep_counter = 0;
sync_runstate_toLua(L, STEPOUT_STOP);
call_lua_function(L, "SendMsgWithStack", 0,"stopOnStepOut");
}
}
else if (ar->event == CALL) {
stackdeep_counter++;
}
//5.3 的tailcall暂时不需要处理。
else if (ar->event == RETURN) {
stackdeep_counter--;
}
}
}
// 无需reconnect返回1 需要重连时返回0
int hook_process_reconnect(lua_State *L){
time_t currentSecs = time(static_cast<time_t*>(NULL));
if(cur_hook_state == DISCONNECT_HOOK){
if (currentSecs - recvMsgSeconds > 1) {
call_lua_function(L, "reConnect", 0);
recvMsgSeconds = currentSecs;
}
return 0;
}
return 1;
}
void litehook_recv_message(lua_State *L){
time_t currentSecs = time(static_cast<time_t*>(NULL));
//2.定时接收消息 -- 这里的状态不只是run
if (cur_hook_state == LITE_HOOK && currentSecs - recvMsgSeconds > 1) {
call_lua_function(L, "debugger_wait_msg", 0);
recvMsgSeconds = currentSecs;
}
}
void hook_process_recv_message(lua_State *L){
time_t currentSecs = time(static_cast<time_t*>(NULL));
if ((cur_run_state == RUN ||
cur_run_state == STEPOVER ||
cur_run_state == STEPIN ||
cur_run_state == STEPOUT)
&& currentSecs - recvMsgSeconds > 1) {
call_lua_function(L, "debugger_wait_msg", 0);
recvMsgSeconds = currentSecs;
}
}
int hook_process_cfunction(lua_State *L, lua_Debug *ar){
if (!(strcmp(ar->what, "C")) || ar->currentline < 0) {
//Lua5.1 tail return会走到这里
if(!(strcmp(ar->source, "=(tail call)")) && ar -> event == TAILRET && (cur_run_state == STEPOVER || cur_run_state == STEPOUT )){
stackdeep_counter --;
}
//5.1
return 0;
}
return 1;
}
int hook_process_code_section(lua_State *L, lua_Debug *ar){
//测试[string ...]形式的路径
int isCodeSec = isCodeSection(ar->short_src);
if (isCodeSec == 1) {
//short_src是[string ]开头
if(strchr(ar->source, '\n') || strchr(ar->source, ';') || strchr(ar->source, '=')){
print_to_vscode(L, "hook jump Code String");
return 0;
}
}
return 1;
}
//检查函数中是否有断点。int check_has_breakpoint 0:全局无断点 , 1:全局有断点但本文件中无断点 , 2:本文件中有断点 , 3:函数中有断点
int checkHasBreakpoint(lua_State *L, const char * src1, int current_line, int sline , int eline){
debug_auto_stack tt(L);
const char *src = getPath(L, src1);
if(!strcmp(src,"")){
// 路径完全一致
return ALL_HOOK;
}
if(all_breakpoint_map.empty() == true) {
// 全局没有断点
return LITE_HOOK;
}
std::map<std::string, std::map<int, breakpoint> >::iterator iter1;
for (iter1 = all_breakpoint_map.begin(); iter1 != all_breakpoint_map.end(); ++iter1) {
if (iter1->first == std::string(src)) {
// compare()
return ALL_HOOK;
}
}
//文件没有断点,MIDHOOK
return MID_HOOK;
}
void check_hook_state(lua_State *L, const char* source , int current_line, int def_line, int last_line ,int event){
if (source == NULL) {
return;
}
if(cur_run_state == RUN && cur_hook_state != DISCONNECT_HOOK){
int stats = checkHasBreakpoint(L, source, current_line, def_line, last_line);
if(stats == LITE_HOOK){
sethookstate(L, LITE_HOOK);
}else if(stats == MID_HOOK){
sethookstate(L, MID_HOOK);
}else if (stats == ALL_HOOK){
sethookstate(L, ALL_HOOK);
}
if( (event == RETURN || event == TAILRET) && cur_hook_state == MID_HOOK){
sethookstate(L, ALL_HOOK);
}
}
}
//这个函数要获取的消息 当前状态,断点列表
void debug_hook_c(lua_State *L, lua_Debug *ar) {
debug_auto_stack _tt(L);
if(!hook_process_reconnect(L)) return;
if(cur_hook_state == LITE_HOOK) {
litehook_recv_message(L);
return;
}
hook_process_recv_message(L);
if (lua_getinfo(L, "Slf", ar) != 0) {
//if in c function , return
if(!hook_process_cfunction(L, ar)) return;
//if in debugger , return
int source_len = strlen(ar->source);
if (debug_file_path_len == source_len) {
if (!strcmp(debug_file_path, ar->source)) return;
}
if (tools_file_path_len == source_len) {
if (!strcmp(tools_file_path, ar->source)) return;
}
//slua "temp buffer"
if (11 == source_len) {
if (!strcmp("temp buffer", ar->source)) return;
}
//xlua "chunk"
if (5 == source_len) {
if (!strcmp("chunk", ar->source)) return;
}
//code section
if(!hook_process_code_section(L, ar)) return;
//output debug info
if (logLevel == 0) {
snprintf(hookLog, sizeof(hookLog), "[hook state] event:%d | source: %s | short_src: %s | line:%d | defined:%d | laseDefined:%d | currentState:%d | currentHookState:%d \n", ar->event, ar->source, ar->short_src, ar->currentline, ar->linedefined, ar->lastlinedefined, cur_run_state, cur_hook_state);
print_to_vscode(L, hookLog);
}
//hook_state
last_source = ar->source;
ar_def_line = ar->linedefined;
ar_lastdef_line = ar->lastlinedefined;
ar_current_line = ar->currentline;
int is_hit = breakpoint_process(L, ar); //断点命中标记位 //line + 预判
//STOP_ON_ENTRY
int stop_on_entry = 0;
if (cur_run_state == STOP_ON_ENTRY && is_hit != 1) {
//STOP_ON_ENTRY
if (ar->event == LINE) {
//命中
stop_on_entry = 1;
stackdeep_counter = 0;
call_lua_function(L, "SendMsgWithStack", 0,"stopOnEntry");
}
}
if (is_hit == 1 || stop_on_entry == 1) {
return;
}
step_process(L, ar);
check_hook_state(L, last_source, ar_current_line, ar_def_line, ar_lastdef_line, ar->event);
}
}
//结束hook
extern "C" int endHook(lua_State *L)
{
cur_hook_state = DISCONNECT_HOOK;
lua_sethook(L, NULL, 0, 0);
all_breakpoint_map.clear();
return 0;
}
static luaL_Reg libpdebug[] = {
{ "sync_breakpoints", sync_breakpoints }, //lua同步断点给c同步发生在新增、删除断点连接开始时
{ "lua_set_hookstate", lua_set_hookstate }, //lua设置hook状态。lua中发生状态切换时同步到C
{ "lua_set_runstate", lua_set_runstate }, //同步运行状态
{ "sync_debugger_path", sync_debugger_path }, //同步debugger文件路径
{ "sync_tools_path", sync_tools_path }, //同步debugger文件路径
{ "sync_config", sync_config }, //同步日志等级
{ "sync_cwd", sync_cwd }, //同步cwd
{ "sync_file_ext", sync_file_ext }, //同步文件后缀
{ "sync_getLibVersion", sync_getLibVersion }, //hook version
{ "sync_bp_hit", sync_bp_hit }, //set BP lua向C同步状态
{ "sync_tempfile_path", sync_tempfile_path }, //sync_tempfile_path
{ "endHook", endHook }, //结束hook停止调试
{ "get_libhook_state", get_libhook_state },
{ "get_last_source", get_last_source },
{ "clear_pathcache", clear_pathcache },
{ "set_bp_twice_check_res", set_bp_twice_check_res },
{ "sync_lua_debugger_ver", sync_lua_debugger_ver },
{ NULL, NULL }
};
#ifdef USE_SOURCE_CODE
extern "C" void pdebug_init(lua_State* L) {
debug_auto_stack _tt(L);
//把libhook压入_G里面方法填上
lua_newtable(L);
for (size_t i = 0; i < sizeof(libpdebug) / sizeof(luaL_Reg); i++) {
if (libpdebug[i].name == NULL) {
break;
}
lua_pushcfunction(L, libpdebug[i].func);
lua_setfield(L, -2, libpdebug[i].name);
}
lua_setglobal(L, "luapanda_chook");
}
#else // !USE_SOURCE_CODE
#ifdef _WIN32
#define DEBUG_API extern "C" __declspec(dllexport)
#else
#define DEBUG_API extern "C"
#endif
DEBUG_API int luaopen_libpdebug(lua_State* L)
{
#ifdef _WIN32
load(L);
#endif
#ifdef _WIN32
#if LUA_VERSION_NUM == 501
// 在windows平台编译时luaL_register等是函数指针运行时查找。
if(luaL_register != NULL){
luaL_register(L, "libpdebug", libpdebug);
}
#elif LUA_VERSION_NUM > 501
if(lua_createtable != NULL && luaL_setfuncs != NULL){
lua_newtable(L);
luaL_setfuncs(L, libpdebug, 0);
}
#endif // LUA_VERSION_NUM
#else // !defined(_WIN32))
#if LUA_VERSION_NUM == 501
// 在macOS编译时luaL_register等是函数定义在lua.h中。
luaL_register(L, "libpdebug", libpdebug);
#elif LUA_VERSION_NUM > 501
lua_newtable(L);
luaL_setfuncs(L, libpdebug, 0);
#endif // LUA_VERSION_NUM
#endif // ifdef _WIN32
return 1;
}
#endif // USE_SOURCE_CODE
//WIN32下函数处理方法
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
//slua-ue template function
#if LUA_VERSION_NUM > 501
template<typename T, typename RET>
RET callLuaFunction(lua_State *L) {
return getInter()->T(L);
}
template<typename T, T>
struct Invoker;
template<typename T, typename RET, typename... ARGS, RET(T::*F)(ARGS...)>
struct Invoker<RET(T::*)(ARGS...), F> {
static RET invoke(const ARGS&... args) {
return (getInter()->*F)(args...);
}
};
template<typename T, typename... ARGS, void(T::*F)(ARGS...)>
struct Invoker<void(T::*)(ARGS...), F> {
static void invoke(const ARGS&... args) {
return (getInter()->*F)(args...);
}
};
template<typename T, T t>
struct LuaCppBinding;
template<typename T, typename RET, typename... ARGS, RET(T::*F)(ARGS...)>
struct LuaCppBinding<RET(T::*)(ARGS...), F> {
static RET luaCFunction(ARGS... args) {
return Invoker<decltype(F), F>::invoke(args...);
}
};
template<typename T, typename... ARGS, void(T::*F)(ARGS...)>
struct LuaCppBinding<void(T::*)(ARGS...), F> {
static void luaCFunction(ARGS... args) {
return Invoker<decltype(F), F>::invoke(args...);
}
};
#endif // LUA_VERSION_NUM > 501
void Slua_UE_find_function()
{ //slua - ue Lua 5.3
#if LUA_VERSION_NUM > 501
#define SLUABINDING(f) LuaCppBinding<decltype(f), f>::luaCFunction;
lua_version = SLUABINDING(&slua::LuaInterface::lua_version);
lua_pushstring = SLUABINDING(&slua::LuaInterface::lua_pushstring);
lua_gettop = (luaDLL_gettop)SLUABINDING(&slua::LuaInterface::lua_gettop);
lua_settop = (luaDLL_settop)SLUABINDING(&slua::LuaInterface::lua_settop);
lua_pcallk = SLUABINDING(&slua::LuaInterface::lua_pcallk);
lua_pushnumber = (luaDLL_pushnumber)SLUABINDING(&slua::LuaInterface::lua_pushnumber);
luaL_checklstring = SLUABINDING(&slua::LuaInterface::luaL_checklstring);
lua_tolstring = (luaDLL_tolstring)SLUABINDING(&slua::LuaInterface::lua_tolstring);
lua_type = (luaDLL_type)SLUABINDING(&slua::LuaInterface::lua_type);
lua_tointegerx = (luaDLL_tointegerx)SLUABINDING(&slua::LuaInterface::lua_tointegerx);
lua_pushnil = (luaDLL_pushnil)SLUABINDING(&slua::LuaInterface::lua_pushnil);
lua_getfield = (luaDLL_getfield)SLUABINDING(&slua::LuaInterface::lua_getfield);
lua_next = (luaDLL_next)SLUABINDING(&slua::LuaInterface::lua_next);
lua_getinfo = (luaDLL_getinfo)SLUABINDING(&slua::LuaInterface::lua_getinfo);
lua_sethook = (luaDLL_sethook)SLUABINDING(&slua::LuaInterface::lua_sethook);
luaL_checknumber = SLUABINDING(&slua::LuaInterface::luaL_checknumber);
lua_createtable = (luaDLL_createtable)SLUABINDING(&slua::LuaInterface::lua_createtable);
luaL_setfuncs = SLUABINDING(&slua::LuaInterface::luaL_setfuncs);
lua_getglobal = SLUABINDING(&slua::LuaInterface::lua_getglobal);
lua_toboolean = (luaDLL_toboolean)SLUABINDING(&slua::LuaInterface::lua_toboolean);
#endif
}
void general_find_function() {
//slua, xlua
#if LUA_VERSION_NUM == 501
luaL_register = (luaLDLL_register)GetProcAddress(hInstLibrary, "luaL_register");//501
lua_pcall = (luaDLL_pcall)GetProcAddress(hInstLibrary, "lua_pcall");//501
lua_tointeger = (luaDLL_tointeger)GetProcAddress(hInstLibrary, "lua_tointeger");//501
#endif
luaL_checkinteger = (luaDLL_checkinteger)GetProcAddress(hInstLibrary, "luaL_checkinteger");
lua_version = (luaDLL_version)GetProcAddress(hInstLibrary, "lua_version");
lua_pushstring = (luaDLL_pushstring)GetProcAddress(hInstLibrary, "lua_pushstring");
lua_gettop = (luaDLL_gettop)GetProcAddress(hInstLibrary, "lua_gettop");
lua_settop = (luaDLL_settop)GetProcAddress(hInstLibrary, "lua_settop");
lua_pushnumber = (luaDLL_pushnumber)GetProcAddress(hInstLibrary, "lua_pushnumber");
luaL_checklstring = (luaDLL_checklstring)GetProcAddress(hInstLibrary, "luaL_checklstring");
lua_tolstring = (luaDLL_tolstring)GetProcAddress(hInstLibrary, "lua_tolstring");
lua_type = (luaDLL_type)GetProcAddress(hInstLibrary, "lua_type");
lua_pushnil = (luaDLL_pushnil)GetProcAddress(hInstLibrary, "lua_pushnil");
lua_getfield = (luaDLL_getfield)GetProcAddress(hInstLibrary, "lua_getfield");
lua_next = (luaDLL_next)GetProcAddress(hInstLibrary, "lua_next");
lua_getinfo = (luaDLL_getinfo)GetProcAddress(hInstLibrary, "lua_getinfo");
lua_sethook = (luaDLL_sethook)GetProcAddress(hInstLibrary, "lua_sethook");
luaL_checknumber = (luaDLL_checknumber)GetProcAddress(hInstLibrary, "luaL_checknumber");
lua_pushinteger = (luaDLL_pushinteger)GetProcAddress(hInstLibrary, "lua_pushinteger");
lua_toboolean = (luaDLL_toboolean)GetProcAddress(hInstLibrary, "lua_toboolean");
//5.3
#if LUA_VERSION_NUM > 501
lua_pcallk = (luaDLL_pcallk)GetProcAddress(hInstLibrary, "lua_pcallk");
lua_tointegerx = (luaDLL_tointegerx)GetProcAddress(hInstLibrary, "lua_tointegerx");
lua_createtable = (luaDLL_createtable)GetProcAddress(hInstLibrary, "lua_createtable");
luaL_setfuncs = (luaDLL_setfuncs)GetProcAddress(hInstLibrary, "luaL_setfuncs");
lua_getglobal = (luaDLL_getglobal)GetProcAddress(hInstLibrary, "lua_getglobal");
#endif
}
void load(lua_State* L) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
//load fail
return;
}
MODULEENTRY32 mi;
mi.dwSize = sizeof(MODULEENTRY32);
BOOL bRet = Module32First(hSnapshot, &mi);
while (bRet)
{
#if LUA_VERSION_NUM > 501
// find slua-ue dll
dll_GetLuaInterface interPtr = (dll_GetLuaInterface)GetProcAddress(mi.hModule, "GetLuaInterface");
if (interPtr != NULL) {
hInstLibrary = mi.hModule;
getInter = interPtr;
Slua_UE_find_function();
break;
}
#endif
// find general lua dll
void* versionPtr = (luaDLL_sethook)GetProcAddress(mi.hModule, "lua_sethook");
if (versionPtr != NULL) {
hInstLibrary = mi.hModule;
general_find_function();
break;
}
//travel next dll
bRet = Module32Next(hSnapshot, &mi);
}
}
#endif