diff options
| author | Greg Clayton <gclayton@apple.com> | 2011-11-13 04:15:56 +0000 |
|---|---|---|
| committer | Greg Clayton <gclayton@apple.com> | 2011-11-13 04:15:56 +0000 |
| commit | 2fc93eabf7e132abd51d0ea0ad599beb3fa44334 (patch) | |
| tree | 5602d102cc9221c535c48dd16caaf44144b08e09 /lldb/source/Plugins | |
| parent | c8cfd3a8fb566ea8521ebd54bfab61e67cc63e55 (diff) | |
| download | bcm5719-llvm-2fc93eabf7e132abd51d0ea0ad599beb3fa44334.tar.gz bcm5719-llvm-2fc93eabf7e132abd51d0ea0ad599beb3fa44334.zip | |
<rdar://problem/10338439>
This is the actual fix for the above radar where global variables that weren't
initialized were not being shown correctly when leaving the DWARF in the .o
files. Global variables that aren't intialized have symbols in the .o files
that specify they are undefined and external to the .o file, yet document the
size of the variable. This allows the compiler to emit a single copy, but makes
it harder for our DWARF in .o files with the executable having a debug map
because the symbol for the global in the .o file doesn't exist in a section
that we can assign a fixed up linked address to, and also the DWARF contains
an invalid address in the "DW_OP_addr" location (always zero). This means that
the DWARF is incorrect and actually maps all such global varaibles to the
first file address in the .o file which is usually the first function. So we
can fix this in either of two ways: make a new fake section in the .o file
so that we have a file address in the .o file that we can relink, or fix the
the variable as it is created in the .o file DWARF parser and actually give it
the file address from the executable. Each variable contains a
SymbolContextScope, or a single pointer that helps us to recreate where the
variables came from (which module, file, function, etc). This context helps
us to resolve any file addresses that might be in the location description of
the variable by pointing us to which file the file address comes from, so we
can just replace the SymbolContextScope and also fix up the location, which we
would have had to do for the other case as well, and update the file address.
Now globals display correctly.
The above changes made it possible to determine if a variable is a global
or static variable when parsing DWARF. The DWARF emits a DW_TAG_variable tag
for each variable (local, global, or static), yet DWARF provides no way for
us to classify these variables into these categories. We can now detect when
a variable has a simple address expressions as its location and this will help
us classify these correctly.
While making the above changes I also noticed that we had two symbol types:
eSymbolTypeExtern and eSymbolTypeUndefined which mean essentially the same
thing: the symbol is not defined in the current object file. Symbol objects
also have a bit that specifies if a symbol is externally visible, so I got
rid of the eSymbolTypeExtern symbol type and moved all code locations that
used it to use the eSymbolTypeUndefined type.
llvm-svn: 144489
Diffstat (limited to 'lldb/source/Plugins')
3 files changed, 116 insertions, 98 deletions
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 679e2b2c312..0e9b1219d09 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -273,7 +273,6 @@ ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) { case eSymbolTypeAny: return eAddressClassUnknown; case eSymbolTypeAbsolute: return eAddressClassUnknown; - case eSymbolTypeExtern: return eAddressClassUnknown; case eSymbolTypeCode: case eSymbolTypeTrampoline: @@ -1195,7 +1194,7 @@ ObjectFileMachO::ParseSymtab (bool minimize) case NListTypeIndirect: // N_INDR - Fall through case NListTypePreboundUndefined:// N_PBUD - Fall through case NListTypeUndefined: // N_UNDF - type = eSymbolTypeExtern; + type = eSymbolTypeUndefined; break; case NListTypeAbsolute: // N_ABS @@ -1458,7 +1457,7 @@ ObjectFileMachO::ParseSymtab (bool minimize) { Address so_addr(symbol_stub_addr, section_list); - if (stub_symbol->GetType() == eSymbolTypeExtern) + if (stub_symbol->GetType() == eSymbolTypeUndefined) { // Change the external symbol into a trampoline that makes sense // These symbols were N_UNDF N_EXT, and are useless to us, so we diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index f872152f7ce..08772c65638 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -5247,31 +5247,114 @@ SymbolFileDWARF::ParseVariableDIE const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die); dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0; + SymbolContextScope * symbol_context_scope = NULL; + // DWARF doesn't specify if a DW_TAG_variable is a local, global + // or static variable, so we have to do a little digging by + // looking at the location of a varaible to see if it contains + // a DW_OP_addr opcode _somewhere_ in the definition. I say + // somewhere because clang likes to combine small global variables + // into the same symbol and have locations like: + // DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus + // So if we don't have a DW_TAG_formal_parameter, we can look at + // the location to see if it contains a DW_OP_addr opcode, and + // then we can correctly classify our variables. if (tag == DW_TAG_formal_parameter) scope = eValueTypeVariableArgument; - else if (is_external || parent_tag == DW_TAG_compile_unit) - scope = eValueTypeVariableGlobal; + else if (location.LocationContains_DW_OP_addr ()) + { + if (is_external) + { + if (m_debug_map_symfile) + { + // When leaving the DWARF in the .o files on darwin, + // when we have a global variable that wasn't initialized, + // the .o file might not have allocated a virtual + // address for the global variable. In this case it will + // have created a symbol for the global variable + // that is undefined and external and the value will + // be the byte size of the variable. When we do the + // address map in SymbolFileDWARFDebugMap we rely on + // having an address, we need to do some magic here + // so we can get the correct address for our global + // variable. The address for all of these entries + // will be zero, and there will be an undefined symbol + // in this object file, and the executable will have + // a matching symbol with a good address. So here we + // dig up the correct address and replace it in the + // location for the variable, and set the variable's + // symbol context scope to be that of the main executable + // so the file address will resolve correctly. + if (location.LocationContains_DW_OP_addr (0)) + { + + // we have a possible uninitialized extern global + Symtab *symtab = m_obj_file->GetSymtab(); + if (symtab) + { + ConstString const_name(name); + Symbol *undefined_symbol = symtab->FindFirstSymbolWithNameAndType (const_name, + eSymbolTypeUndefined, + Symtab::eDebugNo, + Symtab::eVisibilityExtern); + + if (undefined_symbol) + { + ObjectFile *debug_map_objfile = m_debug_map_symfile->GetObjectFile(); + if (debug_map_objfile) + { + Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); + Symbol *defined_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType (const_name, + eSymbolTypeData, + Symtab::eDebugYes, + Symtab::eVisibilityExtern); + if (defined_symbol) + { + const AddressRange *defined_range = defined_symbol->GetAddressRangePtr(); + if (defined_range) + { + const addr_t defined_addr = defined_range->GetBaseAddress().GetFileAddress(); + if (defined_addr != LLDB_INVALID_ADDRESS) + { + if (location.Update_DW_OP_addr (defined_addr)) + { + symbol_context_scope = defined_symbol; + } + } + } + } + } + } + } + } + } + scope = eValueTypeVariableGlobal; + } + else + scope = eValueTypeVariableStatic; + } else scope = eValueTypeVariableLocal; - SymbolContextScope * symbol_context_scope = NULL; - switch (parent_tag) + if (symbol_context_scope == NULL) { - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - case DW_TAG_lexical_block: - if (sc.function) + switch (parent_tag) { - symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); - if (symbol_context_scope == NULL) - symbol_context_scope = sc.function; + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + if (sc.function) + { + symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset())); + if (symbol_context_scope == NULL) + symbol_context_scope = sc.function; + } + break; + + default: + symbol_context_scope = sc.comp_unit; + break; } - break; - - default: - symbol_context_scope = sc.comp_unit; - break; } if (symbol_context_scope) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index b86d9e293f5..c09b1668356 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -373,100 +373,36 @@ SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit // parsed to span the gaps, or we can find the global variable // sizes from the DWARF info as we are parsing. -#if 0 - // First we find the non-stab entry that corresponds to the N_GSYM in the executable - Symbol *exe_gsym_symbol = exe_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny); -#else - // The mach-o object file parser already matches up the N_GSYM with with the non-stab - // entry, so we shouldn't have to do that. If this ever changes, enable the code above - // in the "#if 0" block. STSYM's always match the symbol as found below. - Symbol *exe_gsym_symbol = exe_symbol; -#endif // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file - Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData, Symtab::eDebugNo, Symtab::eVisibilityAny); - if (oso_gsym_symbol == NULL) - oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeExtern, Symtab::eDebugNo, Symtab::eVisibilityExtern); - if (exe_gsym_symbol && oso_gsym_symbol && exe_gsym_symbol->GetAddressRangePtr() && oso_gsym_symbol->GetAddressRangePtr()) + Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(), + eSymbolTypeData, + Symtab::eDebugNo, + Symtab::eVisibilityAny); + + if (exe_symbol && oso_gsym_symbol && exe_symbol->GetAddressRangePtr() && oso_gsym_symbol->GetAddressRangePtr()) { // If we found the symbol, then we - Section* exe_gsym_section = const_cast<Section *>(exe_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); + Section* exe_gsym_section = const_cast<Section *>(exe_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); Section* oso_gsym_section = const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); if (oso_gsym_section) { SectionSP oso_gsym_section_sp (new Section (const_cast<Section *>(oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()), - oso_module, // Module (the .o file) - sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs - exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), // Name the section the same as the symbol for which is was generated! - eSectionTypeDebug, - oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section - 1, // We don't know the size of the global, just do the main address for now. - 0, 0, 0)); + oso_module, // Module (the .o file) + sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs + exe_symbol->GetMangled().GetName(Mangled::ePreferMangled), // Name the section the same as the symbol for which is was generated! + eSectionTypeDebug, + oso_gsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), // File VM address offset in the current section + 1, // We don't know the size of the global, just do the main address for now. + 0, 0, 0)); oso_gsym_section_sp->SetLinkedLocation (exe_gsym_section, - exe_gsym_symbol->GetValue().GetFileAddress() - exe_gsym_section->GetFileAddress()); + exe_symbol->GetValue().GetFileAddress() - exe_gsym_section->GetFileAddress()); oso_gsym_section->GetChildren().AddSection(oso_gsym_section_sp); comp_unit_info->debug_map_sections_sp->AddSection(oso_gsym_section_sp); } } } break; - -// case eSymbolTypeStatic: -// { -// // For each N_STSYM we remap the address for the global by making -// // a new section that we add to the sections found in the .o file. -// // This new section has the file address set to what the -// // addresses are in the .o file, and the load address is adjusted -// // to match where it ended up in the final executable! We do this -// // before we parse any dwarf info so that when it goes get parsed -// // all section/offset addresses that get registered will resolve -// // correctly to the new addresses in the main executable. We -// // initially set the section size to be 1 byte, but will need to -// // fix up these addresses further after all globals have been -// // parsed to span the gaps, or we can find the global variable -// // sizes from the DWARF info as we are parsing. -// -// -// Symbol *exe_stsym_symbol = exe_symbol; -// // First we find the non-stab entry that corresponds to the N_STSYM in the .o file -// Symbol *oso_stsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType(exe_symbol->GetMangled().GetName(), eSymbolTypeData); -// if (exe_stsym_symbol && oso_stsym_symbol) -// { -// // If we found the symbol, then we -// Section* exe_stsym_section = const_cast<Section *>(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); -// Section* oso_stsym_section = const_cast<Section *>(oso_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection()); -// if (oso_stsym_section) -// { -// // The load address of the symbol will use the section in the -// // executable that contains the debug map that corresponds to -// // the N_FUN symbol. We set the offset to reflect the offset -// // into that section since we are creating a new section. -// AddressRange stsym_load_range(exe_stsym_section, exe_stsym_symbol->GetValue().GetFileAddress() - exe_stsym_section->GetFileAddress(), 1); -// // We need the symbol's section offset address from the .o file, but -// // we need a non-zero size. -// AddressRange stsym_file_range(exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetSection(), exe_stsym_symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset(), 1); -// -// // Now we create a section that we will add as a child of the -// // section in which the .o symbol (the N_FUN) exists. -// -//// TODO: mimic what I did for N_FUN if that works... -//// // We use the 1 byte for the size because we don't know the -//// // size of the global symbol without seeing the DWARF. -//// SectionSP oso_fun_section_sp (new Section ( NULL, oso_module, // Module (the .o file) -//// sect_id++, // Section ID starts at 0x10000 and increments so the section IDs don't overlap with the standard mach IDs -//// exe_symbol->GetMangled().GetName(),// Name the section the same as the symbol for which is was generated! -//// // &stsym_load_range, // Load offset is the offset into the executable section for the N_FUN from the debug map -//// &stsym_file_range, // File section/offset is just the same os the symbol on the .o file -//// 0, 0, 0)); -//// -//// // Now we add the new section to the .o file's sections as a child -//// // of the section in which the N_SECT symbol exists. -//// oso_stsym_section->GetChildren().AddSection(oso_fun_section_sp); -//// comp_unit_info->debug_map_sections_sp->AddSection(oso_fun_section_sp); -// } -// } -// } -// break; } } } |

