This is an archive of the discontinued LLVM Phabricator instance.

support debug info for alias variable
Needs ReviewPublic

Authored by kamleshbhalui on May 25 2021, 5:51 PM.

Details

Summary

consider below test demonstration
$cat test.c
int oldname = 1;
extern int newname attribute((alias("oldname")));

$clang -g -O0 test.c

$gdb a.out
(gdb) pt oldname
type = int
(gdb) pt newname
type = <data variable, no debug info>
(gdb) p newname
'newname' has unknown type; cast it to its declared type

debugger is unable to print newname types and value because clang does not emit debug info for newname.
This patch supports having debug info for alias variable as imported entity.

Fixes PR50052.

Diff Detail

Event Timeline

kamleshbhalui created this revision.May 25 2021, 5:51 PM
kamleshbhalui requested review of this revision.May 25 2021, 5:51 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 25 2021, 5:51 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

Looks like GCC emits aliases as a DW_TAG_variable without a location, not as a DW_TAG_imported_declaration - what gave you the inspiration to do it in this way? (I think it's probably good, but DWARF doesn't lend itself to novelty so much... can be good to stick with how other folks already do things since it'll be what consumers already know how to handle)

How's this work if the alias target isn't declared in the source - but in inline assembly instead? (I guess GCC probably handles that OK, but the Clang strategy here might not cope with it)

Looks like GCC emits aliases as a DW_TAG_variable without a location, not as a DW_TAG_imported_declaration - what gave you the inspiration to do it in this way? (I think it's probably good, but DWARF doesn't lend itself to novelty so much... can be good to stick with how other folks already do things since it'll be what consumers already know how to handle)

How's this work if the alias target isn't declared in the source - but in inline assembly instead? (I guess GCC probably handles that OK, but the Clang strategy here might not cope with it)

what gave you the inspiration to do it in this way?

Actually, I got the idea from the discussion in the defect.

How's this work if the alias target isn't declared in the source

gcc spec says that alias target has to be in the same source.
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
it would be great if you share an example if I misunderstood you.

umesh.kalappa0 added inline comments.
clang/lib/CodeGen/CGDebugInfo.cpp
4948

Var is never used in the EmitGlobalAlias ,we don't need the same.

clang/lib/CodeGen/CodeGenModule.cpp
4929

this should be other way right i.e if(!getCodeGenOpts().hasReducedDebugInfo())

clang/lib/CodeGen/CGDebugInfo.cpp
4949

check is redundant ,no required here ....the caller takencare the check .

SouraVX added a subscriber: SouraVX.
kamleshbhalui retitled this revision from support debug info for alias variable to support debug info for alias variable.

removed unnecessary code.

kamleshbhalui marked an inline comment as done.May 26 2021, 3:26 AM

Looks like GCC emits aliases as a DW_TAG_variable without a location, not as a DW_TAG_imported_declaration

and marks it external; this works only because gdb will look up the ELF symbol when you say p newname. I've known debuggers that wouldn't do that. I think the DW_TAG_imported_declaration is making fewer assumptions about debugger behavior.

clang/lib/CodeGen/CGDebugInfo.cpp
4954

The variables Unit and DContext are used only inside the if so I would put those two variables inside the if as well.

match gcc behavior

matching gcc behavior

probinson added inline comments.May 28 2021, 11:30 AM
clang/lib/CodeGen/CGDebugInfo.cpp
4957

I wasn't saying that gcc did the right thing! Quite the opposite, I think the imported declaration is preferable, and I believe @dblaikie also thought it would be okay.

dblaikie added inline comments.May 28 2021, 5:10 PM
clang/lib/CodeGen/CGDebugInfo.cpp
4957

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

Though I'm still not sure about the status of this aspect, for instance:

How's this work if the alias target isn't declared in the source - but in inline assembly instead? (I guess GCC probably handles that OK, but the Clang strategy here might not cope with it)

$cat test.h
int oldname;

$cat test.c

#include "test.h"
int oldname;
asm (

"movq oldname, %rsp\n\t"

);

extern int newname attribute((alias("oldname")));

debug info from gcc:

test.o: file format elf64-x86-64

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000044, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000048)

0x0000000c: DW_TAG_compile_unit

DW_AT_producer    ("GNU C17 12.0.0 20210529 (experimental) -g")
DW_AT_language    (DW_LANG_C11)
DW_AT_name        ("test.c")
DW_AT_comp_dir    ("/folk/kkumar/tcgcc/build/")
DW_AT_stmt_list   (0x00000000)

0x0000001e: DW_TAG_variable

DW_AT_name      ("oldname")
DW_AT_decl_file ("test.h")
DW_AT_decl_line (1)
DW_AT_decl_column       (0x05)
DW_AT_type      (0x00000034 "int")
DW_AT_external  (true)
DW_AT_location  (DW_OP_addr 0x0)

0x00000034: DW_TAG_base_type

DW_AT_byte_size (0x04)
DW_AT_encoding  (DW_ATE_signed)
DW_AT_name      ("int")

0x0000003b: DW_TAG_variable

DW_AT_name      ("newname")
DW_AT_decl_file ("test.c")
DW_AT_decl_line (7)
DW_AT_decl_column       (0x0c)
DW_AT_type      (0x00000034 "int")
DW_AT_external  (true)

0x00000047: NULL

debug info from clang:

test1.o: file format elf64-x86-64

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000042, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000046)

0x0000000b: DW_TAG_compile_unit

DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git b22ff948a94edc7573d226fe404a77b9a7380398)")
DW_AT_language    (DW_LANG_C99)
DW_AT_name        ("test.c")
DW_AT_stmt_list   (0x00000000)
DW_AT_comp_dir    ("/folk/kkumar/tcgcc/build")

0x0000001e: DW_TAG_variable

DW_AT_name      ("newname")
DW_AT_type      (0x00000029 "int")
DW_AT_external  (true)
DW_AT_decl_file ("test.c")
DW_AT_decl_line (7)

0x00000029: DW_TAG_base_type

DW_AT_name      ("int")
DW_AT_encoding  (DW_ATE_signed)
DW_AT_byte_size (0x04)

0x00000030: DW_TAG_variable

DW_AT_name      ("oldname")
DW_AT_type      (0x00000029 "int")
DW_AT_external  (true)
DW_AT_decl_file ("test.c")
DW_AT_decl_line (2)
DW_AT_location  (DW_OP_addr 0x0)

0x00000045: NULL

so debug info looks same to me in gcc and clang .

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things. I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things. I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

The Sony debugger will not be able to figure out the address of "newname" given the DWARF as emitted by gcc (because it looks like an external declaration with no address). We'd much rather have the DW_TAG_imported_declaration that the original patch had.

Of course, if it turns out that gdb can't handle the imported_declaration, we might end up having to do this two different ways under the tuning option. I'd *really* prefer not to do that though, and I'd argue it's a gdb bug if it cannot understand imported_declaration.

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things.

Yep. Given the diversity of ways of expressing things in DWARF, no consumer will handle everything that could be produced in the way a producer might intend - so we do sort of have a defacto standard of "what would GCC do/what does GDB understand".

But also GCC/GDB has had more implementation experience with DWARF in general, and with any feature we haven't implemented yet in particular - that I wouldn't throw out their representational choice too quickly - there may be important tradeoffs that were considered, implemented, and discarded due to limitations.

I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

I don't agree that it's "certainly not what the DWARF spec suggests should be done" - the spec's pretty generous and exactly how a C or ELF level alias should be rendered in DWARF seems pretty unclear to me. For instance an alias is a symbol in the ELF file, arguably different from a source level alias like a typedef or using declaration that DW_TAG_imported_declaration seems to be promoted for.

I doubt gdb would have trouble with DW_TAG_imported_declaration

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things. I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

The Sony debugger will not be able to figure out the address of "newname" given the DWARF as emitted by gcc (because it looks like an external declaration with no address). We'd much rather have the DW_TAG_imported_declaration that the original patch had.

Good to know - any interest in the debugger supporting declarations without addresses? I guess there's no need for GCC compatibility? Clang might emit them under some circumstances... let's see... Hmm, can't find a case now. But there are cases where it would be desirable (such as when compiling some code at -g0 and some with debug info - when you only have the declaration on the debug info side, and no debug info on the definition side (eg: GCC produces a declaration of 'i' in this code: extern int i; int main() { return i; }))

@kamleshbhalui - perhaps you could run the gdb and lldb test suites without either change, then with both the variable declaration and imported declaration versions to see how the results vary? (Well, I guess the lldb test suite probably won't show any changes - but maybe worth running anyway) - along with the manual test you've described in the patch description, to demonstrate that both solutions address that?

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things.

Yep. Given the diversity of ways of expressing things in DWARF, no consumer will handle everything that could be produced in the way a producer might intend - so we do sort of have a defacto standard of "what would GCC do/what does GDB understand".

But also GCC/GDB has had more implementation experience with DWARF in general, and with any feature we haven't implemented yet in particular - that I wouldn't throw out their representational choice too quickly - there may be important tradeoffs that were considered, implemented, and discarded due to limitations.

Well, they aren't the only ones with a decent amount of implementation experience, hrmph, my first contribution to DWARF was in 2002 (my name isn't on the proposal, but I co-developed it).

I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

I don't agree that it's "certainly not what the DWARF spec suggests should be done" - the spec's pretty generous and exactly how a C or ELF level alias should be rendered in DWARF seems pretty unclear to me. For instance an alias is a symbol in the ELF file, arguably different from a source level alias like a typedef or using declaration that DW_TAG_imported_declaration seems to be promoted for.

The spec is generous and doesn't mandate (much), but what I'm referring to is DWARF 5 section 3.2.3 p.73 lines 1-3, "may be used as a general means to rename or provide an alias for an entity, regardless of the context" which seems like a pretty clear suggestion to me.
And I certainly would have thought __attribute__((alias("oldname"))) counted as a source representation?

The Sony debugger will not be able to figure out the address of "newname" given the DWARF as emitted by gcc (because it looks like an external declaration with no address). We'd much rather have the DW_TAG_imported_declaration that the original patch had.

Good to know - any interest in the debugger supporting declarations without addresses? I guess there's no need for GCC compatibility?

No and no. In general we seem to think that if you want to debug a CU, you should produce debug info for that CU.

I experimented with extern int externalname; and Clang doesn't emit a DIE for that at all, even if it's used; so I think the philosophy is not unsound, and is not inconsistent with how Clang behaves. If you want to see data from another CU, you generate debug info for that CU.

@kamleshbhalui - perhaps you could run the gdb and lldb test suites without either change, then with both the variable declaration and imported declaration versions to see how the results vary? (Well, I guess the lldb test suite probably won't show any changes - but maybe worth running anyway) - along with the manual test you've described in the patch description, to demonstrate that both solutions address that?

No objection to running experiments, but Sony will want the imported_declaration construct regardless.

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things.

Yep. Given the diversity of ways of expressing things in DWARF, no consumer will handle everything that could be produced in the way a producer might intend - so we do sort of have a defacto standard of "what would GCC do/what does GDB understand".

But also GCC/GDB has had more implementation experience with DWARF in general, and with any feature we haven't implemented yet in particular - that I wouldn't throw out their representational choice too quickly - there may be important tradeoffs that were considered, implemented, and discarded due to limitations.

Well, they aren't the only ones with a decent amount of implementation experience, hrmph, my first contribution to DWARF was in 2002 (my name isn't on the proposal, but I co-developed it).

Sure enough - didn't mean to disparage your work. Mostly given the desire for Clang to be drop-in compatible (more or less) with GCC, I'm generally interested in whatever choice GCC makes for DWARF to check if there's anything we should be learning from it having done it that way for a while most likely.

I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

I don't agree that it's "certainly not what the DWARF spec suggests should be done" - the spec's pretty generous and exactly how a C or ELF level alias should be rendered in DWARF seems pretty unclear to me. For instance an alias is a symbol in the ELF file, arguably different from a source level alias like a typedef or using declaration that DW_TAG_imported_declaration seems to be promoted for.

The spec is generous and doesn't mandate (much), but what I'm referring to is DWARF 5 section 3.2.3 p.73 lines 1-3, "may be used as a general means to rename or provide an alias for an entity, regardless of the context" which seems like a pretty clear suggestion to me.
And I certainly would have thought __attribute__((alias("oldname"))) counted as a source representation?

Re: Source representation: I was trying to draw a distinction between things that are purely in the source representation/AST (like typedefs/using declarations - though, admittedly, neither of those apply to variables - I guess maybe you can't make a pure source level variable alias? oh, only if you keep it the same name and only move it between namespaces with using ns::name - not if you want to give it a new name) compared to those that have some manifestation in the object file.

For instance, arguably "extern int i; const int &j = i; - j` is an alias, of sorts - perhaps it could be represented with DW_TAG_imported_declaration? Though I'd tend not to think of it that way/use that feature in that way & it's pretty similar to the effect of the alias attribute (in that you get a separate symbol, though admittedly in this case the symbol does store the address of the other thing, rather than being a synonym - but has a similar effect)

The Sony debugger will not be able to figure out the address of "newname" given the DWARF as emitted by gcc (because it looks like an external declaration with no address). We'd much rather have the DW_TAG_imported_declaration that the original patch had.

Good to know - any interest in the debugger supporting declarations without addresses? I guess there's no need for GCC compatibility?

No and no. In general we seem to think that if you want to debug a CU, you should produce debug info for that CU.

I experimented with extern int externalname; and Clang doesn't emit a DIE for that at all, even if it's used; so I think the philosophy is not unsound, and is not inconsistent with how Clang behaves. If you want to see data from another CU, you generate debug info for that CU.

Ish - we do have -fstandalone-debug for when you haven't built everything with debug info, but you want this one thing you did build with debug info to be fairly debuggable & that could include access to such variables (we do something like this for constants and enums since they might not be "pinned" anywhere else - but also for base classes that could be defined in another file but you want them in this file if you're going to debug a derived class that is defined here).

The ability to drop the DWARF if the IR definition is dropped in LTO (& consequently can drop other type information that it references, etc) could be a nice side effect of a more IR-driven representation. (though that might tend more towards a definition, with a location, rather than a declaration)

@kamleshbhalui - perhaps you could run the gdb and lldb test suites without either change, then with both the variable declaration and imported declaration versions to see how the results vary? (Well, I guess the lldb test suite probably won't show any changes - but maybe worth running anyway) - along with the manual test you've described in the patch description, to demonstrate that both solutions address that?

No objection to running experiments, but Sony will want the imported_declaration construct regardless.

I will say, as the person who implemented DW_TAG_imported_declaration support in Clang - it's a bit not great/unfortunate (in part because we currently have to emit them for all using declarations (because clang doesn't track some of the usedness we would need to more selectively emit them), and then we can't reap them in LTO or other optimizations if they are effectively unused) - but such is the way of things.

clang/test/CodeGen/debug-info-alias.c
4

If we go this way, might be good to have more detail on this - to check how this DIGlobalVariable is defined and how it is referenced (what's keeping this DI node alive)

I will say, as the person who implemented DW_TAG_imported_declaration support in Clang - it's a bit not great/unfortunate (in part because we currently have to emit them for all using declarations (because clang doesn't track some of the usedness we would need to more selectively emit them), and then we can't reap them in LTO or other optimizations if they are effectively unused) - but such is the way of things.

Yeah, we've been carrying a downstream patch to turn off a lot of 'using' declarations, and it has been on my wishlist for a long time to get used-ness info in there.

kamleshbhalui added a comment.EditedJun 9 2021, 10:36 PM

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things.

Yep. Given the diversity of ways of expressing things in DWARF, no consumer will handle everything that could be produced in the way a producer might intend - so we do sort of have a defacto standard of "what would GCC do/what does GDB understand".

But also GCC/GDB has had more implementation experience with DWARF in general, and with any feature we haven't implemented yet in particular - that I wouldn't throw out their representational choice too quickly - there may be important tradeoffs that were considered, implemented, and discarded due to limitations.

I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

I don't agree that it's "certainly not what the DWARF spec suggests should be done" - the spec's pretty generous and exactly how a C or ELF level alias should be rendered in DWARF seems pretty unclear to me. For instance an alias is a symbol in the ELF file, arguably different from a source level alias like a typedef or using declaration that DW_TAG_imported_declaration seems to be promoted for.

I doubt gdb would have trouble with DW_TAG_imported_declaration

Mixed feelings - somewhat in favor of "do the thing that's probably already fairly tested/known to work" (GCC's thing). But open to the idea that that approach has problems, for sure.

"Known to work" for whom? gdb, sure, because gcc/gdb cooperate on many things. I'll have to check with my debugger guys whether this would work for us; and I'll just reiterate that it's certainly not what the DWARF spec suggests should be done.

The Sony debugger will not be able to figure out the address of "newname" given the DWARF as emitted by gcc (because it looks like an external declaration with no address). We'd much rather have the DW_TAG_imported_declaration that the original patch had.

Good to know - any interest in the debugger supporting declarations without addresses? I guess there's no need for GCC compatibility? Clang might emit them under some circumstances... let's see... Hmm, can't find a case now. But there are cases where it would be desirable (such as when compiling some code at -g0 and some with debug info - when you only have the declaration on the debug info side, and no debug info on the definition side (eg: GCC produces a declaration of 'i' in this code: extern int i; int main() { return i; }))

@kamleshbhalui - perhaps you could run the gdb and lldb test suites without either change, then with both the variable declaration and imported declaration versions to see how the results vary? (Well, I guess the lldb test suite probably won't show any changes - but maybe worth running anyway) - along with the manual test you've described in the patch description, to demonstrate that both solutions address that?

@dblaikie I have ran gdb and lldb regression here is details.Please let me know if we should go to original fix(imported decl).

case 1) Without any change in clang:

=== gdb Summary ===
  1. of expected passes 75531
  2. of unexpected failures 695
  3. of expected failures 125
  4. of known failures 74
  5. of unresolved testcases 7
  6. of untested testcases 98
  7. of unsupported tests 326
  8. of duplicate test names 202
===lldb summary===

Failed Tests (3):

lldb-shell :: Breakpoint/jit-loader_jitlink_elf.test
lldb-shell :: Breakpoint/jit-loader_rtdyld_elf.test
lldb-shell :: Reproducer/TestDiscard.test

Testing Time: 60.57s

Unsupported: 1095
Passed     : 1202
Failed     :    3

case 2) with imported decl change in clang

=== gdb Summary ===
  1. of expected passes 75531
  2. of unexpected failures 695
  3. of expected failures 125
  4. of known failures 74
  5. of unresolved testcases 7
  6. of untested testcases 98
  7. of unsupported tests 326
  8. of duplicate test names 202
===lldb summary===

Failed Tests (3):

lldb-shell :: Breakpoint/jit-loader_jitlink_elf.test
lldb-shell :: Breakpoint/jit-loader_rtdyld_elf.test
lldb-shell :: Reproducer/TestDiscard.test

Testing Time: 60.57s

Unsupported: 1095
Passed     : 1202
Failed     :    3

case 3) with current change(same change as in this review) in clang

=== gdb Summary ===
  1. of expected passes 75531
  2. of unexpected failures 695
  3. of expected failures 125
  4. of known failures 74
  5. of unresolved testcases 7
  6. of untested testcases 98
  7. of unsupported tests 326
  8. of duplicate test names 202
===lldb summary===

Failed Tests (3):

lldb-shell :: Breakpoint/jit-loader_jitlink_elf.test
lldb-shell :: Breakpoint/jit-loader_rtdyld_elf.test
lldb-shell :: Reproducer/TestDiscard.test

Testing Time: 60.57s

Unsupported: 1095
Passed     : 1202
Failed     :    3

Any idea if the GDB test suite covers this functionality? I'd hope so, but maybe it doesn't.

But yeah, at the moment I don't have any great reason to avoid the imported declaration form - so happy to go with that.

Any idea if the GDB test suite covers this functionality? I'd hope so, but maybe it doesn't.

But yeah, at the moment I don't have any great reason to avoid the imported declaration form - so happy to go with that.

Hi David,

with imported declaration patch and with current patch(in review or say gcc way) this case works ok(we can print type and value of newname)
$cat test.c
int oldname = 1;
extern int newname attribute((alias("oldname")));

but when we make newname static it works with current patch(in review or say gcc way) but it does not work with imported decl patch(https://reviews.llvm.org/D103131?id=347883).

Should we go with gcc way or am I missing something?
note: used gdb debugger.

Any idea if the GDB test suite covers this functionality? I'd hope so, but maybe it doesn't.

But yeah, at the moment I don't have any great reason to avoid the imported declaration form - so happy to go with that.

Hi David,

with imported declaration patch and with current patch(in review or say gcc way) this case works ok(we can print type and value of newname)
$cat test.c
int oldname = 1;
extern int newname attribute((alias("oldname")));

but when we make newname static it works with current patch(in review or say gcc way) but it does not work with imported decl patch(https://reviews.llvm.org/D103131?id=347883).

Should we go with gcc way or am I missing something?
note: used gdb debugger.

An ideas what's happening when newname is static? Is the DWARF any different/interesting there? (since the DWARF for imported decl seems like it would have nothing to do with the linkange of the alias - since it doesn't refer to the actual alias in the object file, etc)

Any idea if the GDB test suite covers this functionality? I'd hope so, but maybe it doesn't.

But yeah, at the moment I don't have any great reason to avoid the imported declaration form - so happy to go with that.

Hi David,

with imported declaration patch and with current patch(in review or say gcc way) this case works ok(we can print type and value of newname)
$cat test.c
int oldname = 1;
extern int newname attribute((alias("oldname")));

but when we make newname static it works with current patch(in review or say gcc way) but it does not work with imported decl patch(https://reviews.llvm.org/D103131?id=347883).

Should we go with gcc way or am I missing something?
note: used gdb debugger.

An ideas what's happening when newname is static? Is the DWARF any different/interesting there? (since the DWARF for imported decl seems like it would have nothing to do with the linkange of the alias - since it doesn't refer to the actual alias in the object file, etc)

There not much different apart from extern has external attribute.
case 1) when newname is static

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000076)

0x0000000b: DW_TAG_compile_unit

DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git 4cd7169f5517167ef456e82c6dcae669bde6c725)")
DW_AT_language    (DW_LANG_C99)
DW_AT_name        ("test.c")
DW_AT_stmt_list   (0x00000000)
DW_AT_comp_dir    ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin")
DW_AT_low_pc      (0x0000000000000000)
DW_AT_high_pc     (0x0000000000000008)

0x0000002a: DW_TAG_variable

DW_AT_name      ("oldname")
DW_AT_type      (0x0000003f "int")
DW_AT_external  (true)
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (1)
DW_AT_location  (DW_OP_addr 0x0)

0x0000003f: DW_TAG_base_type

DW_AT_name      ("int")
DW_AT_encoding  (DW_ATE_signed)
DW_AT_byte_size (0x04)

0x00000046: DW_TAG_variable

DW_AT_name      ("newname")
DW_AT_type      (0x0000003f "int")
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (2)
DW_AT_declaration       (true)

0x00000051: DW_TAG_imported_declaration

DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (2)
DW_AT_import    (0x00000046)
DW_AT_name      ("newname")

0x0000005c: DW_TAG_subprogram

DW_AT_low_pc    (0x0000000000000000)
DW_AT_high_pc   (0x0000000000000008)
DW_AT_frame_base        (DW_OP_reg6 RBP)
DW_AT_name      ("main")
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (3)
DW_AT_type      (0x0000003f "int")
DW_AT_external  (true)

0x00000075: NULL

case 2) when newname is extern

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000076)

0x0000000b: DW_TAG_compile_unit

DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git 4cd7169f5517167ef456e82c6dcae669bde6c725)")
DW_AT_language    (DW_LANG_C99)
DW_AT_name        ("test.c")
DW_AT_stmt_list   (0x00000000)
DW_AT_comp_dir    ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin")
DW_AT_low_pc      (0x0000000000000000)
DW_AT_high_pc     (0x0000000000000008)

0x0000002a: DW_TAG_variable

DW_AT_name      ("oldname")
DW_AT_type      (0x0000003f "int")
DW_AT_external  (true)
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (1)
DW_AT_location  (DW_OP_addr 0x0)

0x0000003f: DW_TAG_base_type

DW_AT_name      ("int")
DW_AT_encoding  (DW_ATE_signed)
DW_AT_byte_size (0x04)

0x00000046: DW_TAG_variable

DW_AT_name      ("newname")
DW_AT_type      (0x0000003f "int")
DW_AT_external  (true)
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (2)
DW_AT_declaration       (true)

0x00000051: DW_TAG_imported_declaration

DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (2)
DW_AT_import    (0x00000046)
DW_AT_name      ("newname")

0x0000005c: DW_TAG_subprogram

DW_AT_low_pc    (0x0000000000000000)
DW_AT_high_pc   (0x0000000000000008)
DW_AT_frame_base        (DW_OP_reg6 RBP)
DW_AT_name      ("main")
DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
DW_AT_decl_line (3)
DW_AT_type      (0x0000003f "int")
DW_AT_external  (true)

0x00000075: NULL

Any idea if the GDB test suite covers this functionality? I'd hope so, but maybe it doesn't.

But yeah, at the moment I don't have any great reason to avoid the imported declaration form - so happy to go with that.

Hi David,

with imported declaration patch and with current patch(in review or say gcc way) this case works ok(we can print type and value of newname)
$cat test.c
int oldname = 1;
extern int newname attribute((alias("oldname")));

but when we make newname static it works with current patch(in review or say gcc way) but it does not work with imported decl patch(https://reviews.llvm.org/D103131?id=347883).

Should we go with gcc way or am I missing something?
note: used gdb debugger.

An ideas what's happening when newname is static? Is the DWARF any different/interesting there? (since the DWARF for imported decl seems like it would have nothing to do with the linkange of the alias - since it doesn't refer to the actual alias in the object file, etc)

There not much different apart from extern has external attribute.
case 1) when newname is static

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000076)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git 4cd7169f5517167ef456e82c6dcae669bde6c725)")
              DW_AT_language    (DW_LANG_C99)
              DW_AT_name        ("test.c")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin")
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x0000000000000008)

0x0000002a:   DW_TAG_variable
                DW_AT_name      ("oldname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (1)
                DW_AT_location  (DW_OP_addr 0x0)

0x0000003f:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x00000046:   DW_TAG_variable
                DW_AT_name      ("newname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_declaration       (true)

0x00000051:   DW_TAG_imported_declaration
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_import    (0x00000046)
                DW_AT_name      ("newname")

0x0000005c:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000008)
                DW_AT_frame_base        (DW_OP_reg6 RBP)
                DW_AT_name      ("main")
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (3)
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)

0x00000075:   NULL

case 2) when newname is extern

.debug_info contents:
0x00000000: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000076)

0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git 4cd7169f5517167ef456e82c6dcae669bde6c725)")
              DW_AT_language    (DW_LANG_C99)
              DW_AT_name        ("test.c")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_comp_dir    ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin")
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x0000000000000008)

0x0000002a:   DW_TAG_variable
                DW_AT_name      ("oldname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (1)
                DW_AT_location  (DW_OP_addr 0x0)

0x0000003f:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x00000046:   DW_TAG_variable
                DW_AT_name      ("newname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_declaration       (true)

0x00000051:   DW_TAG_imported_declaration
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_import    (0x00000046)
                DW_AT_name      ("newname")

0x0000005c:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000008)
                DW_AT_frame_base        (DW_OP_reg6 RBP)
                DW_AT_name      ("main")
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (3)
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)

0x00000075:   NULL

This debug info looks confusing - it looks like it's using /both/ strategies. There's a DW_TAG_variable for oldname then a DW_TAG_variable declaration for newname then a DW_TAG_imported_declaration for newname from newname. I don't think that's a solution we'd want - either we have just the two DW_TAG_variables, or we have the oldname DW_TAG_variable and a DW_TAG_imported_declaration that imports that oldname variable as newname, right?

probinson added subscribers: myler, akhuang, alok and 29 others.EditedJun 12 2021, 12:12 PM
0x0000002a:   DW_TAG_variable
                DW_AT_name      ("oldname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (1)
                DW_AT_location  (DW_OP_addr 0x0)

0x0000003f:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x00000046:   DW_TAG_variable
                DW_AT_name      ("newname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_declaration       (true)

0x00000051:   DW_TAG_imported_declaration
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_import    (0x00000046)
                DW_AT_name      ("newname")

I agree with David, this sequence doesn't seem to do what's desired.
There's nothing that ties "newname" to "oldname" here. What you
want is something more like this:

0x0000002a: DW_TAG_variable
               DW_AT_name ("oldname")
               ...
0x0000003a: DW_TAG_imported_declaration
               DW_AT_import (0x0000002a)
               DW_AT_name ("newname")

That is, there would not be a separate DW_TAG_variable for "newname";
instead, the imported_declaration would import the DIE for "oldname"
giving it the name "newname".

--paulr

0x0000002a:   DW_TAG_variable
                DW_AT_name      ("oldname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_external  (true)
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (1)
                DW_AT_location  (DW_OP_addr 0x0)

0x0000003f:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

0x00000046:   DW_TAG_variable
                DW_AT_name      ("newname")
                DW_AT_type      (0x0000003f "int")
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_declaration       (true)

0x00000051:   DW_TAG_imported_declaration
                DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                DW_AT_decl_line (2)
                DW_AT_import    (0x00000046)
                DW_AT_name      ("newname")

I agree with David, this sequence doesn't seem to do what's desired.
There's nothing that ties "newname" to "oldname" here. What you
want is something more like this:

0x0000002a: DW_TAG_variable
               DW_AT_name ("oldname")
               ...
0x0000003a: DW_TAG_imported_declaration
               DW_AT_import (0x0000002a)
               DW_AT_name ("newname")

That is, there would not be a separate DW_TAG_variable for "newname";
instead, the imported_declaration would import the DIE for "oldname"
giving it the name "newname".

--paulr

Even this does not work with gdb.
Here is what gdb says,

 (gdb) ptype newname
type = <data variable, no debug info>
 (gdb) p newname
'newname' has unknown type; cast it to its declared type
 (gdb) p oldname
 $1 = 1
 (gdb) ptype oldname
 type = int
 (gdb)  
 --------------
 dumped debug info (using llvm-dwarfdump)
 test.o: file format elf64-x86-64
 
 .debug_info contents:
 0x00000000: Compile Unit: length = 0x00000067, format = DWARF32, version = 0x0004, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000006b)
 
 0x0000000b: DW_TAG_compile_unit
               DW_AT_producer    ("clang version 13.0.0 (git@github.com:llvm/llvm-project.git 4cd7169f5517167ef456e82c6dcae669bde6c725)")
               DW_AT_language    (DW_LANG_C99)
               DW_AT_name        ("test.c")
               DW_AT_stmt_list   (0x00000000)
               DW_AT_comp_dir    ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin")
               DW_AT_low_pc      (0x0000000000000000)
               DW_AT_high_pc     (0x0000000000000008)
 
 0x0000002a:   DW_TAG_variable
                 DW_AT_name      ("oldname")
                 DW_AT_type      (0x0000003f "int")
                 DW_AT_external  (true)
                 DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                 DW_AT_decl_line (1)
                 DW_AT_location  (DW_OP_addr 0x0)
 
 0x0000003f:   DW_TAG_base_type
                 DW_AT_name      ("int")
                 DW_AT_encoding  (DW_ATE_signed)
                 DW_AT_byte_size (0x04)
 
 0x00000046:   DW_TAG_imported_declaration
                 DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                 DW_AT_decl_line (2)
                 DW_AT_import    (0x0000002a)
                 DW_AT_name      ("newname")
 
 0x00000051:   DW_TAG_subprogram
                 DW_AT_low_pc    (0x0000000000000000)
                 DW_AT_high_pc   (0x0000000000000008)
                 DW_AT_frame_base        (DW_OP_reg6 RBP)
                 DW_AT_name      ("main")
                 DW_AT_decl_file ("/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/test.c")
                 DW_AT_decl_line (3)
                 DW_AT_type      (0x0000003f "int")
                 DW_AT_external  (true)
 
 0x0000006a:   NULL

Huh, that surprises me - guess gdb favors checking the symbol first. I guess maybe it is using something that determines that that symbol comes from the file with debug info - because on a similar test case (one file without debug info, defining some global variable i, another file with debug info with a using ns::i in the global scope - printing i when stepping into the second file correctly prints the using based alias value, but stepping into the file without debug info and printing i complains about not knowing the type of that i)

How's lldb go?

Huh, that surprises me - guess gdb favors checking the symbol first. I guess maybe it is using something that determines that that symbol comes from the file with debug info - because on a similar test case (one file without debug info, defining some global variable i, another file with debug info with a using ns::i in the global scope - printing i when stepping into the second file correctly prints the using based alias value, but stepping into the file without debug info and printing i complains about not knowing the type of that i)

How's lldb go?

lldb seems to be printing value , but I worry about type.

* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x0000000000400484 a.out`main at test.c:3:12
   1    int oldname = 1;
   2    extern int newname __attribute__((alias("oldname")));
-> 3    int main(){}
(lldb) p oldname
(int) $0 = 1
(lldb) p newname
(void *) $1 = 0x0000000000000001

Huh, that surprises me - guess gdb favors checking the symbol first. I guess maybe it is using something that determines that that symbol comes from the file with debug info - because on a similar test case (one file without debug info, defining some global variable i, another file with debug info with a using ns::i in the global scope - printing i when stepping into the second file correctly prints the using based alias value, but stepping into the file without debug info and printing i complains about not knowing the type of that i)

How's lldb go?

lldb seems to be printing value , but I worry about type.

* thread #1, name = 'a.out', stop reason = breakpoint 1.1
    frame #0: 0x0000000000400484 a.out`main at test.c:3:12
   1    int oldname = 1;
   2    extern int newname __attribute__((alias("oldname")));
-> 3    int main(){}
(lldb) p oldname
(int) $0 = 1
(lldb) p newname
(void *) $1 = 0x0000000000000001

Yeah, that looks a bit suspicious - perhaps try testing it with the alias of some other type (like float) and see if it renders correctly?

Here is what we get when we replace int with float.

$lldb-11 ./a.out 
(lldb) target create "./a.out"
Current executable set to '/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at test.c:3:12, address = 0x0000000000400484
(lldb) p oldname
(float) $0 = 1
(lldb) p newname
(void *) $1 = 0x000000003f800000

Here is what we get when we replace int with float.

$lldb-11 ./a.out 
(lldb) target create "./a.out"
Current executable set to '/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at test.c:3:12, address = 0x0000000000400484
(lldb) p oldname
(float) $0 = 1
(lldb) p newname
(void *) $1 = 0x000000003f800000

Yep, looks like it's ignoring the imported declaration in favor of the raw symbol table entry.

How's lldb handle GCC-style debug info (the variable declaration, without any imported declaration) for the alias?

Here is what we get when we replace int with float.

$lldb-11 ./a.out 
(lldb) target create "./a.out"
Current executable set to '/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at test.c:3:12, address = 0x0000000000400484
(lldb) p oldname
(float) $0 = 1
(lldb) p newname
(void *) $1 = 0x000000003f800000

Yep, looks like it's ignoring the imported declaration in favor of the raw symbol table entry.

How's lldb handle GCC-style debug info (the variable declaration, without any imported declaration) for the alias?

lldb's behavior is same even with GCC -style debug info.

Here is what we get when we replace int with float.

$lldb-11 ./a.out 
(lldb) target create "./a.out"
Current executable set to '/folk/kkumar/tcllvm/llvm-build-lldb-rel/bin/a.out' (x86_64).
(lldb) b main
Breakpoint 1: where = a.out`main + 4 at test.c:3:12, address = 0x0000000000400484
(lldb) p oldname
(float) $0 = 1
(lldb) p newname
(void *) $1 = 0x000000003f800000

Yep, looks like it's ignoring the imported declaration in favor of the raw symbol table entry.

How's lldb handle GCC-style debug info (the variable declaration, without any imported declaration) for the alias?

lldb's behavior is same even with GCC -style debug info.

Hmm, good to know/unfortunate. Guess it'll need some work.

Do you have any interest in seeing if gdb could/would be fixed to handle the imported declaration style? Might be worth knowing if that's feasible, if they have some ideas about if/why that would be a bad idea, etc.