Lua断点调试工具Decoda使用方法

合集下载

掌握代码编辑器中的代码调试工具的使用方法

掌握代码编辑器中的代码调试工具的使用方法

掌握代码编辑器中的代码调试工具的使用方法代码调试是软件开发过程中必不可少的一环。

通过调试工具,开发者可以逐步执行代码,观察变量值,查找错误,并将其修复。

在本文中,将介绍一些常见的代码调试工具及其使用方法。

一、断点调试断点调试是最常用的调试方式之一。

在代码编辑器中设置断点,程序会停在断点位置,开发者可以逐行执行代码并观察变量值。

以下是如何使用断点调试的一般步骤:1. 打开代码编辑器,并选择需要调试的代码文件。

2. 在合适的位置设置断点。

通常,可以在代码行号的左侧单击鼠标左键来设置断点。

3. 运行程序,程序会在断点处停下来。

4. 使用调试工具提供的控制按钮,例如“继续”、“下一步”、“步入”等,来逐步执行代码。

5. 在每个断点处观察变量的值,并与预期结果进行比较。

6. 如果发现问题,可以通过查看变量值、栈跟踪等信息来定位错误。

二、监视表达式监视表达式是调试中另一个重要的工具。

开发者可以通过监视表达式来观察特定变量、表达式或函数的值。

以下是如何使用监视表达式的一般步骤:1. 打开代码编辑器,并选择需要调试的代码文件。

2. 在调试工具的监视窗格中添加要监视的表达式。

通常,可以右键单击变量或表达式,然后选择“添加到监视”。

3. 运行程序并观察监视表达式的值变化。

可以根据需要继续执行代码,或者在特定断点处停下来。

4. 如果监视表达式的值与预期结果不符,可以进一步检查代码并找出问题所在。

三、日志输出日志输出是一种简单但有效的调试方法。

通过在代码中插入日志语句,在程序执行过程中将变量值或特定消息输出到日志文件或控制台。

以下是如何使用日志输出的一般步骤:1. 打开代码编辑器,并选择需要调试的代码文件。

2. 在需要观察的位置插入日志语句。

例如,可以使用语言提供的日志库或简单的打印语句。

3. 运行程序,并观察生成的日志文件或控制台输出。

4. 根据日志信息判断程序行为是否符合预期,如有必要,可以继续添加或修改日志语句以获取更详细的信息。

OD使用完全教程

OD使用完全教程

OD使用完全教程.txt如果不懂就说出来,如果懂了,就笑笑别说出来。

贪婪是最真实的贫穷,满足是最真实的财富。

幽默就是一个人想哭的时候还有笑的兴致。

OllyDbg调试工具使用完全教程一,什么是 OllyDbg?OllyDbg 是一种具有可视化界面的 32 位汇编-分析调试器。

它的特别之处在于可以在没有源代码时解决问题,并且可以处理其它编译器无法解决的难题。

Version 1.10 是最终的发布版本。

这个工程已经停止,我不再继续支持这个软件了。

但不用担心:全新打造的 OllyDbg 2.00 不久就会面世!运行环境: OllyDbg 可以以在任何采用奔腾处理器的 Windows 95、98、ME、NT 或是 XP(未经完全测试)操作系统中工作,但我们强烈建议您采用300-MHz以上的奔腾处理器以达到最佳效果。

还有,OllyDbg 是极占内存的,因此如果您需要使用诸如追踪调试[Trace]之类的扩展功能话,建议您最好使用128MB以上的内存。

支持的处理器: OllyDbg 支持所有 80x86、奔腾、MMX、3DNOW!、Athlon 扩展指令集、SSE 指令集以及相关的数据格式,但是不支持SSE2指令集。

配置:有多达百余个(天呀!)选项用来设置 OllyDbg 的外观和运行。

数据格式: OllyDbg 的数据窗口能够显示的所有数据格式:HEX、ASCII、UNICODE、 16/32位有/无符号/HEX整数、32/64/80位浮点数、地址、反汇编(MASM、IDEAL或是HLA)、PE文件头或线程数据块。

帮助:此文件中包含了关于理解和使用 OllyDbg 的必要的信息。

如果您还有 Windows API 帮助文件的话(由于版权的问题 win32.hlp 没有包括在内),您可以将它挂在 OllyDbg 中,这样就可以快速获得系统函数的相关帮助。

启动:您可以采用命令行的形式指定可执行文件、也可以从菜单中选择,或直接拖放到OllyDbg中,或者重新启动上一个被调试程序,或是挂接[Attach]一个正在运行的程序。

Lua调试工具使用及原理

Lua调试工具使用及原理

Lua调试⼯具使⽤及原理前⾔当我们在linux下使⽤c/c++开发时,可以通过gdb来调试我们编译后的elf⽂件。

gdb⽀持了attch、单步运⾏(单⾏、单指令)、设置断点等⾮常实⽤的功能来辅助我们调试。

当使⽤lua开发的时候,⼀般可能会使⽤print(打印到屏幕)或是输出⽇志等稍微简陋的调试⽅式,但如果⽇志输出不能满⾜我们需求时,⽐如我们需要类似断点、单步执⾏等更⾼级的调试功能,此时就必须借助第三⽅⼯具。

本⽂介绍了lua调试⼯具LuaPanda的使⽤,以及lua调试⼯具和gdb在实现上的⼀些区别。

gdb调试原理先简单介绍⼀下gdb的原理。

⼀般的我们将gdb这种调试进程称为tracer,被调试进程称为tracee。

当进程被调试时(处于traced状态)时,每次收到任何除了SIGKILL以外的任何信号,都会暂停当前的执⾏,并且tracer进程可以通过waitpid来获取tracee的暂停原因。

gdb使⽤ptrace系统调⽤来实现操作tracee进程1. gdb附加到进程当使⽤gdb附加到⼀个正在运⾏的进程(tracee)上时,gdb会执⾏类似下⾯的代码:ptrace(PTRACE_ATTACH, pid, ...)这⾥的pid是tracee的pid。

系统调⽤执⾏后,os会给tracee进程发送⼀个SIGTRAP信号,然后tracee的执⾏将会暂停。

最后gdb(tracer)可以通过系统调⽤waitpid来获取tracee的暂停原因,并且开始调试。

2. gdb单步执⾏单步调试与上述attch类似,gdb通过下⾯的代码告诉tracee进程需要在运⾏完⼀个指令后暂停:ptrace(PTRACE_SINGLESTEP, pid, ...)当tracee执⾏完⼀个指令后,tracee也会因为收到os的SIGTRAP信号从⽽暂停执⾏。

3. gdb设置断点设置断点稍微有点不同,⾸先gdb需要从调试程序的调试信息中根据⾏号(函数名)找到代码的内存地址,然后通过ptrace将tracee进程的代码替换成⼀个软中断指令:int 3。

debug 的使用

debug 的使用

Debug是一种程序调试工具,主要用于帮助程序员检查和修复程序中的错误。

以下是如何使用Debug的基本步骤:
设置断点:断点是一种标记,告诉Debug从标记的地方开始查看。

在要设置断点的代码行上单击鼠标左键即可。

运行程序:在代码区域右击,选择Debug执行。

单步执行:点击Step Into(F7)这个箭头,或者直接按F7,以一行一行地操纵代码,从而判断程序的执行流程是否与预期一致。

查看变量值:在执行过程中,可以查看变量的当前值,以了解程序状态。

删除或禁用断点:选择要删除的断点,单击鼠标左键即可。

如果是多个断点,可以每一个再点击一次。

也可以一次性全部删除。

以上是使用Debug的基本步骤,但请注意,具体使用方式可能会根据Debug的具体版本和配置有所不同。

javascript debugger使用方法

javascript debugger使用方法

在 JavaScript 中,调试器(debugger)是一个强大的工具,可以帮助你检测和修复代码中的错误。

主流的浏览器都内置了 JavaScript 调试器工具,例如 Chrome 的开发者工具和 Firefox 的开发者工具等。

下面是一些常见的 JavaScript 调试器的基本使用方法:
1.在代码中插入断点:你可以在你认为可能出现问题的代码行上插入断点。

断点会暂停代码的执行,使你能够逐步检查代码的执行过程。

// 在代码中插入断点
debugger;
2.打开浏览器的开发者工具:按下F12键或右键单击网页中的任何元素,然后
选择“检查”或“检查元素”,打开浏览器的开发者工具。

3.调试代码:在开发者工具中,你可以查看当前脚本、HTML 和 CSS,检查网
络请求,并监视 JavaScript 的运行情况。

4.检查变量的值:在断点处,你可以检查变量的值,以了解代码执行到此处
时变量的具体值。

5.逐步执行代码:你可以使用调试器的控制按钮(例如“继续”、“单步执行”
等),逐步执行代码并观察每一步的结果。

6.监视表达式:在调试器中,你可以设置监视表达式,以便在代码执行时监
视特定表达式的值。

7.控制台调试:你可以在控制台中输出日志信息,以便在代码执行过程中查
看特定变量的值或输出调试信息。

8.处理异常:调试器还可以帮助你捕获和处理代码中的异常,以及检测错误
的来源。

在调试过程中,通过逐步执行代码并检查变量的值,你可以更好地理解代码的执行流程,并找到潜在的问题所在。

熟练使用调试器可以帮助你提高代码质量并提升开发效率。

DEBUG的使用方法

DEBUG的使用方法

DEBUG的使用方法1.设置断点:断点是在代码中设置的一个位置,程序在运行到这个位置时会暂停执行。

可以在关键的代码行上设置断点,以便在程序运行到这些位置时进行观察和调试。

在DEBUG工具中,我们可以在代码行上单击左侧的空白区域来设置断点。

2.执行步进:步进是一种按步执行程序的方法,可以逐行或逐过程执行代码。

通过逐行执行代码,可以观察每一行代码的执行情况,以便找出程序中的错误。

可以使用DEBUG工具提供的步进功能,一次执行一行代码或一个过程。

3.观察变量:在程序运行过程中,可以观察和监视变量的值,以便了解程序的状态。

可以使用DEBUG工具来查看变量的值,并在程序执行过程中跟踪变量的变化。

这对于发现变量值的改变和问题的根源非常有帮助。

4.输出调试信息:在调试过程中,可以通过在代码中插入输出语句来输出调试信息。

可以使用DEBUG工具提供的输出窗口或控制台来查看这些调试信息。

输出调试信息有助于了解程序的执行流程,找到错误发生的原因。

5.检查堆栈:堆栈是保存程序执行状态的一种数据结构,可以在DEBUG工具中查看和跟踪堆栈的状态。

堆栈信息可以告诉我们程序的执行路径,以及代码是如何调用和返回的。

通过检查堆栈,我们可以找到错误发生的上下文和调用链。

6.使用断言:断言是一种在代码中插入的条件,用于检查程序执行过程中的假设和要求。

可以使用DEBUG工具中的断言功能,在关键的代码位置插入断言条件。

当断言条件不满足时,程序会执行中断操作,从而帮助我们快速定位错误。

7.进行追踪:追踪是一种记录程序执行过程的方法,可以在DEBUG工具中查看程序的执行轨迹。

追踪记录了程序的每一步操作,包括函数调用、条件语句的执行和变量的修改等。

通过追踪,我们可以逐步了解程序的执行情况,并找到错误所在。

8.使用条件断点:条件断点是一种在特定条件下触发断点的方法。

可以在DEBUG工具中设置条件断点,当满足特定条件时,程序会在断点处暂停执行。

条件断点可以帮助我们找出特定情况下的错误,提高调试的效率。

断点调试的基本方法

断点调试的基本方法

断点调试的基本方法断点调试是一种常用的程序调试技术,它可以帮助开发人员定位和解决程序中的错误和问题。

通过在代码中设置断点,我们可以让程序在指定位置暂停执行,以便我们可以逐行查看代码的执行情况、变量的值以及程序流程。

本文将介绍断点调试的基本方法,包括设置断点、运行程序、调试控制等方面。

1. 设置断点在开始进行断点调试之前,我们首先需要在代码中设置断点。

通常情况下,我们会选择在可能出现问题或者感兴趣的位置设置断点。

在一个循环中,我们可以选择在每次循环迭代时设置断点,以便查看每次迭代时变量的值。

在大多数集成开发环境(IDE)中,设置断点非常简单。

只需要在代码行号处点击鼠标左键或者使用快捷键(通常是F9),就可以在该位置设置一个断点。

一旦成功设置了一个断点,该行代码前面会出现一个小圆圈标记。

2. 运行程序当我们完成了断点的设置之后,就可以开始运行程序进行调试了。

通常情况下,我们会选择以调试模式启动程序,这样可以让程序遇到断点时暂停执行,以便我们进行调试。

在大多数IDE中,可以通过点击菜单栏上的“调试”或者“Debug”按钮来启动程序的调试模式。

启动调试模式后,程序会按照正常的方式运行,直到遇到第一个断点。

一旦程序遇到断点,它会暂停执行,并且我们可以查看当前代码行的状态和变量的值。

3. 调试控制一旦程序进入了调试模式并且遇到了断点,我们就可以利用调试工具来查看和控制程序的执行。

下面是一些常用的调试控制方法:•单步执行(Step over):这个功能可以让我们一次执行一行代码,并且不进入函数或方法内部。

如果当前行是一个函数或方法的调用,那么该函数或方法会被整体执行完毕,并且返回结果。

•单步进入(Step into):这个功能可以让我们进入函数或方法内部,并且逐行执行其中的代码。

如果当前行是一个函数或方法的调用,那么会跳转到该函数或方法内部的第一行。

•单步返回(Step out):这个功能可以让我们从当前函数或方法内部跳出,并返回到它的调用位置。

高效使用调试工具:断点、日志和追踪的技巧

高效使用调试工具:断点、日志和追踪的技巧

高效使用调试工具:断点、日志和追踪的技巧在软件开发过程中,调试是一个非常重要的环节。

无论是解决问题,还是优化性能,调试工具都是开发人员的得力助手。

本文将介绍三种常用的调试工具:断点、日志和追踪,并分享一些使用这些工具的技巧。

首先,断点是调试中最基础也是最常用的工具之一。

通过在代码中设置断点,我们可以在程序执行到指定位置时停下来,观察变量的值,检查代码的执行情况。

对于比较复杂的程序或者有特定条件的分支,设置断点是非常有帮助的。

在使用断点时,我们可以选择在进入代码行、离开代码行或者在条件满足时停下来。

此外,还可以通过条件断点来设置只有在特定条件下才会触发断点,提高调试的效率。

其次,日志是另一种常用的调试工具。

通过在关键代码位置插入日志输出,我们可以观察变量、判断分支走向等信息,帮助我们定位问题。

相比设置断点,使用日志的好处是可以查看程序执行过程中的完整日志信息,对于复现问题或者对程序整体流程有更好的了解。

在使用日志时,我们可以根据需要设定输出级别,通过控制级别来过滤输出信息。

另外,可以使用日志的一些高级特性,如输出堆栈信息、记录运行时间等,进一步辅助我们进行调试。

最后,追踪是一种调试工具,主要用于性能优化和代码覆盖率测试。

通过追踪工具,我们可以获取程序中各个函数的耗时信息,找到性能瓶颈;还可以统计代码执行次数,评估测试用例的覆盖率。

在使用追踪工具时,我们应该选择合适的粒度,避免过多的方法调用导致数据过大或者影响程序性能。

对于性能优化,可以通过追踪工具定位到具体代码行,并结合日志和断点进一步调试。

在使用这些调试工具时,还有一些技巧可以提高调试效率。

首先,合理的调试策略非常重要。

我们可以根据问题的特点,先使用日志或者断点定位大致问题位置,再使用追踪工具进行深入调试。

其次,针对复杂的问题,可以使用一些辅助工具,如堆栈追踪、内存泄漏检查等,定位问题的具体原因。

此外,我们还应该学会分析调试信息,从中找到关键信息,帮助我们更快地解决问题。

lua断点调试(云风)

lua断点调试(云风)

---------------------------- bp.lua --------------------------local type=type local tostring=tostring local print=print local setmetatable=setmetatable local getfenv=getfenv local ipairs=ipairs local pairs=pairs local xpcall=xpcall local error=error local table_insert=table.insert local table_concat=table.concat local debug=debug module "bp" local nil_value={} local function traversal_r(tbl,num) num = num or 64 local ret={} local function insert(v) table_insert(ret,v) if #ret>num then error() end end local function traversal(e) if e==nil_value or e==nil then insert("nil,") elseif type(e)=="table" then insert("{") local maxn=0 for i,v in ipairs(e) do traversal(v)maxn=i end for k,v in pairs(e) do if not (type(k)=="number" and k>0 and k<=maxn) then if type(k)=="number" then insert("["..k.."]=") else insert(tostring(k).."=") end traversal(v) end end insert("}") elseif type(e)=="string" then insert('"'..e..'",') else insert(tostring(e)) insert(",") end end local err=xpcall( function() traversal(tbl) end, function() end ) if not err then table_insert(ret,"...") end return table_concat(ret) end function print_r(tbl,num) print(traversal_r(tbl,num)) end local function init_local(tbl,level) local n=1 local index={}while true do local name,value=debug.getlocal(level,n) if not name then break end if name~="(*temporary)" then if value==nil then value=nil_value end tbl[name]=value index["."]=n end n=n+1 end setmetatable(tbl,{__index=index}) return tbl end local function init_upvalue(tbl,func) local n=1 local index={} while true do local name,value=debug.getupvalue(func,n) if not name then break end if value==nil then value=nil_value end tbl[name]=value index["."]=n n=n+1 endsetmetatable(tbl,{__index=index}) return tbl endfunction dbg(level) level=level and level+2 or 2 local lv=init_local({},level+1) local func=debug.getinfo(level,"f").func local uv=init_upvalue({},func) local _L={} setmetatable(_L,{ __index=function(_,k) local ret=lv[k] return ret~=nil_value and ret or nil end, __newindex=function(_,k,v) if lv[k] then lv[k]= v~= nil and nil_value or v debug.setlocal(level+3,lv["."..k],v) else print("error:invalid local name:",k) end end, __tostring=function(_) return traversal_r(lv) end }) print("_L=",traversal_r(lv)) local _U={} setmetatable(_U,{ __index=function(_,k) local ret=uv[k] return ret~=nil_value and ret or nil end, __newindex=function(_,k,v) if uv[k] then uv[k]= v~= nil and nil_value or vdebug.setupvalue(func,uv["."..k],v) else print("error:invalid upvalue name",k) end end, __tostring=function(_) return traversal_r(uv) end }) print("_U=",traversal_r(uv)) local _G=getfenv(level) _G._L,_G._U=_L,_U debug.debug() _G._L,_G._U=nil,nil endlocal _bp_list={} local _bp_desc={} local function bp_list_name(name) local t=type(_bp_desc[name]) print("[".."]",_bp_list[name] and "on" or "off") if t=="table" then for _,v in ipairs(_bp_desc[name]) do print("----",v) end elseif t=="string" then print("---",_bp_desc[name]) end end local function bp_list(name) if name then bp_list_name(name) else for k,v in pairs(_bp_list) do bp_list_name(k)end end end local _bp_unnamed={} local _bp_unnamed_desc={} local _bp_unnamed_index={} local _bp_index=1 do local weak={__mode="kv"} setmetatable(_bp_unnamed,weak) setmetatable(_bp_unnamed_desc,{__mode="k"}) setmetatable(_bp_unnamed_index,weak) end local function bp_add_index() local info=debug.getinfo(3,"Slf") local func=info.func if _bp_unnamed[info.func]==nil then local desc=info.source.."(".currentline..")" _bp_unnamed[func]=true _bp_unnamed_desc[func]=desc _bp_unnamed_index[func]=_bp_index _bp_unnamed_index[_bp_index]=func _bp_index=_bp_index+1 end return _bp_unnamed[func],_bp_unnamed_index[func] end local _bp_named={} local _bp_named_desc={} local function bp_add_name(name) local info=debug.getinfo(3,"Sl") local desc=info.source.."(".currentline..")" if _bp_named[name]==nil then _bp_named[name]=false endlocal tbl=_bp_named_desc[name] if tbl then tbl[desc] = true else _bp_named_desc[name]={ [desc] = true } end return _bp_named[name],name end local function bp_show(n) if type(n)=="number" then local func=_bp_unnamed_index[n] if func==nil then error "invalid break point id" end print("break point:",n, _bp_unnamed[func] and "on" or "off", _bp_unnamed_desc[func] ) else print("break point:",n,_bp_named[n] and "on" or "off") if _bp_named_desc[n] then for k,v in pairs(_bp_named_desc[n]) do print("",k) end else print("\tundefined") end end end local function bp_show_all() for k,_ in pairs(_bp_unnamed) do bp_show(_bp_unnamed_index[k]) end for k,_ in pairs(_bp_named) do bp_show(k) endend function bp(n) local trigger,name if n==nil then trigger,name=bp_add_index() else trigger,name=bp_add_name(n) end if trigger then bp_show(name) dbg(1) else _bp_list[name]=false end end function trigger(n,on) on = on~=false if type(n)=="number" then local func=_bp_unnamed_index[n] if func==nil then error "invalid break point id" end _bp_unnamed[func]=on else _bp_named[n]=on end end function list(v) if v then bp_show(v) else bp_show_all() end endfunction error_handle(msg) print(msg) dbg(1) end可以这样测试一下:require "bp" function foo(arg) bp.bp() end =foo(0) -- 输出 foo(0) -- 设置一个匿名断点 return arg+1运行后会进入调试控制台: 可以发现断点被编了号(1 号)并被触发,局部变量放在 _L 这张表里可以直接操作,upvalue 放 在了 _U 表中 .break point: _L= _U=1on=stdin(2){arg=0,} {}我们可以改一下 arg 的值,如 _L.arg=1 然后 cont 退出控制台.可以发现 foo 函数返回了 2 . 这种匿名断点添加方便,而且断点跟随逻辑而不是和代码行做映射.也就是说,同一个 function 的不同实例(不同的 closure)可以有不同 id 的断点,单独控制. 我们也可以使用具名断点,方法是 bp.bp "bpname" 具名断点缺省是 disable 状态的.如果需要激活可以用 bp.trigger "bpname" . 给断点起名字的好处是,可以给一组断点起同一个名字,这样可以批量开关. bp.trigger(name,true/false) 用于开关断点,name 可以是字符串也可以是 id . 列出所有断点可以用 bp.list() 也可以用 bp.list(name) 来列出一个断点的状态,name 可以是字符串也可以是 id . 还有一种方式,就是把调试控制台用在错误处理函数中,这样函数一出错就自动切入控制 台. 方法是 xpcall(some_function,bp.error_handle) 下一步打算做单步执行 :D。

【Java】Debug断点调试常用技巧

【Java】Debug断点调试常用技巧

【Java 】Debug 断点调试常⽤技巧Debug 适⽤场景1. 在程序出现问题时,查看参数变化以及⽅法的调⽤。

2. 查看参数结构3. 查看⽅法调⽤以及参数变化Debug 操作技巧Show Execution Point将光标回到当前断点停顿的地⽅Step Over 执⾏当前⾏代码,并将运⾏进度跳转到下⼀⾏。

Step Into进⼊到当前代码⾏的⽅法内部。

Step Out从⽅法内部出去Force Step Into强制进⼊Java ⾃带⽅法的内部ⅡⅡⅡⅡⅡRun to Cursor将光标定位到想到达的代码⾏点击Run to CursorDrop Frame 丢弃当前虚拟机栈帧初始:进⼊⽅法:丢弃当前帧:也就是说,我们退回了上⼀步进⼊⽅法之前。

ⅡⅡEvaluate Expression可以⽤它来评估表达式如p.getName()等。

Force Return | 避免操作资源我们在调试代码的时候中间出现了异常,但是我们⼜没有做异常捕获,稀⾥糊涂地把错误数据存到了数据库中,我们⼜需要将这些数据给删除,将数据库复原,才能达到之前我们需要的效果。

所以,接下来我们讲⼀讲如何避免操作资源,强制返回。

public static void saveResource() {System.out.println("shit happens");System.out.println("save to db");System.out.println("save to redis");System.out.println("send message to mq for money payout");}debug:我们发现程序出现了异常Force ReturnⅡⅡ它会只打印shit happens ,不会继续向下执⾏了。

Trace Current Stream Chain | Stream Debugpublic static void streamDebug() {// stream chainArrays.asList(1, 2, 3, 45).stream().filter(i -> i % 2 == 0 || i % 3 == 0).map(i -> i * i) .forEach(System.out::print);}左下⾓平铺模式Flat Mode :Ⅱ断点常⽤技巧断点(Breakpoint)断点:如果把程序想象成⼀条平滑的线,那么断点就是⼀个结,可以让程序中断在需要的地⽅,从⽽⽅便其分析。

lua的调试器技术

lua的调试器技术

lua的调试器技术来自转载:简介:LUA没有自带调试器,只提供了一套调试库,可以实现符合自己需要的调试器.晚上没事,改写了一下以前的一个GDB风格的LUA调试器,可嵌入到应用程序中,在需要的时候触发并调试,有需要的朋友可以参考下. 支持如下命令:h 帮助信息c 继续动行s 单步运行(不跳过函数调用)n 单步运行(跳过函数调用)p var 打印变量值b src:line 添加断点,注意src要写文件的绝对路径,例如b script/main.lua:22d num 删除断点bl 列出所有断点be num 启用一个断点bd num 禁用一个断点bt 打印调用栈实现:LUA支持用debug.sethook设置三种Hook:一,每行代码执行时调用Hook函数二,每个函数调用时执行Hook函数三,每个函数返回时调用Hook函数在Hook函数中,可以通过调用debug.getinfo得到当前LUA文件名,当前所执行代码的行号.所以,要实现针对行下断点,一个显尔易见的办法就是在每个HOOK中判断当前文件和当前行号是否是一个断点,是的话就中断下来(调用io.read()来等待输入).这样当然会比较慢,因为每行代码执行时都会去调用HOOK函数,但LUA一般是用来做逻辑而不是算术密集的操作,而且一般只是在开发期调试会使用hook,所以绝大部分情况下是足够用了.特殊情况下有效率要求时,可以使用下文介绍的另一种办法.但在实际开发中碰到了个问题:如何实现n命令(单步运行,跳过函数调用),LUA的HOOK是每行代码都会触发,可以取得当前函数,所以单步运行时很容易知道是不是进入了一个新函数,但是如何在进入这个函数时不中断,在调用完成时才中断?最直观的想法是在n命令碰到函数时,自动在函数调用的下一行加入断点并运行.但是实际情况要复杂得多,比如函数调用下一行是空行,函数调用当前行有return,比如: if ( foo() ) return end这样就要写很多代码分析的代码来保证正确性,逻辑就写复杂了,放弃这种做法.另一种想法是下函数执行hook和函数返回hook,执行hook触发时增量某个变量,返回hook扫许时减量某个变量,这样变量为0时就是返回到调用函数了(调用栈平衡),但是程序逻辑也变得复杂了,放弃这种做法.最直观的办法是检查调用栈深度,因为被调用函数返回时,调用栈深度总是不会变的.但是LUA debug库没有检查调用栈深度的函数,还好LUA是开源的,动手加一个即可.最后的代码见下面,如有更简单的办法请告之:在lua(5.1.4)源代码文件 ldblib.c中添加返回调用栈深度的函数: static int db_traceback_count (lua_State *L) {lua_Debug ar;int index = 1;while (lua_getstack(L, index, &ar))index++;lua_pushnumber( L, index - 1 );return 1;}在static const luaL_Reg dblib[] 数组中添加一行函数注册:{"traceback_count", db_traceback_count},重新编译LUA.为了像GDB一样在单步调试时能显示当前源代码,在C/C++层注册一个读取指定文件指定行的函数:int get_file_line( lua_State *L ){const char *file = luaL_checkstring( L, 1 );int line = lua_tonumber( L, 2 );if ( line < 1 ) line = 1;int n = 1;char src[2046];FILE *f = fopen( file, "r" );if ( f ){while ( fgets( src, 2046, f ) ){if ( n == line ){int last = strlen(src) - 1;if ( src[last] == '/n' )src[last] = '/0';lua_pushstring( L, src );fclose( f );return 1;}n++;}lua_pushnil( L );fclose( f );return 1;}else{lua_pushnil( L );return 1;}return 0;}在合适的地方注册即可,lua_pushcfunction( L, get_file_line );lua_setglobal( L, "get_file_line" );运行时加载debug.lua(在后面给出)就可以了使用:lua本身要加载debug库可以注册一个信号处理函数(linux)或热键处理函数(win32),在处理函数中调用lua_getglobal( L, "begin_debug" );int error = lua_pcall( L, 0, 0, 0 );if ( expr ){printf( "%s/n", lua_tostring( L, -1 ) );lua_pop( L, 1 );}如果是Win32 gui界面的程序,可以用AllocConsole函数分配一个控制台,在控制台中调试.下面是debug.lua,还有很多可以优化和改进的地方,有需要的朋友可以自己修改_DEBUG_FILE需要改成debug.lua在程序运行的相对路径debug.lua_DEBUG_FILE = "script/debug.lua"debug.bps = {max = 0,trace = false,last_cmd = "",next = false,cur_func = nil,trace_count = 0,var_tbl = nil,}function debug_log( log_str )print( "(ldb) " .. log_str )endfunction debug_print_var( name, value, level )local prefix = string.rep( " ", level )local str = string.format( "%s%s = %s", prefix, name, tostring(value) )if type( value ) == "table" thenif debug.var_tbl[value] then--已在临时表中的,只打印表地址print( str )end--加到临时表中,以免表出现循环引用时,打印也产生死循环debug.var_tbl[value] = true--打印表中所有数据print( string.format( "%s%s = {", prefix, name ) )for k, v in pairs( value ) do--不打印 "_"开头的内部变量if string.sub( k, 1, 1 ) ~= "_" thendebug_print_var( k, v, level + 1 )endendprint( prefix .. "}" )elseif type( value ) == "string" thenprint( str )elseprint( str )endendfunction debug_print_expr( var )--清空临时变量表debug.var_tbl = {}local index = 1--找局部变量while true dolocal name, value = debug.getlocal( 4, index )if not name then break endindex = index + 1if name == var thendebug_print_var( var, value, 0 )endend--找全局变量if _G[var] ~= nil thendebug_print_var( var, _G[var], 0 )returnenddebug_log( var .. " is invalid" )endfunction add_breakpoint( expr )local si = string.find( expr, ":" )if nil == si thendebug_log( "add breakpoint error, expr (" .. expr .. ") invalid" ) returnendlocal line = string.sub( expr, si + 1 )local line = tonumber( line )local source = string.sub( expr, 1, si - 1 )--先查找有不有相同断点if ( debug.bps[line] ~= nil ) and ( debug.bps[line][source] ~= nil ) thendebug_log( string.format( "breakpoint %s:%d existed", source, line ) )returnendlocal tbl = {}tbl.source = sourcetbl.line = linetbl.active = truetbl.number = debug.bps.max + 1if debug.bps[line] == nil thendebug.bps[line] = {}enddebug.bps[line][source] = tbldebug.bps.max = debug.bps.max + 1endfunction debug_show_bp()for k, v in pairs( debug.bps ) doif type( v ) == "table" thenfor k1, v1 in pairs( v ) dolocal str = string.format( "bp num:%d %s:%d active:", v1.number,v1.source,v1.line )if v1.active thenstr = str .. "enable"elsestr = str .. "disable"endprint( str )endendendendfunction debug_del_bp( expr )local number = tonumber( expr )for k, v in pairs( debug.bps ) doif type( v ) == "table" thenfor k1, v1 in pairs( v ) doif v1.number == number thendebug.bps[k][k1] = nildebug_log( "remove bp:" .. number .. " ok" ) endendendendendfunction debug_enable_bp( expr )local number = tonumber( expr )for k, v in pairs( debug.bps ) doif type( v ) == "table" thenfor k1, v1 in pairs( v ) doif v1.number == number thenv1.active = truedebug_log( "enable bp:" .. number )endendendendendfunction debug_disable_bp( expr )local number = tonumber( expr )for k, v in pairs( debug.bps ) doif type( v ) == "table" thenfor k1, v1 in pairs( v ) doif v1.number == number thenv1.active = falsedebug_log( "disable bp:" .. number ) endendendendendfunction debug_help()print( "h help info" )print( "c continue" )print( "s trace" )print( "n next" )print( "p var print variable" )print( "b src:line add breakpoint" ) print( "d num del breakpoint" ) print( "bl list breakpoint" )print( "be num enable breakpoint" ) print( "bd num disable breakpoint" ) print( "bt print traceback" )endfunction debug_execute_cmd( env ) io.write( "(ldb) " )local cmd = io.read()--取上一次的命令,方便调试if cmd ~= "" thenst_cmd = cmdelsecmd = st_cmdendlocal c = cmdlocal expr = ""local si = string.find( cmd, " " )if si ~= nil thenc = string.sub( cmd, 1, si - 1 )expr = string.sub( cmd, string.find( cmd, " %w" ) + 1 ) endif c == "c" thendebug.bps.trace = falsereturn trueelseif c == "s" thendebug.bps.trace = truereturn trueelseif c == "n" thendebug.bps.trace = falsedebug.bps.next = truedebug.bps.cur_func = env.funcdebug.bps.trace_count = debug.traceback_count() - 1 return trueelseif c == "p" thendebug_print_expr( expr )elseif c == "b" thenadd_breakpoint( expr )elseif c == "bl" thendebug_show_bp()elseif c == "d" thendebug_del_bp( expr )elseif c == "be" thendebug_enable_bp( expr )elseif c == "bd" thendebug_disable_bp( expr )elseif c == "bt" thenprint( debug.traceback("", 3) )elseif c == "h" thendebug_help()elsedebug_log( "invalid cmd:" .. cmd )endreturn falseendfunction debug_trace( event, line )local env = debug.getinfo( 2 )if env.short_src == _DEBUG_FILE thenreturnend--判断是否在next调试if debug.bps.next thenlocal trace_count = debug.traceback_count()--函数返回了,调用栈数量就会比现在小if trace_count < debug.bps.trace_count thendebug.bps.next = falsedebug.bps.trace = trueelseif trace_count == debug.bps.trace_count thenif debug.bps.cur_func == env.func thendebug.bps.next = falsedebug.bps.trace = trueendendend--判断是否有断点if ( not debug.bps.trace ) and ( debug.bps[line] ~= nil ) thenlocal tbl = debug.bps[line][env.short_src]if ( tbl ~= nil ) and tbl.active then--如果在next时,碰到断点了,就清除单步运行状态debug.bps.next = falsedebug.bps.trace = truedebug_log( "breakpoint " .. tbl.number )endendif debug.bps.trace thenlocal src = get_file_line( env.short_src, line )local funname = or "unknow"debug_log( string.format( "%s:%d(%s) %s", env.short_src, line, funname, src ) )debug.bps.cur_file = env.short_src;debug.bps.cur_line = linewhile not debug_execute_cmd( env ) doendendendfunction begin_debug()debug.bps.trace = truedebug.sethook( debug_trace, "l" )end--关闭debuggerfunction debug_close()debug.bps.trace = falsedebug.bps.next = falsedebug.sethook()end本文来自CSDN博客,转载请标明出处:/pankun/archive/2009/04/07/4055614.aspx。

C++断点调试

C++断点调试

C++调试工具——Debug(设置和移除断点)由于引起运行时错误的原因难以被发现,所以我们有时候要利用工具来完成调试工作。

Debug就是VC++提供的一种常用调试工具。

它能够让语句一句一句或一段一段执行,并且能够观察程序运行过程中各变量的变化情况。

在介绍如何使用Debug工具之前,我们要介绍一下什么是断点(Breakpoint)。

当程序运行到断点的时候,它会暂时停止运行后面的语句,供用户观察程序的运行情况,并等待用户发出指令。

断点不是语句,而是附在某条语句上的一个标志。

如何设置和移除断点点击需要设置断点的语句,使光标移动到该语句所在的行。

按下F9键或按钮就会发现,在该语句之前出现一个红点,这就是断点标志。

如下图11.5.1所示:如果要移除已经设置好的断点,则同样点击断点所在语句,按下F9键或按钮则断点被移除。

我们可以个给一个程序设置多个断点。

Go设置了断点之后,我们就能开始调试程序了。

与以前不同,我们不能按执行按钮,而是要按F5键或按钮,或者选择Build菜单Start Debug中的Go。

一旦按下了Go,则程序会正常运行直至遇到断点。

我们以下面这个程序(程序11.5)来演示Debug功能的使用。

该程序主要目的是统计一个不多于20项的正整数数列中,有多少对成双倍关系的项,该数列以0结尾。

比如数列1 3 4 2 5 6 0中,成双倍关系的项有3对(1和2、2和4、3和6)。

#include <iostream>using namespace std;int main(){● int a[50],b[50],sum=0;//在此设置断点for (int i=0;a[i-1]!=0;i++){cin >>a[i];b[i]=2*a[i];}for (i=0;a[i]!=0;i++){for (int j=0;b[j]!=0;j++){if (a[i]==b[j]){sum++;break;}}}cout <<sum <<endl;return 0;}设置好断点,按下Go按钮以后,我们可以看到如下的界面:在界面中出现了三个我们不熟悉的窗口。

luadec编译

luadec编译

luadec编译
Luadec是一个Lua字节码反编译器,可以将Lua字节码转换为可读的Lua源代码。

本文将介绍使用Luadec编译Lua字节码的方法。

首先需要下载Luadec,并确保已经安装了Lua环境。

然后将需要反编译的Lua字节码保存为一个文件,例如'test.luac'。

打开命令行界面,进入Luadec的安装目录,输入命令'luadec test.luac',即可生成一个名为'test.lua'的源代码文件。

这个文件就是反编译后的Lua源代码。

在生成的源代码中,可能会出现一些变量名、函数名等被Luadec 重命名的情况。

这是因为Luadec为了保护源代码的作者和版权,会对一些标识符进行重命名。

如果需要保留原有的变量名和函数名,可以使用命令'luadec -s test.luac'。

除了反编译单个Lua字节码文件,Luadec还支持批量反编译。

可以将所有需要反编译的Lua字节码文件放在同一个文件夹下,然后使用命令'luadec -d foldername',即可将该文件夹下所有的Lua字节码反编译为源代码。

Luadec是一个非常实用的工具,可以方便地将Lua字节码转换为可读的源代码。

在调试和学习Lua程序时,特别是在没有源代码的情况下,Luadec可以为我们提供很大的帮助。

- 1 -。

lua 断点调试原理

lua 断点调试原理

lua 断点调试原理
Lua 断点调试是一种通过在代码中设置断点,从而实现程序停止执行和查看程序状态的技术。

在 Lua 程序中,断点调试可以通过使用调试器来实现。

当程序执行到设置的断点处时,调试器会停止程序的执行并显示当前程序的状态,包括变量值、堆栈信息等。

这使得开发人员能够更加容易地调试程序并找出潜在问题。

Lua 断点调试的原理是通过在程序的特定位置插入断点指令,当程序执行到这些位置时,便停止程序的执行并进入调试模式。

调试模式下,开发人员可以查看当前程序的状态并进行调试操作。

调试器还可以监视变量的值,并在变量值发生变化时提醒开发人员。

在实现 Lua 断点调试时,通常需要配合使用调试库和 IDE 等工具。

调试库用于实现断点指令和其他调试功能,而 IDE 则提供了更加友好的用户界面和便捷的调试操作,使得开发人员可以更加高效地进行调试。

总之,Lua 断点调试是一种有效的调试技术,它可以帮助开发人员快速定位程序问题并提高开发效率。

DecodaTutorialLUA调式器强大的lua调试工具

DecodaTutorialLUA调式器强大的lua调试工具

DecodaTutorialLUA调式器强⼤的lua调试⼯具今天项⽬组的同事提起来要整个调式lua的⼯具,由于近期项⽬中⽤到lua的脚本⽇趋增长,导致脚本出问题的⼏率也⽇益增加~~ 。

调试起来也不是特别⽅便,所以有必要整⼀个。

于是就先找到了⼀个调式器,暂时可以满⾜项⽬的需求。

下⾯先转帖⼀下⽹上⼀位朋友写的软件使⽤帮助,感谢!Decoda Tutorial 1:从Decoda启动宿主程序调试lua我从Decoda刚发布就⼀直关注着,这个⼯具可以注⼊到宿主程序内对lua脚本进⾏调试,还可以设置断点观察变量的值,功能⾮常强⼤。

下⾯我介绍⼀下使⽤⽅法。

⾸先找到⼀个使⽤了lua的程序,我这⾥⽤举例,这是个很好很强⼤的⽹络截包⼯具,wireshark内部使⽤了lua。

没有wireshark的请下去google⼀下并下载安装,此为开源软件。

调试使⽤lua的宿主程序有两种启动⽅式,⼀种是从Decoda启动宿主程序,另⼀种是先启动宿主程序然后⽤decoda注⼊。

本篇⽂章将介绍如何从Decoda启动宿主程序启动Decoda并点击Debug⽬录下的StartDebuging,弹出⼀个⼯程设置对话框,点击对话框⾥的第⼀⾏的Command右边的按钮,然后找到你的wireshark.exe可执⾏⽂件,点击OK。

此时wireshark程序开始执⾏,稍等⼀会在左边的窗⼝中会出现⼀个init.lua⽂件,这就是这个wireshark使⽤的lua⽂件。

(decoda可以检测程序使⽤的所有lua⽂件并将他们显⽰在左边的窗⼝中)现在你可以在这个init.lua⾥⾯设置断点了,在disable_lua = true; do return end;这⼀句下断点,聪明⼈都看得出来,只能在这⾥下断点,因为下⾯的语句都是不会执⾏的,除⾮将这⼀句注释。

选择Debug菜单中的Stop Debugging退出调试,然后再选择Start Debugging重新启动调试,此时程序就会断点到你设置断点的这⼀⾏。

断点调试——精选推荐

断点调试——精选推荐

断点调试断点调试1. 实际需求在开发中,程序员发现⼀个⾮常诡异的错误,怎么看源代码都发现不了这个错误,这时⽼程序员就会温馨提⽰,可以使⽤断点调试,⼀步⼀步的看源码执⾏的过程,从⽽发现错误所在2.断点调试介绍断点调试是指⾃⼰在程序的某⼀⾏设置⼀个断点,调试时,程序运⾏到这⼀⾏就会停住,然后你可以⼀步⼀步的往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码⾏即显⽰错误,停下,然后程序可以进⾏分析从⽽找到这个BUG断点调试是程序员必须掌握的重要的技能使⽤断点调试也能帮助我们最终查看C程序代码的执⾏过程,提⾼程序员的⽔平3.断点调试的快捷键f5 开始调试,执⾏到下⼀个断点f11 逐句执⾏代码,会进⼊到函数体中f10 逐过程执⾏(遇到函数,跳出前,会将该函数执⾏完)shift+f5 终⽌调试shift+f11 跳出(跳出某个函数,跳出前,会将该函数执⾏完)4.断点调试应⽤案例看⼀下变量的变化情况void main(){int sum=0;//断点下在这⾥,然后使⽤f10(逐过程执⾏,可以看到各个变量的变化情况)int i=0;for(i=0;i<10;i++){sum+=i;printf("i=%d",i);printf("sum=%d",sum);}printf("退出for循环了");}5.断点调试应⽤案例2看⼀下数组越界的情况,当数组越界后,会输出⼀个为⽌的值void main(){int arr[]={1,2,3,4,5};int i=0;int len=sizeof(arr)/sizeof(int);for(i=0;i<=len;i++){printf("arr[%d]=%d",i,arr[i]);}}6.断点调试应⽤案例3演⽰如果进⼊到调⽤的函数体内,f11(进⼊到函数体),shift+f11(跳出函数)double cal2(int num1,int num2,char oper){double res=0.0;switch(oper){case '+':res=num1+num2;break;case '-':res=num1-num2;break;case '*':res=num1*num2;break;case '/':res=num1/num2;break;default:printf("你的运算符有误");}return res;}7.断点调试应⽤案例4#include<stdio.h>#include<stdlib.h>#include"myfun.h"void main(){int n1=10;int n2=40;char oper="+";double res=cal2(n1,n2,oper);printf("res=%.2f",res);printf("hello1");printf("hello2");system("pause");}断点调试1. 实际需求在开发中,程序员发现⼀个⾮常诡异的错误,怎么看源代码都发现不了这个错误,这时⽼程序员就会温馨提⽰,可以使⽤断点调试,⼀步⼀步的看源码执⾏的过程,从⽽发现错误所在2.断点调试介绍断点调试是指⾃⼰在程序的某⼀⾏设置⼀个断点,调试时,程序运⾏到这⼀⾏就会停住,然后你可以⼀步⼀步的往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码⾏即显⽰错误,停下,然后程序可以进⾏分析从⽽找到这个BUG断点调试是程序员必须掌握的重要的技能使⽤断点调试也能帮助我们最终查看C程序代码的执⾏过程,提⾼程序员的⽔平3.断点调试的快捷键f5 开始调试,执⾏到下⼀个断点f11 逐句执⾏代码,会进⼊到函数体中f10 逐过程执⾏(遇到函数,跳出前,会将该函数执⾏完)shift+f5 终⽌调试shift+f11 跳出(跳出某个函数,跳出前,会将该函数执⾏完)4.断点调试应⽤案例看⼀下变量的变化情况void main(){int sum=0;//断点下在这⾥,然后使⽤f10(逐过程执⾏,可以看到各个变量的变化情况)int i=0;for(i=0;i<10;i++){sum+=i;printf("i=%d",i);printf("sum=%d",sum);}printf("退出for循环了");}5.断点调试应⽤案例2看⼀下数组越界的情况,当数组越界后,会输出⼀个为⽌的值void main(){int arr[]={1,2,3,4,5};int i=0;int len=sizeof(arr)/sizeof(int);for(i=0;i<=len;i++){printf("arr[%d]=%d",i,arr[i]);}}6.断点调试应⽤案例3演⽰如果进⼊到调⽤的函数体内,f11(进⼊到函数体),shift+f11(跳出函数) double cal2(int num1,int num2,char oper){double res=0.0;switch(oper){case '+':res=num1+num2;break;case '-':res=num1-num2;break;case '*':res=num1*num2;break;case '/':res=num1/num2;break;default:printf("你的运算符有误");}return res;}7.断点调试应⽤案例4#include<stdio.h>#include<stdlib.h>#include"myfun.h"void main(){int n1=10;int n2=40;char oper="+";double res=cal2(n1,n2,oper);printf("res=%.2f",res);printf("hello1");printf("hello2");system("pause");}。

lua 断点调试原理

lua 断点调试原理

lua 断点调试原理Lua是一种高效的轻量级脚本语言,常用于游戏开发和嵌入式设备中。

在 Lua 脚本的开发过程中,调试是不可避免的一环。

本文将介绍 Lua 的断点调试原理,帮助开发者更好地理解和利用 Lua 的调试功能。

在 Lua 中,调试器需要实现以下几个基本功能:1. 设置断点:在程序执行到某一行时,暂停程序的运行,等待程序员进行调试操作。

Lua 调试器通常会在代码行前面设置一个断点标记,表示该行是断点。

2. 单步执行:在程序停止运行的情况下,逐行执行代码,以便开发者查看程序执行过程中的变量值和输出结果。

3. 查看变量:开发者可以通过调试器查看变量的值,在调试过程中及时发现程序中的问题。

4. 修改变量:在程序停止运行的情况下,可以修改变量的值,以便测试程序的不同执行分支。

5. 继续执行:在调试过程中,开发者可以选择继续执行程序,直到下一个断点或程序结束。

实现上述功能的核心是使用 Lua 的 debug 库。

debug 库提供了若干函数,用于获取当前函数的信息、设置断点、获取变量值等操作。

以下是一些常用的函数:1. debug.getinfo(level, [what]):获取当前函数或指定函数的信息,包括函数名、行号、源文件位置等。

2. debug.sethook([func], [mask], [count]):设置钩子函数,用于在程序执行到指定位置时发生断点。

func 参数指定钩子函数,mask 参数指定钩子触发的事件,count 参数指定钩子调用的频率。

3. debug.getlocal(level, local):获取当前函数或指定函数的局部变量的值,local 参数指定变量名。

4. debug.setlocal(level, local, value):设置当前函数或指定函数的局部变量的值,local 参数指定变量名,value 参数指定变量的新值。

5. debug.debug():进入交互式调试模式,可以逐行执行代码并查看变量值。

lua断点调试(云风)

lua断点调试(云风)

---------------------------- bp.lua --------------------------local type=type local tostring=tostring local print=print local setmetatable=setmetatable local getfenv=getfenv local ipairs=ipairs local pairs=pairs local xpcall=xpcall local error=error local table_insert=table.insert local table_concat=table.concat local debug=debug module "bp" local nil_value={} local function traversal_r(tbl,num) num = num or 64 local ret={} local function insert(v) table_insert(ret,v) if #ret>num then error() end end local function traversal(e) if e==nil_value or e==nil then insert("nil,") elseif type(e)=="table" then insert("{") local maxn=0 for i,v in ipairs(e) do traversal(v)maxn=i end for k,v in pairs(e) do if not (type(k)=="number" and k>0 and k<=maxn) then if type(k)=="number" then insert("["..k.."]=") else insert(tostring(k).."=") end traversal(v) end end insert("}") elseif type(e)=="string" then insert('"'..e..'",') else insert(tostring(e)) insert(",") end end local err=xpcall( function() traversal(tbl) end, function() end ) if not err then table_insert(ret,"...") end return table_concat(ret) end function print_r(tbl,num) print(traversal_r(tbl,num)) end local function init_local(tbl,level) local n=1 local index={}while true do local name,value=debug.getlocal(level,n) if not name then break end if name~="(*temporary)" then if value==nil then value=nil_value end tbl[name]=value index["."]=n end n=n+1 end setmetatable(tbl,{__index=index}) return tbl end local function init_upvalue(tbl,func) local n=1 local index={} while true do local name,value=debug.getupvalue(func,n) if not name then break end if value==nil then value=nil_value end tbl[name]=value index["."]=n n=n+1 endsetmetatable(tbl,{__index=index}) return tbl endfunction dbg(level) level=level and level+2 or 2 local lv=init_local({},level+1) local func=debug.getinfo(level,"f").func local uv=init_upvalue({},func) local _L={} setmetatable(_L,{ __index=function(_,k) local ret=lv[k] return ret~=nil_value and ret or nil end, __newindex=function(_,k,v) if lv[k] then lv[k]= v~= nil and nil_value or v debug.setlocal(level+3,lv["."..k],v) else print("error:invalid local name:",k) end end, __tostring=function(_) return traversal_r(lv) end }) print("_L=",traversal_r(lv)) local _U={} setmetatable(_U,{ __index=function(_,k) local ret=uv[k] return ret~=nil_value and ret or nil end, __newindex=function(_,k,v) if uv[k] then uv[k]= v~= nil and nil_value or vdebug.setupvalue(func,uv["."..k],v) else print("error:invalid upvalue name",k) end end, __tostring=function(_) return traversal_r(uv) end }) print("_U=",traversal_r(uv)) local _G=getfenv(level) _G._L,_G._U=_L,_U debug.debug() _G._L,_G._U=nil,nil endlocal _bp_list={} local _bp_desc={} local function bp_list_name(name) local t=type(_bp_desc[name]) print("[".."]",_bp_list[name] and "on" or "off") if t=="table" then for _,v in ipairs(_bp_desc[name]) do print("----",v) end elseif t=="string" then print("---",_bp_desc[name]) end end local function bp_list(name) if name then bp_list_name(name) else for k,v in pairs(_bp_list) do bp_list_name(k)end end end local _bp_unnamed={} local _bp_unnamed_desc={} local _bp_unnamed_index={} local _bp_index=1 do local weak={__mode="kv"} setmetatable(_bp_unnamed,weak) setmetatable(_bp_unnamed_desc,{__mode="k"}) setmetatable(_bp_unnamed_index,weak) end local function bp_add_index() local info=debug.getinfo(3,"Slf") local func=info.func if _bp_unnamed[info.func]==nil then local desc=info.source.."(".currentline..")" _bp_unnamed[func]=true _bp_unnamed_desc[func]=desc _bp_unnamed_index[func]=_bp_index _bp_unnamed_index[_bp_index]=func _bp_index=_bp_index+1 end return _bp_unnamed[func],_bp_unnamed_index[func] end local _bp_named={} local _bp_named_desc={} local function bp_add_name(name) local info=debug.getinfo(3,"Sl") local desc=info.source.."(".currentline..")" if _bp_named[name]==nil then _bp_named[name]=false endlocal tbl=_bp_named_desc[name] if tbl then tbl[desc] = true else _bp_named_desc[name]={ [desc] = true } end return _bp_named[name],name end local function bp_show(n) if type(n)=="number" then local func=_bp_unnamed_index[n] if func==nil then error "invalid break point id" end print("break point:",n, _bp_unnamed[func] and "on" or "off", _bp_unnamed_desc[func] ) else print("break point:",n,_bp_named[n] and "on" or "off") if _bp_named_desc[n] then for k,v in pairs(_bp_named_desc[n]) do print("",k) end else print("\tundefined") end end end local function bp_show_all() for k,_ in pairs(_bp_unnamed) do bp_show(_bp_unnamed_index[k]) end for k,_ in pairs(_bp_named) do bp_show(k) endend function bp(n) local trigger,name if n==nil then trigger,name=bp_add_index() else trigger,name=bp_add_name(n) end if trigger then bp_show(name) dbg(1) else _bp_list[name]=false end end function trigger(n,on) on = on~=false if type(n)=="number" then local func=_bp_unnamed_index[n] if func==nil then error "invalid break point id" end _bp_unnamed[func]=on else _bp_named[n]=on end end function list(v) if v then bp_show(v) else bp_show_all() end endfunction error_handle(msg) print(msg) dbg(1) end可以这样测试一下:require "bp" function foo(arg) bp.bp() end =foo(0) -- 输出 foo(0) -- 设置一个匿名断点 return arg+1运行后会进入调试控制台: 可以发现断点被编了号(1 号)并被触发,局部变量放在 _L 这张表里可以直接操作,upvalue 放 在了 _U 表中 .break point: _L= _U=1on=stdin(2){arg=0,} {}我们可以改一下 arg 的值,如 _L.arg=1 然后 cont 退出控制台.可以发现 foo 函数返回了 2 . 这种匿名断点添加方便,而且断点跟随逻辑而不是和代码行做映射.也就是说,同一个 function 的不同实例(不同的 closure)可以有不同 id 的断点,单独控制. 我们也可以使用具名断点,方法是 bp.bp "bpname" 具名断点缺省是 disable 状态的.如果需要激活可以用 bp.trigger "bpname" . 给断点起名字的好处是,可以给一组断点起同一个名字,这样可以批量开关. bp.trigger(name,true/false) 用于开关断点,name 可以是字符串也可以是 id . 列出所有断点可以用 bp.list() 也可以用 bp.list(name) 来列出一个断点的状态,name 可以是字符串也可以是 id . 还有一种方式,就是把调试控制台用在错误处理函数中,这样函数一出错就自动切入控制 台. 方法是 xpcall(some_function,bp.error_handle) 下一步打算做单步执行 :D。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档