Next round of DWARF issues/questions

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),
i6 4 mul (i64 ptrtoint (%tart.core.Object* getelementptr ({ i1, %tart.core.Object }* null, i64 0, i32 1) to i64), i64 8),
i64 0, i32 0, null, metadata !16, i32 0, null} ; [ DW_TAG_class_type ]

However, when I print out the debugging information via dwarfdump, you can see that the size of the object is zero:

<1>< 2233> DW_TAG_class_type
DW_AT_sibling <2295>
DW_AT_name tart.core.Object
DW_AT_byte_size 0
DW_AT_decl_file 65
DW_AT_decl_line 9
<2>< 2258> DW_TAG_member
DW_AT_name __tib
DW_AT_type <2228>
DW_AT_decl_file 65
DW_AT_decl_line 10
DW_AT_data_member_location DW_OP_plus_uconst 0
<2>< 2274> DW_TAG_member
DW_AT_name __gcstate
DW_AT_type <156>
DW_AT_decl_file 65
DW_AT_decl_line 11
DW_AT_data_member_location DW_OP_plus_uconst 0

In addition, it appears that all of the field offsets are zero as well - see the DIEs immediately following the class definition.

#2) I can’t seem to get llvm.dbg.declare() to work for local variables, although it appears to work fine for function parameters. For example, look at the following snippet of IR:

define {} @ReflectionTest.testModuleReflection(%ReflectionTest* %self) gc “tart-gc” {

prologue:

%m = alloca %tart.reflect.Module*

call void @llvm.dbg.value(metadata !{%ReflectionTest* %self}, i64 0, metadata !1176)

call void @llvm.dbg.declare(metadata !{%tart.reflect.Module** %m}, metadata !1177)

%0 = bitcast %tart.reflect.Module** %m to i8**, !dbg !1178

call void @llvm.gcroot(i8** %0, i8* null), !dbg !1178

In the debugger, I can examine the value of ‘self’, however when I attempt to print the value of ‘m’, gdb reports ‘No symbol “m” in current context.’

#3) When I use the -ka option with dwarfdump, I get tons of errors of the following form:

<1>< 616> DW_TAG_class_type

DW_AT_sibling <791>

DW_AT_name tart.reflect.NameTable

DW_AT_byte_size 0

*** DWARF CHECK: DW_AT_decl_file: does not point to valid file info ***

DW_AT_decl_file 65

DW_AT_decl_line 6

However, I’ve double- and triple-checked my code. The code that generates a DIFile looks like this:

DASSERT(srcPath.isAbsolute());

DASSERT(dbgCompileUnit_.Verify());

file = dbgFactory_.CreateFile(

srcPath.getLast(),

srcPath.getDirname(),

dbgCompileUnit_);

And you can see in the earlier example that I’m passing the generated DIFile to CreateComplexTypeEx.

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

i6 4 mul (i64 ptrtoint (%tart.core.Object* getelementptr ({ i1, %tart.core.Object }* null, i64 0, i32 1) to i64), i64 8),
i64 0, i32 0, null, metadata !16, i32 0, null} ; [ DW_TAG_class_type ]

However, when I print out the debugging information via dwarfdump, you can see that the size of the object is zero:

<1>< 2233> DW_TAG_class_type
DW_AT_sibling <2295>
DW_AT_name tart.core.Object
DW_AT_byte_size 0
DW_AT_decl_file 65
DW_AT_decl_line 9
<2>< 2258> DW_TAG_member
DW_AT_name __tib
DW_AT_type <2228>
DW_AT_decl_file 65
DW_AT_decl_line 10
DW_AT_data_member_location DW_OP_plus_uconst 0
<2>< 2274> DW_TAG_member
DW_AT_name __gcstate
DW_AT_type <156>
DW_AT_decl_file 65
DW_AT_decl_line 11
DW_AT_data_member_location DW_OP_plus_uconst 0

In addition, it appears that all of the field offsets are zero as well - see the DIEs immediately following the class definition.

#2) I can’t seem to get llvm.dbg.declare() to work for local variables, although it appears to work fine for function parameters. For example, look at the following snippet of IR:

define {} @ReflectionTest.testModuleReflection(%ReflectionTest* %self) gc “tart-gc” {

prologue:

%m = alloca %tart.reflect.Module*

call void @llvm.dbg.value(metadata !{%ReflectionTest* %self}, i64 0, metadata !1176)

call void @llvm.dbg.declare(metadata !{%tart.reflect.Module** %m}, metadata !1177)

%0 = bitcast %tart.reflect.Module** %m to i8**, !dbg !1178

call void @llvm.gcroot(i8** %0, i8* null), !dbg !1178

In the debugger, I can examine the value of ‘self’, however when I attempt to print the value of ‘m’, gdb reports ‘No symbol “m” in current context.’

Are using -O0? You do not have line number info with dbg.declare intrinsic. FWIW, following works …

define void @foo() nounwind ssp {
entry:
%i = alloca i32, align 4
call void @llvm.dbg.declare(metadata !{i32* %i}, metadata !5), !dbg !8
store i32 2, i32* %i, align 4, !dbg !9
ret void, !dbg !10
}

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

I’m not sure I understand what you are saying - isn’t llvm::ConstantExpr::getSizeOf() and llvm::ConstantExpr::getAlignOf() the proper way to compute the size and alignment of a field? If those functions can’t be used for debug info, then that’s really inconvenient - I don’t want to have to write my own calculations for it, since (a) I’m likely to get it wrong in some subtle way, and (b) I’d be duplicating code, since the same calculations need to be done in a lot of other places.

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

i6 4 mul (i64 ptrtoint (%tart.core.Object* getelementptr ({ i1, %tart.core.Object }* null, i64 0, i32 1) to i64), i64 8),
i64 0, i32 0, null, metadata !16, i32 0, null} ; [ DW_TAG_class_type ]

However, when I print out the debugging information via dwarfdump, you can see that the size of the object is zero:

<1>< 2233> DW_TAG_class_type
DW_AT_sibling <2295>
DW_AT_name tart.core.Object
DW_AT_byte_size 0
DW_AT_decl_file 65
DW_AT_decl_line 9
<2>< 2258> DW_TAG_member
DW_AT_name __tib
DW_AT_type <2228>
DW_AT_decl_file 65
DW_AT_decl_line 10
DW_AT_data_member_location DW_OP_plus_uconst 0
<2>< 2274> DW_TAG_member
DW_AT_name __gcstate
DW_AT_type <156>
DW_AT_decl_file 65
DW_AT_decl_line 11
DW_AT_data_member_location DW_OP_plus_uconst 0

In addition, it appears that all of the field offsets are zero as well - see the DIEs immediately following the class definition.

#2) I can’t seem to get llvm.dbg.declare() to work for local variables, although it appears to work fine for function parameters. For example, look at the following snippet of IR:

define {} @ReflectionTest.testModuleReflection(%ReflectionTest* %self) gc “tart-gc” {

prologue:

%m = alloca %tart.reflect.Module*

call void @llvm.dbg.value(metadata !{%ReflectionTest* %self}, i64 0, metadata !1176)

call void @llvm.dbg.declare(metadata !{%tart.reflect.Module** %m}, metadata !1177)

%0 = bitcast %tart.reflect.Module** %m to i8**, !dbg !1178

call void @llvm.gcroot(i8** %0, i8* null), !dbg !1178

In the debugger, I can examine the value of ‘self’, however when I attempt to print the value of ‘m’, gdb reports ‘No symbol “m” in current context.’

Are using -O0? You do not have line number info with dbg.declare intrinsic. FWIW, following works …

define void @foo() nounwind ssp {
entry:
%i = alloca i32, align 4
call void @llvm.dbg.declare(metadata !{i32* %i}, metadata !5), !dbg !8
store i32 2, i32* %i, align 4, !dbg !9
ret void, !dbg !10
}

Hmm, well I modified the front-end to add the line number on the dbg.declare, and I still have the same problem - the debugger can see the function parameter ‘self’ but not the local variable ‘m’. Here’s what the IR looks like for me:

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

I’m not sure I understand what you are saying - isn’t llvm::ConstantExpr::getSizeOf() and llvm::ConstantExpr::getAlignOf() the proper way to compute the size and alignment of a field? If those functions can’t be used for debug info, then that’s really inconvenient - I don’t want to have to write my own calculations for it, since (a) I’m likely to get it wrong in some subtle way, and (b) I’d be duplicating code, since the same calculations need to be done in a lot of other places.

llvm::Constant* refers to llvm struct and fields. They do not necessarily map directly to source lang structs and fields. Debugging information cares about size, offset and alignment as per lang. That said, if anyone prepares appropriate DebugInfo and Dwarfwriter patches then I won’t oppose.

Devang

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

I’m not sure I understand what you are saying - isn’t llvm::ConstantExpr::getSizeOf() and llvm::ConstantExpr::getAlignOf() the proper way to compute the size and alignment of a field? If those functions can’t be used for debug info, then that’s really inconvenient - I don’t want to have to write my own calculations for it, since (a) I’m likely to get it wrong in some subtle way, and (b) I’d be duplicating code, since the same calculations need to be done in a lot of other places.

llvm::Constant* refers to llvm struct and fields. They do not necessarily map directly to source lang structs and fields. Debugging information cares about size, offset and alignment as per lang. That said, if anyone prepares appropriate DebugInfo and Dwarfwriter patches then I won’t oppose.

First, apologies for responding to this after such a long interval.

So I think I understand what you are saying here, although the way that I would say it is “Dwarfwriter doesn’t understand constant expressions, only simple constants”. At least, when I changed my code to use simple constants instead of ConstantExpr::getSizeOf(), it worked.

Also, in my original message in this thread, I listed 3 issues. The one we’ve been discussing is issue #1 (class sizes coming out as zero) which I will consider solved. However, I never did figure out the answers to the other two issues I mentioned: 2) llvm.dbg.declare() not working for local variables, and 3) dwarfdump printing lots of errors when trying to dump a module produced by my frontend - even though when I check the debug info manually it all appears to be correct.

After to speaking to Devang and a number of other people at the developer’s conference, I was able to make some forward progress on getting debugging to work. I’m now able to actually single-step through my program and set breakpoints, and examine function parameters.

However, I’m also seeing a lot of new problems which weren’t exposed before. After spending the better part of two days working on them, I’d like to describe them here and get some advice on what I might be doing wrong.

#1) Class sizes coming out as zero.

In my frontend, I call DebugFactory::CreateCompositeTypeEx as follows:

DICompositeType di = dbgFactory_.CreateCompositeTypeEx(
type->typeClass() == Type::Class ? dwarf::DW_TAG_class_type : dwarf::DW_TAG_structure_type,
dbgCompileUnit_,
type->typeDefn()->linkageName().c_str(),
genDIFile(type->typeDefn()),
getSourceLineNumber(type->typeDefn()->location()),
getSizeOfInBits(type->irType()),
getAlignOfInBits(type->irType()),
getInt64Val(0), 0,
DIType(),
dbgFactory_.GetOrCreateArray(members.data(), members.size()));

The ‘getSizeOfInBits()’ function and the others like it basically call llvm::ConstantExpr::getSizeOf() and then multiple the result by 8. Looking at the generated IR, I can see that the expressions look correct to me (I’ve added some line breaks for clarity):

!15 = metadata !{i32 589826, metadata !2, metadata !“tart.core.Object”, metadata !12, i32 9,
i64 mul (i64 ptrtoint (%tart.core.Object* getelementptr (%tart.core.Object* null, i32 1) to i64), i64 8),

This does not work. The DebugInfo accessors uses getSizeInBits() to get an integer for the size. You will have to modify it to get the value.

I’m not sure I understand what you are saying - isn’t llvm::ConstantExpr::getSizeOf() and llvm::ConstantExpr::getAlignOf() the proper way to compute the size and alignment of a field? If those functions can’t be used for debug info, then that’s really inconvenient - I don’t want to have to write my own calculations for it, since (a) I’m likely to get it wrong in some subtle way, and (b) I’d be duplicating code, since the same calculations need to be done in a lot of other places.

llvm::Constant* refers to llvm struct and fields. They do not necessarily map directly to source lang structs and fields. Debugging information cares about size, offset and alignment as per lang. That said, if anyone prepares appropriate DebugInfo and Dwarfwriter patches then I won’t oppose.

First, apologies for responding to this after such a long interval.

So I think I understand what you are saying here, although the way that I would say it is “Dwarfwriter doesn’t understand constant expressions, only simple constants”. At least, when I changed my code to use simple constants instead of ConstantExpr::getSizeOf(), it worked.

Also, in my original message in this thread, I listed 3 issues. The one we’ve been discussing is issue #1 (class sizes coming out as zero) which I will consider solved. However, I never did figure out the answers to the other two issues I mentioned: 2) llvm.dbg.declare() not working for local variables, and 3) dwarfdump printing lots of errors when trying to dump a module produced by my frontend - even though when I check the debug info manually it all appears to be correct.

Also, there’s another issue I wanted to mention: I have noticed that debugging and inlining don’t play very well together. Even if other optimizations are disabled, if I turn on inlining, I get null pointer errors in this piece of code in DwarfDebug::constructInlinedScopeDIE():

  **if** (!Scope->getScopeNode())
    **return** NULL;
  DIScope DS(Scope->getScopeNode());
  DIE *ScopeDIE = **new** DIE(dwarf::DW_TAG_inlined_subroutine);

  DISubprogram InlinedSP = getDISubprogram(DS);
  CompileUnit *TheCU = getCompileUnit(InlinedSP);
  DIE *OriginDIE = TheCU->getDIE(InlinedSP);
  assert(OriginDIE && **"Unable to find Origin DIE!"**);
  addDIEEntry(ScopeDIE, dwarf::DW_AT_abstract_origin,
              **dwarf**::DW_FORM_ref4, OriginDIE);

What’s happening is that InlinedSP.DbgNode is NULL, which causes getCompileUnit() to assert.

Note that this occurs in both llc and my linker (tartln) because they both use the same set of passes to generate machine code. So basically whenever I want to debug, I have to disable inlining.

Also, in my original message in this thread, I listed 3 issues. The one we’ve been discussing is issue #1 (class sizes coming out as zero) which I will consider solved.

ok

However, I never did figure out the answers to the other two issues I mentioned: 2) llvm.dbg.declare() not working for local variables,

I suggest, you try looking at LLVM IR generated for small c test cases by Clang to understand what is missing link in your FE generated LLVM IR.

and 3) dwarfdump printing lots of errors when trying to dump a module produced by my frontend - even though when I check the debug info manually it all appears to be correct.

I am assuming same dwarfdump error is repeated multiple times. Only thing I can suggest is get as small as possible LLVM IR where dwarfdump produces one or two errors and attach it to bugzilla PR.

Please file a bugzilla PR with a reproduce testcase. A small LLVM IR which I can feed to llc to reproduce this crash should be good enough.
Thanks,