Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/link: dsymutil also mangles __debug_info sometimes #22068

Closed
aarzilli opened this issue Sep 27, 2017 · 4 comments

Comments

Projects
None yet
3 participants
@aarzilli
Copy link
Contributor

commented Sep 27, 2017

Found while investigating this: #21945

When calling dsymutil with the verbose option a number of warnings like this are emitted:

while processing /tmp/testdir/go.o:
warning: could not find referenced DIE
    in DIE:

0x00306e5f:       DW_TAG_array_type [14] *
                    DW_AT_name [DW_FORM_string] ("[62]testing.InternalTest")
                    DW_AT_type [DW_FORM_ref_addr]       (0x00000000003061b0)
                    DW_AT_byte_size [DW_FORM_udata]     (1488)
                    DW_AT_Unknown_2900 [DW_FORM_data1]  (0x11)

the corresponding DIE is fine in go.o but mangled (missing the DW_AT_Type attribute) in the final binary:

 <1><18af46>: Abbrev Number: 27 (DW_TAG_array_type)
    <18af47>   DW_AT_name        : (indirect string, offset: 0x195b72): [62]testing.InternalTest
    <18af4b>   DW_AT_byte_size   : 1488
    <18af4d>   Unknown AT value: 2900: 17

See issue #21945 for more details on how to reproduce this. This problem was originally observed in this old bug.

cc @heschik @hyangah

@heschik heschik added the Debugging label Sep 27, 2017

@heschik heschik changed the title cmd/link: dsymutil also mangles __debug_info sometimes [Debugging] cmd/link: dsymutil also mangles __debug_info sometimes Sep 27, 2017

@heschik

This comment has been minimized.

Copy link
Contributor

commented Oct 4, 2017

I built dsymutil from source and debugged it today. I didn't get all the way through but wanted to write down findings so far.

The problem occurs when dsymutil applies relocations here:
https://github.com/llvm-mirror/llvm/blob/f1ff67e5f1d9bba6d4a95deef0a72ab888158c60/tools/dsymutil/DwarfLinker.cpp#L2749

.debug_info contains relocations to multiple sections. In the instance I was looking at, the DW_AT_type that was getting lost relocated to some offset X within .debug_info. It so happened that a prior function DIE's DW_AT_high_pc had the same offset X, but that's a relocation into .text. Something somewhere conflated the two relocations, and it ended up using the function's address where it should have used the type DIE's.

Right now I think there are two possibilities: either dsymutil is busted somewhere, or the Go toolchain is producing a bad debug map. (I don't know exactly what a debug map is, but it seems to contain relocations, and it's what's fed to the RelocMgr above.) I'll try to figure out which at some point.

@heschik

This comment has been minimized.

Copy link
Contributor

commented Oct 4, 2017

Okay. I don't like it, but I think I understand what's happening now.

In a normal .debug_info, you can get away without a relocation within the same CU using the CU-relative forms of reference (DW_FORM_refN) but for references to a different CU or a different section (.debug_loc, .debug_ranges) you need a DW_FORM_ref_addr and a relocation. This allows the linker to adjust the pointers as it merges the debug information from all the object files.

Mach-O C++ object files don't seem to have any relocations to their DWARF at all. Instead, they rely completely on the existence of dsymutil to do a content-aware linking step without the benefit of any relocations. It walks over all the DIEs in the input and emits referenced ranges and location lists, updating the references as it goes. (https://github.com/llvm-mirror/llvm/blob/f1ff67e5f1d9bba6d4a95deef0a72ab888158c60/tools/dsymutil/DwarfLinker.cpp#L2871, https://github.com/llvm-mirror/llvm/blob/f1ff67e5f1d9bba6d4a95deef0a72ab888158c60/tools/dsymutil/DwarfLinker.cpp#L838).

Dropping the relocations from the output seems to work. I'll mail a WIP CL.

@gopherbot

This comment has been minimized.

Copy link

commented Oct 4, 2017

Change https://golang.org/cl/68330 mentions this issue: cmd/link: suppress unnecessary DWARF relocs that confuse dsymutil

@heschik

This comment has been minimized.

Copy link
Contributor

commented Oct 10, 2017

Some notes for posterity. There's still a bunch I don't understand here though.

The crux of the problem is the way that dsymutil finds entries in the debug map. It assumes that all relocations are absolute addresses, and reads the addend of the relocation (which in Mach-O is in the instruction text, see https://github.com/llvm-mirror/llvm/blob/f1ff67e5f1d9bba6d4a95deef0a72ab888158c60/tools/dsymutil/DwarfLinker.cpp#L1936). It uses that to get the final address and replace the relocation with it. This breaks with our R_DWARFREF relocations, which are section-relative, not absolute addresses. When they happen to collide with an absolute address in the debug map, we get this issue.

There's a debug map for each object file, formed from two pieces of information: STAB entries in the main binary, which map a symbol name to its final value, and the object's symbol table, which maps that to the addend that dsymutil can recognize -- its location in the object file.

It's not clear to me how the Go linker produces an object whose relocations' addends match the position they end up in the object file. @crawshaw suggests that this might be because the linker mostly thinks it's linking the final binary, and so it thinks it knows the load address of the object. I'm mostly just confused.

@gopherbot gopherbot closed this in a0402b6 Oct 12, 2017

@golang golang locked and limited conversation to collaborators Oct 12, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.