我正在尝试使用 python LLDB 库打印出一个 char ** 。 需要明确的是,C 程序中 main 函数中的 char **argv 。 输入的数组中应该有 3 个字符串。
启动 C 程序并立即停止时 主要(int argc,字符**argv) 在 xcode 中,我只需执行 p argv[0] 和 p argv[1] 即可获得要打印的正确参数字符串。
在 python 中,我有一个函数可以打印前 2 个 argv 字符串
def print_argv(argv: lldb.SBValue, target:SBTarget):
pointer = argv.Dereference()
summary = pointer.GetSummary().strip('\"')
print(summary)
str_len = len(summary)
next_str_address:int = pointer.GetLoadAddress() + str_len + 1
pointer_type = pointer.GetType()
addr = SBAddress(next_str_address, target)
next_value = target.CreateValueFromAddress("argv", addr, pointer_type)
summary = next_value.GetSummary().strip('\"')
但是第二个输入不存在。
我尝试了多种不同的方法,但我看不到获得第二根字符串。我尝试使用 argv.GetChildAtIndex ,它适用于 0,但不适用于 1 或 2。我注意到地址按字符串长度偏移,所以我尝试更新指针,再次没有运气。我通过从 C 程序中打印出来来检查输入是否确实存在。
编辑: 以下是如何设置对打印功能的调用
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(False)
target = debugger.CreateTargetWithFileAndArch (str(binary_path), lldb.LLDB_ARCH_DEFAULT)
assert target, "Failed to create target"
target.BreakpointCreateByName ("main", target.GetExecutable().GetFilename())
launch_info = lldb.SBLaunchInfo(str_args)
launch_info.SetWorkingDirectory(os.getcwd())
error = lldb.SBError()
process = target.Launch(launch_info, error)
assert process, "Failed to launch process"
for _ in range(1000):# Putting an upper limit on the number of functions to trace
state = process.GetState()
if state == lldb.eStateStopped:
for thread in process:
function_name = frame.GetFunctionName()
frame = thread.frames[0]
if function_name in function_names:
for arg in frame.arguments:
if arg.name == "argv":
print_argv(arg, 3, target)
process.Continue()
解决方案: 结果你需要使用 can_create_synthetic==True 。
child = argv.GetChildAtIndex(1, lldb.eNoDynamicValues, True)
这是一个通用的C vrs。调试器问题,因为 C 允许未指定大小的数组,因此它不会给调试器提供有关如何检查的提示。正如您所发现的,如果您告诉它可以创建“合成子项”来表示元素,那么要解决此问题,lldb 将为您动态自动调整未大小数组的大小。
但是由于您也知道数组的大小(
argc
),因此还有一种更直接且“正确”的方法来执行此操作:
lldb 的 SBType 有一个
SBType::GetArrayType(uint64_t size)
API,它将从任何 C 类型返回给定大小的固定大小数组的类型。因此,实现打印机的简单方法是将 argc
和 argv
传递给打印函数。正如您所做的那样,从 argv
变量获取指针类型,然后使用指针类型上的 argc
调用创建一个包含 GetArrayType(argc)
元素的数组类型,并使用它代替 CreateValueFromAddress
中的指针类型
.
然后你将得到一个自然具有正确数量的子级的数组,并且你不会冒险意外获取太多元素等。它也没有那么神奇,如果你必须弄清楚这是如何实现的,这很有用经过足够长的时间,你已经忘记了魔法之后,它会再次起作用......