<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
This commit is contained in:
Greg Clayton 2011-11-13 04:15:56 +00:00
parent c8cfd3a8fb
commit 2fc93eabf7
14 changed files with 507 additions and 196 deletions

View File

@ -42,24 +42,24 @@ typedef uint32_t dw_offset_t; // Dwarf Debug Information Entry offset for
#define DW_EH_PE_MASK_ENCODING 0x0F
// The following are used only internally within lldb - don't
// document them in the llvm Dwarf.h header file, we won't see
// them in executable files anywhere.
// These constants fit between DW_OP_lo_user (0xe0) and DW_OP_hi_user (0xff).
#define DW_OP_APPLE_array_ref 0xEE // first pops index, then pops array; pushes array[index]
#define DW_OP_APPLE_extern 0xEF // ULEB128 index of external object (i.e., an entity from the program that was used in the expression)
#define DW_OP_APPLE_uninit 0xF0
#define DW_OP_APPLE_assign 0xF1 // pops value off and assigns it to second item on stack (2nd item must have assignable context)
#define DW_OP_APPLE_address_of 0xF2 // gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
#define DW_OP_APPLE_value_of 0xF3 // pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
#define DW_OP_APPLE_deref_type 0xF4 // gets the address of the top stack item (top item must be a variable, or a clang type)
#define DW_OP_APPLE_expr_local 0xF5 // ULEB128 expression local index
#define DW_OP_APPLE_constf 0xF6 // 1 byte float size, followed by constant float data
#define DW_OP_APPLE_scalar_cast 0xF7 // Cast top of stack to 2nd in stack's type leaving all items in place
#define DW_OP_APPLE_clang_cast 0xF8 // pointer size clang::Type * off the stack and cast top stack item to this type
#define DW_OP_APPLE_clear 0xFE // clears the entire expression stack, ok if the stack is empty
#define DW_OP_APPLE_error 0xFF // Stops expression evaluation and returns an error (no args)
//// The following are used only internally within lldb - don't
//// document them in the llvm Dwarf.h header file, we won't see
//// them in executable files anywhere.
//// These constants fit between DW_OP_lo_user (0xe0) and DW_OP_hi_user (0xff).
//
//#define DW_OP_APPLE_array_ref 0xEE // first pops index, then pops array; pushes array[index]
//#define DW_OP_APPLE_extern 0xEF // ULEB128 index of external object (i.e., an entity from the program that was used in the expression)
#define DW_OP_APPLE_uninit 0xF0 // This is actually generated by some apple compilers in locations lists
//#define DW_OP_APPLE_assign 0xF1 // pops value off and assigns it to second item on stack (2nd item must have assignable context)
//#define DW_OP_APPLE_address_of 0xF2 // gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
//#define DW_OP_APPLE_value_of 0xF3 // pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
//#define DW_OP_APPLE_deref_type 0xF4 // gets the address of the top stack item (top item must be a variable, or a clang type)
//#define DW_OP_APPLE_expr_local 0xF5 // ULEB128 expression local index
//#define DW_OP_APPLE_constf 0xF6 // 1 byte float size, followed by constant float data
//#define DW_OP_APPLE_scalar_cast 0xF7 // Cast top of stack to 2nd in stack's type leaving all items in place
//#define DW_OP_APPLE_clang_cast 0xF8 // pointer size clang::Type * off the stack and cast top stack item to this type
//#define DW_OP_APPLE_clear 0xFE // clears the entire expression stack, ok if the stack is empty
//#define DW_OP_APPLE_error 0xFF // Stops expression evaluation and returns an error (no args)
#endif // DebugBase_dwarf_h_

View File

@ -130,6 +130,30 @@ public:
bool
LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const;
//------------------------------------------------------------------
/// If a location is not a location list, return true if the location
/// contains a DW_OP_addr () opcode in the stream that matches \a
/// file_addr. If file_addr is LLDB_INVALID_ADDRESS, the this
/// function will return true if the variable there is any DW_OP_addr
/// in a location that (yet still is NOT a location list). This helps
/// us detect if a variable is a global or static variable since
/// there is no other indication from DWARF debug info.
///
/// @param[in] file_addr
/// The file address to search for in the location.
///
/// @return
/// True if IsLocationList() is false and the \a file_addr was
/// is contained in a DW_OP_addr location opcode or if \a file_addr
/// was invalid and there are any DW_OP_addr opcodes, false
/// otherwise.
//------------------------------------------------------------------
bool
LocationContains_DW_OP_addr (lldb::addr_t file_addr = LLDB_INVALID_ADDRESS) const;
bool
Update_DW_OP_addr (lldb::addr_t file_addr);
//------------------------------------------------------------------
/// Make the expression parser read its location information from a
/// given data source. Does not change the offset and length

View File

@ -428,7 +428,6 @@ namespace lldb {
eSymbolTypeAny = 0,
eSymbolTypeInvalid = 0,
eSymbolTypeAbsolute,
eSymbolTypeExtern,
eSymbolTypeCode,
eSymbolTypeData,
eSymbolTypeTrampoline,

View File

@ -702,7 +702,7 @@ public:
size_t count = comp_unit_varlist_sp->GetSize();
if (count > 0)
{
s.Printf ("Global in %s/%s:\n",
s.Printf ("Global variables for %s/%s:\n",
comp_unit->GetDirectory().GetCString(),
comp_unit->GetFilename().GetCString());

View File

@ -746,7 +746,6 @@ ClangExpressionDeclMap::GetSymbolAddress (Target &target, const ConstString &nam
case eSymbolTypeParam:
case eSymbolTypeInvalid:
case eSymbolTypeAbsolute:
case eSymbolTypeExtern:
case eSymbolTypeException:
case eSymbolTypeSourceFile:
case eSymbolTypeHeaderFile:

View File

@ -11,6 +11,7 @@
#include <vector>
#include "lldb/Core/DataEncoder.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
@ -193,19 +194,19 @@ DW_OP_value_to_name (uint32_t val)
case 0x98: return "DW_OP_call2";
case 0x99: return "DW_OP_call4";
case 0x9a: return "DW_OP_call_ref";
case DW_OP_APPLE_array_ref: return "DW_OP_APPLE_array_ref";
case DW_OP_APPLE_extern: return "DW_OP_APPLE_extern";
// case DW_OP_APPLE_array_ref: return "DW_OP_APPLE_array_ref";
// case DW_OP_APPLE_extern: return "DW_OP_APPLE_extern";
case DW_OP_APPLE_uninit: return "DW_OP_APPLE_uninit";
case DW_OP_APPLE_assign: return "DW_OP_APPLE_assign";
case DW_OP_APPLE_address_of: return "DW_OP_APPLE_address_of";
case DW_OP_APPLE_value_of: return "DW_OP_APPLE_value_of";
case DW_OP_APPLE_deref_type: return "DW_OP_APPLE_deref_type";
case DW_OP_APPLE_expr_local: return "DW_OP_APPLE_expr_local";
case DW_OP_APPLE_constf: return "DW_OP_APPLE_constf";
case DW_OP_APPLE_scalar_cast: return "DW_OP_APPLE_scalar_cast";
case DW_OP_APPLE_clang_cast: return "DW_OP_APPLE_clang_cast";
case DW_OP_APPLE_clear: return "DW_OP_APPLE_clear";
case DW_OP_APPLE_error: return "DW_OP_APPLE_error";
// case DW_OP_APPLE_assign: return "DW_OP_APPLE_assign";
// case DW_OP_APPLE_address_of: return "DW_OP_APPLE_address_of";
// case DW_OP_APPLE_value_of: return "DW_OP_APPLE_value_of";
// case DW_OP_APPLE_deref_type: return "DW_OP_APPLE_deref_type";
// case DW_OP_APPLE_expr_local: return "DW_OP_APPLE_expr_local";
// case DW_OP_APPLE_constf: return "DW_OP_APPLE_constf";
// case DW_OP_APPLE_scalar_cast: return "DW_OP_APPLE_scalar_cast";
// case DW_OP_APPLE_clang_cast: return "DW_OP_APPLE_clang_cast";
// case DW_OP_APPLE_clear: return "DW_OP_APPLE_clear";
// case DW_OP_APPLE_error: return "DW_OP_APPLE_error";
default:
snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
return invalid;
@ -567,55 +568,55 @@ DWARFExpression::DumpLocation (Stream *s, uint32_t offset, uint32_t length, lldb
// break;
// case DW_OP_lo_user: s->PutCString("DW_OP_lo_user"); break; // 0xe0
// case DW_OP_hi_user: s->PutCString("DW_OP_hi_user"); break; // 0xff
case DW_OP_APPLE_extern:
s->Printf("DW_OP_APPLE_extern(%llu)", m_data.GetULEB128(&offset));
break;
case DW_OP_APPLE_array_ref:
s->PutCString("DW_OP_APPLE_array_ref");
break;
// case DW_OP_APPLE_extern:
// s->Printf("DW_OP_APPLE_extern(%llu)", m_data.GetULEB128(&offset));
// break;
// case DW_OP_APPLE_array_ref:
// s->PutCString("DW_OP_APPLE_array_ref");
// break;
case DW_OP_APPLE_uninit:
s->PutCString("DW_OP_APPLE_uninit"); // 0xF0
break;
case DW_OP_APPLE_assign: // 0xF1 - pops value off and assigns it to second item on stack (2nd item must have assignable context)
s->PutCString("DW_OP_APPLE_assign");
break;
case DW_OP_APPLE_address_of: // 0xF2 - gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
s->PutCString("DW_OP_APPLE_address_of");
break;
case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
s->PutCString("DW_OP_APPLE_value_of");
break;
case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of the top stack item (top item must be a variable, or a clang type)
s->PutCString("DW_OP_APPLE_deref_type");
break;
case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index
s->Printf("DW_OP_APPLE_expr_local(%llu)", m_data.GetULEB128(&offset));
break;
case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data
{
uint8_t float_length = m_data.GetU8(&offset);
s->Printf("DW_OP_APPLE_constf(<%u> ", float_length);
m_data.Dump(s, offset, eFormatHex, float_length, 1, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
s->PutChar(')');
// Consume the float data
m_data.GetData(&offset, float_length);
}
break;
case DW_OP_APPLE_scalar_cast:
s->Printf("DW_OP_APPLE_scalar_cast(%s)", Scalar::GetValueTypeAsCString ((Scalar::Type)m_data.GetU8(&offset)));
break;
case DW_OP_APPLE_clang_cast:
{
clang::Type *clang_type = (clang::Type *)m_data.GetMaxU64(&offset, sizeof(void*));
s->Printf("DW_OP_APPLE_clang_cast(%p)", clang_type);
}
break;
case DW_OP_APPLE_clear:
s->PutCString("DW_OP_APPLE_clear");
break;
case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
s->PutCString("DW_OP_APPLE_error");
break;
// case DW_OP_APPLE_assign: // 0xF1 - pops value off and assigns it to second item on stack (2nd item must have assignable context)
// s->PutCString("DW_OP_APPLE_assign");
// break;
// case DW_OP_APPLE_address_of: // 0xF2 - gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
// s->PutCString("DW_OP_APPLE_address_of");
// break;
// case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
// s->PutCString("DW_OP_APPLE_value_of");
// break;
// case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of the top stack item (top item must be a variable, or a clang type)
// s->PutCString("DW_OP_APPLE_deref_type");
// break;
// case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index
// s->Printf("DW_OP_APPLE_expr_local(%llu)", m_data.GetULEB128(&offset));
// break;
// case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data
// {
// uint8_t float_length = m_data.GetU8(&offset);
// s->Printf("DW_OP_APPLE_constf(<%u> ", float_length);
// m_data.Dump(s, offset, eFormatHex, float_length, 1, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
// s->PutChar(')');
// // Consume the float data
// m_data.GetData(&offset, float_length);
// }
// break;
// case DW_OP_APPLE_scalar_cast:
// s->Printf("DW_OP_APPLE_scalar_cast(%s)", Scalar::GetValueTypeAsCString ((Scalar::Type)m_data.GetU8(&offset)));
// break;
// case DW_OP_APPLE_clang_cast:
// {
// clang::Type *clang_type = (clang::Type *)m_data.GetMaxU64(&offset, sizeof(void*));
// s->Printf("DW_OP_APPLE_clang_cast(%p)", clang_type);
// }
// break;
// case DW_OP_APPLE_clear:
// s->PutCString("DW_OP_APPLE_clear");
// break;
// case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
// s->PutCString("DW_OP_APPLE_error");
// break;
}
}
}
@ -797,6 +798,275 @@ ReadRegisterValueAsScalar
// return false;
//}
static uint32_t
GetOpcodeDataSize (const DataExtractor &data, const uint32_t data_offset, const uint8_t op)
{
uint32_t offset = data_offset;
switch (op)
{
case DW_OP_addr:
case DW_OP_call_ref: // 0x9a 1 address sized offset of DIE (DWARF3)
return data.GetAddressByteSize();
// Opcodes with no arguments
case DW_OP_deref: // 0x06
case DW_OP_dup: // 0x12
case DW_OP_drop: // 0x13
case DW_OP_over: // 0x14
case DW_OP_swap: // 0x16
case DW_OP_rot: // 0x17
case DW_OP_xderef: // 0x18
case DW_OP_abs: // 0x19
case DW_OP_and: // 0x1a
case DW_OP_div: // 0x1b
case DW_OP_minus: // 0x1c
case DW_OP_mod: // 0x1d
case DW_OP_mul: // 0x1e
case DW_OP_neg: // 0x1f
case DW_OP_not: // 0x20
case DW_OP_or: // 0x21
case DW_OP_plus: // 0x22
case DW_OP_shl: // 0x24
case DW_OP_shr: // 0x25
case DW_OP_shra: // 0x26
case DW_OP_xor: // 0x27
case DW_OP_eq: // 0x29
case DW_OP_ge: // 0x2a
case DW_OP_gt: // 0x2b
case DW_OP_le: // 0x2c
case DW_OP_lt: // 0x2d
case DW_OP_ne: // 0x2e
case DW_OP_lit0: // 0x30
case DW_OP_lit1: // 0x31
case DW_OP_lit2: // 0x32
case DW_OP_lit3: // 0x33
case DW_OP_lit4: // 0x34
case DW_OP_lit5: // 0x35
case DW_OP_lit6: // 0x36
case DW_OP_lit7: // 0x37
case DW_OP_lit8: // 0x38
case DW_OP_lit9: // 0x39
case DW_OP_lit10: // 0x3A
case DW_OP_lit11: // 0x3B
case DW_OP_lit12: // 0x3C
case DW_OP_lit13: // 0x3D
case DW_OP_lit14: // 0x3E
case DW_OP_lit15: // 0x3F
case DW_OP_lit16: // 0x40
case DW_OP_lit17: // 0x41
case DW_OP_lit18: // 0x42
case DW_OP_lit19: // 0x43
case DW_OP_lit20: // 0x44
case DW_OP_lit21: // 0x45
case DW_OP_lit22: // 0x46
case DW_OP_lit23: // 0x47
case DW_OP_lit24: // 0x48
case DW_OP_lit25: // 0x49
case DW_OP_lit26: // 0x4A
case DW_OP_lit27: // 0x4B
case DW_OP_lit28: // 0x4C
case DW_OP_lit29: // 0x4D
case DW_OP_lit30: // 0x4E
case DW_OP_lit31: // 0x4f
case DW_OP_reg0: // 0x50
case DW_OP_reg1: // 0x51
case DW_OP_reg2: // 0x52
case DW_OP_reg3: // 0x53
case DW_OP_reg4: // 0x54
case DW_OP_reg5: // 0x55
case DW_OP_reg6: // 0x56
case DW_OP_reg7: // 0x57
case DW_OP_reg8: // 0x58
case DW_OP_reg9: // 0x59
case DW_OP_reg10: // 0x5A
case DW_OP_reg11: // 0x5B
case DW_OP_reg12: // 0x5C
case DW_OP_reg13: // 0x5D
case DW_OP_reg14: // 0x5E
case DW_OP_reg15: // 0x5F
case DW_OP_reg16: // 0x60
case DW_OP_reg17: // 0x61
case DW_OP_reg18: // 0x62
case DW_OP_reg19: // 0x63
case DW_OP_reg20: // 0x64
case DW_OP_reg21: // 0x65
case DW_OP_reg22: // 0x66
case DW_OP_reg23: // 0x67
case DW_OP_reg24: // 0x68
case DW_OP_reg25: // 0x69
case DW_OP_reg26: // 0x6A
case DW_OP_reg27: // 0x6B
case DW_OP_reg28: // 0x6C
case DW_OP_reg29: // 0x6D
case DW_OP_reg30: // 0x6E
case DW_OP_reg31: // 0x6F
case DW_OP_nop: // 0x96
case DW_OP_push_object_address: // 0x97 DWARF3
case DW_OP_form_tls_address: // 0x9b DWARF3
case DW_OP_call_frame_cfa: // 0x9c DWARF3
return 0;
// Opcodes with a single 1 byte arguments
case DW_OP_const1u: // 0x08 1 1-byte constant
case DW_OP_const1s: // 0x09 1 1-byte constant
case DW_OP_pick: // 0x15 1 1-byte stack index
case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
return 1;
// Opcodes with a single 2 byte arguments
case DW_OP_const2u: // 0x0a 1 2-byte constant
case DW_OP_const2s: // 0x0b 1 2-byte constant
case DW_OP_skip: // 0x2f 1 signed 2-byte constant
case DW_OP_bra: // 0x28 1 signed 2-byte constant
case DW_OP_call2: // 0x98 1 2-byte offset of DIE (DWARF3)
return 2;
// Opcodes with a single 4 byte arguments
case DW_OP_const4u: // 0x0c 1 4-byte constant
case DW_OP_const4s: // 0x0d 1 4-byte constant
case DW_OP_call4: // 0x99 1 4-byte offset of DIE (DWARF3)
return 4;
// Opcodes with a single 8 byte arguments
case DW_OP_const8u: // 0x0e 1 8-byte constant
case DW_OP_const8s: // 0x0f 1 8-byte constant
return 8;
// All opcodes that have a single ULEB (signed or unsigned) argument
case DW_OP_constu: // 0x10 1 ULEB128 constant
case DW_OP_consts: // 0x11 1 SLEB128 constant
case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
case DW_OP_breg0: // 0x70 1 ULEB128 register
case DW_OP_breg1: // 0x71 1 ULEB128 register
case DW_OP_breg2: // 0x72 1 ULEB128 register
case DW_OP_breg3: // 0x73 1 ULEB128 register
case DW_OP_breg4: // 0x74 1 ULEB128 register
case DW_OP_breg5: // 0x75 1 ULEB128 register
case DW_OP_breg6: // 0x76 1 ULEB128 register
case DW_OP_breg7: // 0x77 1 ULEB128 register
case DW_OP_breg8: // 0x78 1 ULEB128 register
case DW_OP_breg9: // 0x79 1 ULEB128 register
case DW_OP_breg10: // 0x7a 1 ULEB128 register
case DW_OP_breg11: // 0x7b 1 ULEB128 register
case DW_OP_breg12: // 0x7c 1 ULEB128 register
case DW_OP_breg13: // 0x7d 1 ULEB128 register
case DW_OP_breg14: // 0x7e 1 ULEB128 register
case DW_OP_breg15: // 0x7f 1 ULEB128 register
case DW_OP_breg16: // 0x80 1 ULEB128 register
case DW_OP_breg17: // 0x81 1 ULEB128 register
case DW_OP_breg18: // 0x82 1 ULEB128 register
case DW_OP_breg19: // 0x83 1 ULEB128 register
case DW_OP_breg20: // 0x84 1 ULEB128 register
case DW_OP_breg21: // 0x85 1 ULEB128 register
case DW_OP_breg22: // 0x86 1 ULEB128 register
case DW_OP_breg23: // 0x87 1 ULEB128 register
case DW_OP_breg24: // 0x88 1 ULEB128 register
case DW_OP_breg25: // 0x89 1 ULEB128 register
case DW_OP_breg26: // 0x8a 1 ULEB128 register
case DW_OP_breg27: // 0x8b 1 ULEB128 register
case DW_OP_breg28: // 0x8c 1 ULEB128 register
case DW_OP_breg29: // 0x8d 1 ULEB128 register
case DW_OP_breg30: // 0x8e 1 ULEB128 register
case DW_OP_breg31: // 0x8f 1 ULEB128 register
case DW_OP_regx: // 0x90 1 ULEB128 register
case DW_OP_fbreg: // 0x91 1 SLEB128 offset
case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
data.Skip_LEB128(&offset);
return offset - data_offset;
// All opcodes that have a 2 ULEB (signed or unsigned) arguments
case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
data.Skip_LEB128(&offset);
data.Skip_LEB128(&offset);
return offset - data_offset;
default:
assert (!"Unhandled DW_OP_XXX opcode, add support for it");
break;
}
return UINT32_MAX;
}
bool
DWARFExpression::LocationContains_DW_OP_addr (lldb::addr_t file_addr) const
{
if (IsLocationList())
return false;
uint32_t offset = 0;
while (m_data.ValidOffset(offset))
{
const uint8_t op = m_data.GetU8(&offset);
if (op == DW_OP_addr)
{
if (file_addr == LLDB_INVALID_ADDRESS)
return true;
addr_t op_file_addr = m_data.GetAddress(&offset);
if (op_file_addr == file_addr)
return true;
}
else
{
const uint32_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
if (op_arg_size == UINT32_MAX)
break;
offset += op_arg_size;
}
}
return false;
}
bool
DWARFExpression::Update_DW_OP_addr (lldb::addr_t file_addr)
{
if (IsLocationList())
return false;
uint32_t offset = 0;
while (m_data.ValidOffset(offset))
{
const uint8_t op = m_data.GetU8(&offset);
if (op == DW_OP_addr)
{
const uint8_t addr_byte_size = m_data.GetAddressByteSize();
// We have to make a copy of the data as we don't know if this
// data is from a read only memory mapped buffer, so we duplicate
// all of the data first, then modify it, and if all goes well,
// we then replace the data for this expression
// So first we copy the data into a heap buffer
std::auto_ptr<DataBufferHeap> head_data_ap (new DataBufferHeap (m_data.GetDataStart(),
m_data.GetByteSize()));
// Make en encoder so we can write the address into the buffer using
// the correct byte order (endianness)
DataEncoder encoder (head_data_ap->GetBytes(),
head_data_ap->GetByteSize(),
m_data.GetByteOrder(),
addr_byte_size);
// Replace the address in the new buffer
if (encoder.PutMaxU64 (offset, addr_byte_size, file_addr) == UINT32_MAX)
return false;
// All went well, so now we can reset the data using a shared
// pointer to the heap data so "m_data" will now correctly
// manage the heap data.
m_data.SetData (DataBufferSP (head_data_ap.release()));
return true;
}
else
{
const uint32_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
if (op_arg_size == UINT32_MAX)
break;
offset += op_arg_size;
}
}
return false;
}
bool
DWARFExpression::LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const
{
@ -2309,7 +2579,7 @@ DWARFExpression::Evaluate
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call4.");
return false;
#if 0
//----------------------------------------------------------------------
// OPCODE: DW_OP_call_ref
// OPERANDS:
@ -2344,15 +2614,15 @@ DWARFExpression::Evaluate
error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call_ref.");
return false;
//----------------------------------------------------------------------
// OPCODE: DW_OP_APPLE_array_ref
// OPERANDS: none
// DESCRIPTION: Pops a value off the stack and uses it as the array
// index. Pops a second value off the stack and uses it as the array
// itself. Pushes a value onto the stack representing the element of
// the array specified by the index.
//----------------------------------------------------------------------
case DW_OP_APPLE_array_ref:
//----------------------------------------------------------------------
// OPCODE: DW_OP_APPLE_array_ref
// OPERANDS: none
// DESCRIPTION: Pops a value off the stack and uses it as the array
// index. Pops a second value off the stack and uses it as the array
// itself. Pushes a value onto the stack representing the element of
// the array specified by the index.
//----------------------------------------------------------------------
case DW_OP_APPLE_array_ref:
{
if (stack.size() < 2)
{
@ -2375,7 +2645,7 @@ DWARFExpression::Evaluate
error_ptr->SetErrorString("Invalid array index.");
return false;
}
if (array_val.GetContextType() != Value::eContextTypeClangType)
{
if (error_ptr)
@ -2433,7 +2703,7 @@ DWARFExpression::Evaluate
stack.push_back(member);
}
break;
break;
//----------------------------------------------------------------------
// OPCODE: DW_OP_APPLE_uninit
@ -2866,6 +3136,8 @@ DWARFExpression::Evaluate
if (error_ptr)
error_ptr->SetErrorString ("Generic error.");
return false;
#endif // #if 0
}
}

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}
}

View File

@ -238,7 +238,6 @@ ObjectFile::GetAddressClass (addr_t file_addr)
{
case eSymbolTypeAny: return eAddressClassUnknown;
case eSymbolTypeAbsolute: return eAddressClassUnknown;
case eSymbolTypeExtern: return eAddressClassUnknown;
case eSymbolTypeCode: return eAddressClassCode;
case eSymbolTypeTrampoline: return eAddressClassCode;
case eSymbolTypeData: return eAddressClassData;

View File

@ -317,7 +317,6 @@ Symbol::GetTypeAsString() const
{
ENUM_TO_CSTRING(Invalid);
ENUM_TO_CSTRING(Absolute);
ENUM_TO_CSTRING(Extern);
ENUM_TO_CSTRING(Code);
ENUM_TO_CSTRING(Data);
ENUM_TO_CSTRING(Trampoline);

View File

@ -53,8 +53,9 @@ class GlobalVariablesTestCase(TestBase):
substrs = ['GLOBAL: (int) g_file_global_int = 42',
'GLOBAL: (const char *) g_file_global_cstr',
'"g_file_global_cstr"',
'GLOBAL: (const char *) g_file_static_cstr',
'"g_file_static_cstr"'])
'STATIC: (const char *) g_file_static_cstr',
'"g_file_static_cstr"',
'GLOBAL: (int) g_common_1 = 21'])
# 'frame variable' should support address-of operator.
self.runCmd("frame variable &g_file_global_int")

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include <stdio.h>
int g_common_1; // Not initialized on purpose to cause it to be undefined external in .o file
int g_file_global_int = 42;
const char *g_file_global_cstr = "g_file_global_cstr";
static const char *g_file_static_cstr = "g_file_static_cstr";
@ -15,7 +16,8 @@ static const char *g_file_static_cstr = "g_file_static_cstr";
extern int g_a;
int main (int argc, char const *argv[])
{
g_common_1 = g_file_global_int / 2;
static const char *g_func_static_cstr = "g_func_static_cstr";
printf ("%s %s\n", g_file_global_cstr, g_file_static_cstr);
return g_file_global_int + g_a; // Set break point at this line. //// break $source:$line; continue; var -global g_a -global g_global_int
return g_file_global_int + g_a + g_common_1; // Set break point at this line. //// break $source:$line; continue; var -global g_a -global g_global_int
}

View File

@ -190,8 +190,6 @@ def symbol_type_to_str(enum):
return "invalid"
elif enum == lldb.eSymbolTypeAbsolute:
return "absolute"
elif enum == lldb.eSymbolTypeExtern:
return "extern"
elif enum == lldb.eSymbolTypeCode:
return "code"
elif enum == lldb.eSymbolTypeData: