[llvm-dev] Debugging a metadata-emit problem, Bug #30413
Lobron, David via llvm-dev
llvm-dev at lists.llvm.org
Tue Jan 17 07:31:37 PST 2017
Hello llvm-dev,
I opened bug report 30413 a while ago, and I'd like to request help from someone with better knowledge of clang. The bug occurs on Linux, where clang does not emit type metadata when compiling Objective-C programs, as it does on the Mac, and as gcc does on Linux. My program uses that metadata to do type introspection (see below for an example).
>From code inspection, it appears that the type metadata is written by code in clang's ASTContext class. I wrote a test program, copied below, which reproduces this bug. I ran clang under gdb, and set a breakpoint on all the methods in the clang::ASTContext:: namespace, but I found that none of these were called (at least, none of the 571 breakpoints was triggered). I confirmed that other gdb breakpoints (e.g., on ::main) did get triggered, so I know that my breakpoints in general were working.
I was left with two questions:
- Are the clang::ASTContext:: methods not called when compiling an ObjC program?
- Is there some other part of the code where the metadata is emitted, if not from clang::ASTContext::? I looked for a quite a while, but I could not find a plausible candidate.
Any help would be appreciated! Feel free to reply to me directly, or to the list, or to post suggestions in the bug report here:
https://llvm.org/bugs/show_bug.cgi?id=30413
Thanks!
--David
My test program code is below. On a Mac, compiled with clang, the runtime can correctly introspect the type of an NSString* instance variable. The output is:
2017-01-17 10:26:21.333 TestClassMetadata[13856:3607976] Ivar type _intIvar does not appear to be an object-valued class: type is i
2017-01-17 10:26:21.334 TestClassMetadata[13856:3607976] Ivar type _doubleVar does not appear to be an object-valued class: type is d
2017-01-17 10:26:21.334 TestClassMetadata[13856:3607976] Introspected class NSString for ivar name _stringIvar
On Linux, compiled with clang, the NSString introspection does not work, because the metadata is not present. The output there is:
2017-01-17 15:27:15.641 TestClassMetadata[32308:32308] Ivar type _intIvar does not appear to be an object-valued class: type is i
2017-01-17 15:27:15.661 TestClassMetadata[32308:32308] Ivar type _doubleVar does not appear to be an object-valued class: type is d
2017-01-17 15:27:15.661 TestClassMetadata[32308:32308] Ivar type _stringIvar does not appear to be an object-valued class: type is @
(Note the difference in the last lines).
Program code:
#import <Foundation/Foundation.h>
#ifdef __APPLE__
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#endif
@interface TestClass : NSObject {
@public
int _intIvar;
double _doubleVar;
NSString *_stringIvar;
}
- (id)init;
- (void)sayHello:(NSString *)txt;
@end
@implementation TestClass
- (void)sayHello:(NSString *)txt
{
[_stringIvar release];
_stringIvar = [txt retain];
NSLog(@"%@", _stringIvar);
}
- (void)dealloc
{
[_stringIvar release];
[super dealloc];
}
- (id)init {
if ((self = [super init]) != nil) {
unsigned i;
Class c = [self class];
NSAssert(c != 0, @"Could not get class object");
unsigned ivarCount;
Ivar *ivarList = class_copyIvarList(c, &ivarCount);
for (i = 0; i < ivarCount; i++) {
Ivar ivar = ivarList[i];
const char *ivarCname = ivar_getName(ivar);
if (ivarCname != 0) {
NSString *ivarName = [NSString stringWithUTF8String:ivarCname];
const char *ivarType = ivar_getTypeEncoding(ivar);
if (ivarType[0] == '@' && ivarType[1] == '"') {
NSString *className = [[[NSString alloc] initWithBytes: &ivarType[2]
length: strlen(&ivarType[2])-1
encoding: NSUTF8StringEncoding] autorelease];
Class c = NSClassFromString(className);
if (c == nil) {
NSLog(@"WARNING: unknown class name \"%@\" in declaration of %@", className, [self class]);
} else {
NSLog(@"Introspected class %@ for ivar name %@",
className, ivarName);
}
} else {
NSLog(@"Ivar type %s does not appear to be an object-valued class: type is %s", ivarCname, ivarType);
}
}
}
if (ivarList)
free(ivarList);
}
return self;
}
@end
int main() {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
TestClass *c = [[[TestClass alloc] init] autorelease];
[pool release];
return 0;
}
More information about the llvm-dev
mailing list