如何获取 iOS 中任意线程的正确帧指针?

2024-03-20

获取帧指针的方法

在 iPhone 5s 设备/Xcode 7 上运行的演示应用程序上,我尝试获取frame pointer of an 随意的线程使用thread_get_state http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html,但总是会导致错误的结果:

- (BOOL)fillThreadState:(thread_t)thread intoMachineContext:(_STRUCT_MCONTEXT *)machineContext {
    mach_msg_type_number_t state_count = MACHINE_THREAD_STATE_COUNT;
    kern_return_t kr = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count);
    if (kr != KERN_SUCCESS) {
        char *str = mach_error_string(kr);
        printf("%s\n", str);
        return NO;
    }

    return YES;
}

我这样读取帧指针:uintptr_t fp = machineContext.__ss.__fp;,根据苹果文档(ARMv6 https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html and ARM64 https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW1),

寄存器 R7 在 ARMv6 上用作帧指针

而 ARM64 上的 x29

帧指针寄存器 (x29) 必须始终寻址有效的帧记录,尽管某些函数(例如叶函数或尾部调用)可能选择不在该列表中创建条目。因此,即使没有调试信息,堆栈跟踪也始终是有意义的。

_STRUCT_ARM_THREAD_STATE64
{
    __uint64_t    __x[29];  /* General purpose registers x0-x28 */
    __uint64_t    __fp;     /* Frame pointer x29 */
    __uint64_t    __lr;     /* Link register x30 */
    __uint64_t    __sp;     /* Stack pointer x31 */
    __uint64_t    __pc;     /* Program counter */
    __uint32_t    __cpsr;   /* Current program status register */
    __uint32_t    __pad;    /* Same size for 32-bit or 64-bit clients */
};

证明帧指针错误的方法

我如何证明 fp (machineContext.__ss.__fp) 不是一个正确的帧指针?

  1. 如果参数是当前线程,例如mach_thread_self(),则fp 始终为 0,这不同于__builtin_frame_address(0);

  2. 如果参数不是当前线程,例如主线程,则指向上一帧的指针fp在两到三个帧中将为 NULL,这对于正常的堆栈帧链接列表来说太短了;

  3. 仍然不是当前线程,我使用打印出调用堆栈地址backtrace之前在主线程上sleep。然后在另一个线程上,我挂起主线程并使用读取帧指针thread_get_state为了遍历调用堆栈,两个回溯缓冲区完全不同;

是什么让我困惑

苹果文档 https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW1 says 帧指针寄存器 (x29) 必须始终寻址有效的帧记录,但我可以读到ZERO从中获得价值。

此外,ARM Doc http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf states 在过程调用标准的所有变体中,寄存器 r16、r17、r29 和 r30 都具有特殊作用。在这些角色中他们 用于保存地址时标记为 IP0、IP1、FP 和 LR.

下面是部分示例_STRUCT_MCONTEXT的值:

Printing description of machineContext:
(__darwin_mcontext64) machineContext = {
  __es = (__far = 0, __esr = 0, __exception = 0)
  __ss = {
    __x = {
      [0] = 292057776134
      [1] = 6142843584
      [2] = 3
      [3] = 40
      [4] = 624
      [5] = 17923
      [6] = 0
      [7] = 0
      [8] = 3968
      [9] = 4294966207
      [10] = 3603
      [11] = 70
      [12] = 0
      [13] = 33332794515418112
      [14] = 0
      [15] = 4294967295
      [16] = 4294967284
      [17] = 18446744073709551585
      [18] = 4295035980
      [19] = 0
      [20] = 0
      [21] = 0
      [22] = 17923
      [23] = 624
      [24] = 6142843584
      [25] = 3
      [26] = 40
      [27] = 3
      [28] = 0
    }
    __fp = 0
    __lr = 6142843568
    __sp = 6877072044
    __pc = 6142843488
    __cpsr = 2582105136
    __pad = 1
  }
  __ns = {

我在寻找什么

我现在正在寻找一种方法来获取正确的值Frame Pointer任意线程的.

谢谢你的帮助!

UPDATE 1

当然,我想要的是得到正确的Frame Pointer任意线程的叶堆栈帧,然后沿着调用堆栈Previous Pointer of the Frame pointer.

在此之前,我已阅读这些链接:

获取其他线程的回溯 https://stackoverflow.com/questions/6402160/getting-a-backtrace-of-other-thread

如何在 iPad 应用程序中循环所有活动线程 https://stackoverflow.com/questions/6351229/how-to-loop-through-all-active-thread-in-ipad-app

从另一个线程打印堆栈跟踪 https://stackoverflow.com/questions/4765158/printing-a-stack-trace-from-another-thread

再次感谢。

UPDATE 2

我在其他平台上尝试过,但结果相同:错误的帧指针.

- (uintptr_t)framePointerOfMachineContext:(_STRUCT_MCONTEXT *)machineContext {
#if defined (__i386__)
    return machineContext->__ss.__ebp;
#endif

#if defined (__x86_64__)
    return machineContext->__ss.__rbp;
#endif

#if defined (__arm64__)
    return machineContext->__ss.__fp;
#endif
}

价值framePointerOfMachineContext返回的结果不一样__builtin_frame_address(0).

UPDATE 3

受到同事的启发,我尝试了内联汇编并在 i386 上实现了:

uintptr_t ebp = 1;
__asm__ ("mov %%ebp, %0;"
         :"=r"(ebp));

uintptr_t builtinFP = (uintptr_t)__builtin_frame_address(0);

Now ebp变量保持相同的值builtinFP的。但是如何在任意线程上做到这一点呢?


我最终发现了问题,

- (BOOL)fillThreadState:(thread_t)thread intoMachineContext:(_STRUCT_MCONTEXT *)machineContext {
    mach_msg_type_number_t state_count = MACHINE_THREAD_STATE_COUNT;
    kern_return_t kr = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count);
    if (kr != KERN_SUCCESS) {
        char *str = mach_error_string(kr);
        printf("%s\n", str);
        return NO;
    }

    return YES;
}

thread_get_state可以,但参数应该是特定于架构的,例如x86_THREAD_STATE32, x86_THREAD_STATE64等等。

我对宏的理解有误MACHINE_THREAD_STATE,这给了我不同架构的普遍意义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何获取 iOS 中任意线程的正确帧指针? 的相关文章

  • 无法读取未定义的属性“messageHandlers”

    我想将 JavaScript 变量传递给 Swift 我在 JavaScript 中遇到错误并进行了搜索 但没有得到任何结果 错误是 类型错误 无法读取未定义的属性 messageHandlers 任何人都可以帮忙吗 我在 Xcode 中的
  • C# 按下按钮时跳出循环

    我有一个简单的 C foreach 循环 如何在按下按钮时跳出循环 它不在backgroundWorker线程中 所以我不能使用backgroundWorker Cancellation Pending 在表单中创建一个布尔标志 将事件处理
  • 如何更改 GridView 内 ListViewItemPresenter 中的 SelectedBackground

    我在 SubSection 中有一个 Clickable Gridview
  • 如何使用 swift 隐藏导航控制器中的后栏按钮

    在故事板 Xcode 6 iOS 8 和 swift 中 我在导航控制器中嵌入了 TableViewController 从对象库中 我拖放一个栏按钮项目作为后退按钮 它显示一个图标图像 当我单击该按钮时 我显示一个设置视图 我怎样才能隐藏
  • 如何在 Xamarin.Forms 中强制使用浅色模式?

    我的应用程序的 UI 设计为在灯光模式下使用 但如果手机的默认主题是深色模式 我的应用程序也会切换到深色模式 并且 UI 看起来很垃圾 所以我想强制我的应用程序使用灯光模式 我怎样才能做到这一点 In my app xaml我使用的文件Us
  • 无法使用 MinGW C++ 在 NetBeans IDE 7.3 中编译“Hello World”

    我正在尝试制作一个简单的 Hello World 在 NetBeans IDE 7 3 中使用 MinGW 作为我的 C 编译器来编写程序 我遇到了构建失败的情况 但我不知道为什么 这是我的编译器设置 Family MinGW 基本目录 C
  • JObject ToString 与 StringEnumConverter 不起作用

    我正在尝试序列化一个匿名类 如下所示 public enum ErrorCode A B C var response JObject FromObject new Error new Message Test Code ErrorCode
  • 如何设置属性选择器的值 Expression>

    我需要使用模式工厂的想法将 Person 类实体中的实体属性 Address 与 FactoryEntities 类中的表达式 linq 相关联 看看这就是我所拥有的并且我想要做的 Address address new Address a
  • boost::unordered_map 是...有序的吗?

    我有一个 boost unordered map 但它看起来是有序的 给我一种压倒性的 你做错了 的感觉 为什么输出是这样的 我希望底层的哈希算法能够随机化这个顺序 include
  • 提高 ASP.NET/C# 编译速度的最佳方法是什么?

    更新 请将您的答案集中在硬件解决方案上 您使用什么硬件 工具 插件来提高 ASP NET 编译和首次执行速度 我们正在寻找固态硬盘来加快速度 但现在价格确实很高 我现在有两个 RAID 0 的 7200 rpm 硬盘 但我对性能不再满意 所
  • Windows Phone 8.1 应用程序多语言

    我正在使用 Visual Studio 2015 在 SilverLight 中创建 Windows Phone 应用程序 8 1 我正在用英语和阿拉伯语创建多语言应用程序 为此 我在项目中创建了 Strings 文件夹 其中包含 en U
  • 拦截C# HttpClient GetAsync

    我有一个 Web 项目 C MVC5 但没有 WebAPI 和一个简单的 HTTP REST 客户端 该客户端调用外部 REST 服务并获取 accessToken 等 我想检查所有 Get PostAsync 调用对 statusCode
  • 为什么这是一个未定义的行为?

    我的回答这个问题 https stackoverflow com q 18706587 845092这个函数是 inline bool divisible15 unsigned int x 286331153 2 32 1 15 40086
  • 产量回报延迟迭代问题

    我知道yield return 利用了延迟加载 但我想知道我是否可能滥用迭代器或者很可能需要重构 我的递归迭代器方法返回给定的所有祖先PageNode包括pageNode itself public class PageNodeIterat
  • C# 中的自定义按钮:如何删除悬停背景?

    我正在尝试使用 Visual Studio 2005 对我的表单 其 FormBorderStyle none 执行自定义按钮 我在链接到该按钮的 ImageList 中有我的 3 种状态按钮图像 this btnClose AutoSiz
  • 初学者友好的方法来获取所有文件和目录的列表

    使用 NET 3 0 我得到了下面的方法 它可以正确返回指定目录的所有文件和目录 以及子目录 的集合 如果可能的话 我想将其简化为仅使用我非常熟悉的结构 具体来说 有以下几点我不太清楚 1 IEnumerable
  • iOS 中的设备兼容性问题

    我们上传了一个应用程序 在第一个版本中 我们添加了设备功能 电话 以限制信息 plist 中的 iPhone 设备 在第二个版本中 我们忘记添加 电话 并提交给了应用商店 我们计划上传第三个版本 其中设备功能为 电话 但在提交到 App S
  • UITabBar 显示更多图标而不是“更多”选项

    我目前正在尝试使用UITabBar对于包含 7 个的 iOS 应用程序tabBar Items 当我使用故事板时 我能够实现所有 7 个目标tabBarItems 当我以编程方式添加tabBarItems 它强制 更多 按钮访问其他 tab
  • 如何在 C++ 中打印变量的名称? [复制]

    这个问题在这里已经有答案了 可能的重复 在C中获取变量名称的编程方法 https stackoverflow com questions 1623111 programmatic way to get variable name in c
  • iOS 所需的设备功能自动对焦相机

    我有一个 iOS 应用程序 我在其中设置Required Device Capabilities配置设置需要两者still camera and auto focus camera因为它需要在具有更好的自动对焦相机传感器的新一代设备上运行

随机推荐