Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么回溯不包含Objective-C符号而不考虑-rdynamic?_Objective C_Linux_Gcc_Stack Trace_Glibc - Fatal编程技术网

为什么回溯不包含Objective-C符号而不考虑-rdynamic?

为什么回溯不包含Objective-C符号而不考虑-rdynamic?,objective-c,linux,gcc,stack-trace,glibc,Objective C,Linux,Gcc,Stack Trace,Glibc,更新:我正在Linux上使用GNU运行时。苹果运行时的MacOS上不会出现问题 更新2:我在MacOS上编译了GNU运行时,并用它构建了示例。该错误在带有GNU运行时的MacOS上不会发生。我认为问题在于glibc(因为backtrace和backtrace\u符号都是glibc扩展) 在GCC编译的Objective-C应用程序中使用backtrace和backtrace\u符号打印回溯时,我没有得到任何Objective-C符号。仅显示文件名、地址和C符号 我用-g编译,并用-rdynami

更新:我正在Linux上使用GNU运行时。苹果运行时的MacOS上不会出现问题

更新2:我在MacOS上编译了GNU运行时,并用它构建了示例。该错误在带有GNU运行时的MacOS上不会发生。我认为问题在于glibc(因为
backtrace
backtrace\u符号
都是glibc扩展)

在GCC编译的Objective-C应用程序中使用
backtrace
backtrace\u符号
打印回溯时,我没有得到任何Objective-C符号。仅显示文件名、地址和C符号

我用
-g
编译,并用
-rdynamic
链接

我的测试应用程序:

void _printTrace()
{
    void *addr[1024];
    int aCount = backtrace(addr, 1024);
    char **frameStrings = backtrace_symbols(addr, aCount);
    for (int i = 0; i < aCount; i++) {
        printf("%s\n", frameStrings[i]);
    }
    free(frameStrings);
}

@interface TheObject
+ (void)_printTrace;
+ (void)printTrace;
@end

@implementation TheObject
+ (void)_printTrace
{
    _printTrace();
}

+ (void)printTrace
{
    [self _printTrace];
}
@end

void printTrace()
{
    [TheObject printTrace];
}

int main(int argc, char **argv)
{
    printTrace();
    return 0;
}

有没有办法让Objective-C符号出现在此回溯中?

我希望您需要询问ObjC运行时有关地址的信息,以获取符号信息。例如,从backtrace()返回的地址可能会被传递到类似object_getClass()的对象以获取类。我没有尝试过这些方法,但在本例中,我将在下一步进行研究。

dladdr()
仅报告全局符号和弱符号。但所有Objective-C函数符号都是局部的:

$ readelf -s so_backtrace

Symbol table '.dynsym' contains 29 entries:
…

Symbol table '.symtab' contains 121 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
…
    49: 08048a01    13 FUNC    LOCAL  DEFAULT   14 _c_TheObject___printTrace
    50: 08048a0e    47 FUNC    LOCAL  DEFAULT   14 _c_TheObject__printTrace
…
您可以通过查看本地符号来验证是否从未返回本地符号
backtrace_symbols()
在sysdeps/generic/elf/backtracesyms.c中定义。它依赖于elf/dl addr.c中定义的
\u dl\u addr()
,为其提供符号名称。最终调用
determinate\u info()
。如果可以,它将使用,其中不包括设计上的本地符号:

49       /* We look at all symbol table entries referenced by the hash
50          table.  */
…
60                   /* The hash table never references local symbols so
61                      we can omit that test here.  */
如果GNU哈希表不存在,它将返回标准哈希表。这包括所有符号,但
determine\u info()
code会过滤掉除全局符号和弱符号以外的所有符号:

90         if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
91              || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)

要对Objective-C函数地址进行符号化,您必须自己执行查找,而不是过滤掉本地函数符号。此外,您必须要求Objective-C函数符号将
\u C\u TheObject\u\u printTrace
恢复到
+[TheObject\u printTrace]
GNUstep的
NSException
实现不使用
backtrace
,而是使用
libbfd
(二进制文件描述符)。我认为实际执行这项工作的函数叫做
static void find_address
,您可以查看它。通过这个简单的例子,我得到了下面的结果

#include <Foundation/Foundation.h>

@interface Test : NSObject {}
+ (void) test;
@end

@implementation Test
+ (void) test
{
    Class GSStackTrace = objc_getClass("GSStackTrace");

    id stack = [GSStackTrace currentStack];

    for (int i = 0; i < [stack frameCount]; i++)
    {
        NSLog (@"%@", [[stack frameAt:i] function]);
    }
}
@end

int main(int argc, char **argv)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [Test test];

    [pool release];

    return 0;
}
您可能能够分离
GSStackTrace
。它是一个“私有”类(这就是为什么我需要使用
objc_getClass
,您还将收到许多无法识别的选择器警告),但它似乎包含读取Objective-C类名所需的所有代码


在Ubuntu9.04上测试,GNUstep配置了
——启用调试(因此
GSFunctionInfo
包含在构建中)。

Woah这对我来说似乎是非常推测性的
backtrace
(和
backtrace\u符号
)是glibc扩展,后者依赖于链接器
-rdynamic
链接的符号。如果
backtrace
返回的地址适用于Objective-C运行时,我会感到惊讶,但我还是会尝试一下。好的,我查阅了运行时API。我正在使用GNU运行时,但没有找到用于获取符号地址的类或方法的函数。在GNU运行时中,没有
object\u getClass()
,而是一个
object\u get\u class()
来获取一个对象。但是我非常确定,
backtrace
的地址不是指向对象的。现在我确定:
backtrace
的地址既不是对象也不是类。如果我知道你在使用GNU运行时,我就不会回答了,因为我不知道那里有什么可用或不可用。你应该从一开始就说清楚。我可以提出其他建议,但不是那些与您的环境相关的建议。嗯,我认为运行时并不重要。尽管如此,我今天还是会在Mac上尝试这个例子,如果它真的在Mac上起作用,我会澄清这个问题。答案很好,但我的应用程序必须使用标准的glibc运行,我无法复制和更改glibc代码,因为一些细节(如
链接地图
结构的
成员是私有的)。要知道为什么我接受了你的答案但没有给你奖金,请阅读我对dreamlax答案的评论。你赢得奖金是因为你的答案让我实现了一个有用的StackTrace,而没有高级第三方库(如GNUStep;))。但我会接受杰里米的回答,因为我犯了错误,提出了两个问题:1。为什么stacktrace不包括Obj-C符号和2。如何使用Obj-C符号创建stacktrace。显然,我开始悬赏是为了得到第二个问题的答案。但是第一个是标题,所以我接受杰里米的回答。
#include <Foundation/Foundation.h>

@interface Test : NSObject {}
+ (void) test;
@end

@implementation Test
+ (void) test
{
    Class GSStackTrace = objc_getClass("GSStackTrace");

    id stack = [GSStackTrace currentStack];

    for (int i = 0; i < [stack frameCount]; i++)
    {
        NSLog (@"%@", [[stack frameAt:i] function]);
    }
}
@end

int main(int argc, char **argv)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [Test test];

    [pool release];

    return 0;
}
2010-10-18 14:14:46.188 a.out[29091] +[GSStackTrace currentStack]
2010-10-18 14:14:46.190 a.out[29091] +[Test test]
2010-10-18 14:14:46.190 a.out[29091] main
2010-10-18 14:14:46.190 a.out[29091] __libc_start_main