/* Print a natural-language description of SYMBOL to STREAM. */ static int locexpr_describe_location (struct symbol *symbol, struct ui_file *stream) { /* FIXME: be more extensive. */ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu); if (dlbaton->size == 1 && dlbaton->data[0] >= DW_OP_reg0 && dlbaton->data[0] <= DW_OP_reg31) { struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); int regno = gdbarch_dwarf2_reg_to_regnum (gdbarch, dlbaton->data[0] - DW_OP_reg0); fprintf_filtered (stream, "a variable in register %s", gdbarch_register_name (gdbarch, regno)); return 1; } /* The location expression for a TLS variable looks like this (on a 64-bit LE machine): DW_AT_location : 10 byte block: 3 4 0 0 0 0 0 0 0 e0 (DW_OP_addr: 4; DW_OP_GNU_push_tls_address) 0x3 is the encoding for DW_OP_addr, which has an operand as long as the size of an address on the target machine (here is 8 bytes). 0xe0 is the encoding for DW_OP_GNU_push_tls_address. The operand represents the offset at which the variable is within the thread local storage. */ if (dlbaton->size > 1 && dlbaton->data[dlbaton->size - 1] == DW_OP_GNU_push_tls_address) if (dlbaton->data[0] == DW_OP_addr) { struct objfile *objfile = dwarf2_per_cu_objfile (dlbaton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); CORE_ADDR offset = dwarf2_read_address (gdbarch, &dlbaton->data[1], &dlbaton->data[dlbaton->size - 1], addr_size); fprintf_filtered (stream, "a thread-local variable at offset %s in the " "thread-local storage for `%s'", paddr_nz (offset), objfile->name); return 1; } fprintf_filtered (stream, "a variable with complex or multiple locations (DWARF2)"); return 1; }
static gdb_byte * find_location_expression (struct dwarf2_loclist_baton *baton, size_t *locexpr_length, CORE_ADDR pc) { CORE_ADDR low, high; gdb_byte *loc_ptr, *buf_end; int length; struct objfile *objfile = dwarf2_per_cu_objfile (baton->per_cu); struct gdbarch *gdbarch = get_objfile_arch (objfile); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); unsigned int addr_size = dwarf2_per_cu_addr_size (baton->per_cu); CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); CORE_ADDR base_address = baton->base_address + base_offset; loc_ptr = baton->data; buf_end = baton->data + baton->size; while (1) { if (buf_end - loc_ptr < 2 * addr_size) error (_("find_location_expression: Corrupted DWARF expression.")); low = extract_unsigned_integer (loc_ptr, addr_size, byte_order); loc_ptr += addr_size; /* A base-address-selection entry. */ if (low == base_mask) { base_address = dwarf2_read_address (gdbarch, loc_ptr, buf_end, addr_size); loc_ptr += addr_size; continue; } high = extract_unsigned_integer (loc_ptr, addr_size, byte_order); loc_ptr += addr_size; /* An end-of-list entry. */ if (low == 0 && high == 0) return NULL; /* Otherwise, a location expression entry. */ low += base_address; high += base_address; length = extract_unsigned_integer (loc_ptr, 2, byte_order); loc_ptr += 2; if (pc >= low && pc < high) { *locexpr_length = length; return loc_ptr; } loc_ptr += length; } }
static int dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size, struct dwarf2_per_cu_data *per_cu) { struct needs_frame_baton baton; struct dwarf_expr_context *ctx; int in_reg; baton.needs_frame = 0; ctx = new_dwarf_expr_context (); ctx->gdbarch = get_objfile_arch (dwarf2_per_cu_objfile (per_cu)); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); ctx->baton = &baton; ctx->read_reg = needs_frame_read_reg; ctx->read_mem = needs_frame_read_mem; ctx->get_frame_base = needs_frame_frame_base; ctx->get_tls_address = needs_frame_tls_address; dwarf_expr_eval (ctx, data, size); in_reg = ctx->in_reg; if (ctx->num_pieces > 0) { int i; /* If the location has several pieces, and any of them are in registers, then we will need a frame to fetch them from. */ for (i = 0; i < ctx->num_pieces; i++) if (ctx->pieces[i].in_reg) in_reg = 1; } free_dwarf_expr_context (ctx); return baton.needs_frame || in_reg; }
/* Evaluate a location description, starting at DATA and with length SIZE, to find the current location of variable VAR in the context of FRAME. */ static struct value * dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, gdb_byte *data, unsigned short size, struct dwarf2_per_cu_data *per_cu) { struct value *retval; struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; if (size == 0) { retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = not_lval; set_value_optimized_out (retval, 1); return retval; } baton.frame = frame; baton.objfile = dwarf2_per_cu_objfile (per_cu); ctx = new_dwarf_expr_context (); ctx->gdbarch = get_objfile_arch (baton.objfile); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); ctx->baton = &baton; ctx->read_reg = dwarf_expr_read_reg; ctx->read_mem = dwarf_expr_read_mem; ctx->get_frame_base = dwarf_expr_frame_base; ctx->get_tls_address = dwarf_expr_tls_address; dwarf_expr_eval (ctx, data, size); if (ctx->num_pieces > 0) { int i; long offset = 0; bfd_byte *contents; retval = allocate_value (SYMBOL_TYPE (var)); contents = value_contents_raw (retval); for (i = 0; i < ctx->num_pieces; i++) { struct dwarf_expr_piece *p = &ctx->pieces[i]; if (p->in_reg) { struct gdbarch *arch = get_frame_arch (frame); bfd_byte regval[MAX_REGISTER_SIZE]; int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->value); get_frame_register (frame, gdb_regnum, regval); memcpy (contents + offset, regval, p->size); } else /* In memory? */ { read_memory (p->value, contents + offset, p->size); } offset += p->size; } } else if (ctx->in_reg) { struct gdbarch *arch = get_frame_arch (frame); CORE_ADDR dwarf_regnum = dwarf_expr_fetch (ctx, 0); int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum); retval = value_from_register (SYMBOL_TYPE (var), gdb_regnum, frame); } else { CORE_ADDR address = dwarf_expr_fetch (ctx, 0); retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = lval_memory; set_value_lazy (retval, 1); set_value_address (retval, address); } set_value_initialized (retval, ctx->initialized); free_dwarf_expr_context (ctx); return retval; }