2003-04-13 Daniel Jacobowitz <drow@mvista.com>
authorDaniel Jacobowitz <drow@false.org>
Sun, 13 Apr 2003 15:43:35 +0000 (15:43 +0000)
committerDaniel Jacobowitz <drow@false.org>
Sun, 13 Apr 2003 15:43:35 +0000 (15:43 +0000)
* dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
made non-static.
(execute_stack_op): All callers updated.
* dwarf2expr.h: Add prototype for dwarf2_read_address.
* dwarf2loc.c (find_location_expression): New function.
(dwarf_expr_frame_base): Call it.
(dwarf2_evaluate_loc_desc): Handle 0-length location expressions.
(dwarf2_tracepoint_var_ref): New function, broken out from
locexpr_tracepoint_var_ref.
(locexpr_tracepoint_var_ref): Call dwarf2_tracepoint_var_ref.
Make static.
(loclist_read_variable, loclist_read_needs_frame): New functions.
(loclist_describe_location, loclist_tracepoint_var_ref): New
functions.
(dwarf2_loclist_funcs): New struct location_funcs.
* dwarf2loc.h (struct dwarf2_loclist_baton): New type.
(struct dwarf2_locexpr_baton): Add comments.
(dwarf2_loclist_funcs): New extern.
* dwarf2read.c (struct comp_unit_head): Remove DIE member, add
base_address and base_known.
(dwarf_loc_buffer): New variable.
(struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
(dwarf2_has_info): Initialize dwarf_loc_offset.
(dwarf2_build_psymtabs): Read in .debug_loc.
(dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
DWARF_LOC_SIZE.
(psymtab_to_symtab_1): Likewise.  Move base address calculation
here, from...
(dwarf2_get_pc_bounds): ... here.  Use the base address from
cu_header.
(dwarf2_symbol_mark_computed): Handle location lists.

gdb/ChangeLog
gdb/dwarf2expr.c
gdb/dwarf2expr.h
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/dwarf2read.c

index 7d6f504e4be5adf2911bb9cf39c4d7482108d320..502514aad4cc8691bca70b88015616499d508287 100644 (file)
@@ -1,3 +1,38 @@
+2003-04-13  Daniel Jacobowitz  <drow@mvista.com>
+
+       * dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
+       made non-static.
+       (execute_stack_op): All callers updated.
+       * dwarf2expr.h: Add prototype for dwarf2_read_address.
+       * dwarf2loc.c (find_location_expression): New function.
+       (dwarf_expr_frame_base): Call it.
+       (dwarf2_evaluate_loc_desc): Handle 0-length location expressions.
+       (dwarf2_tracepoint_var_ref): New function, broken out from
+       locexpr_tracepoint_var_ref.
+       (locexpr_tracepoint_var_ref): Call dwarf2_tracepoint_var_ref.
+       Make static.
+       (loclist_read_variable, loclist_read_needs_frame): New functions.
+       (loclist_describe_location, loclist_tracepoint_var_ref): New
+       functions.
+       (dwarf2_loclist_funcs): New struct location_funcs.
+       * dwarf2loc.h (struct dwarf2_loclist_baton): New type.
+       (struct dwarf2_locexpr_baton): Add comments.
+       (dwarf2_loclist_funcs): New extern.
+       * dwarf2read.c (struct comp_unit_head): Remove DIE member, add
+       base_address and base_known.
+       (dwarf_loc_buffer): New variable.
+       (struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
+       (DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
+       (dwarf2_has_info): Initialize dwarf_loc_offset.
+       (dwarf2_build_psymtabs): Read in .debug_loc.
+       (dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
+       DWARF_LOC_SIZE.
+       (psymtab_to_symtab_1): Likewise.  Move base address calculation
+       here, from...
+       (dwarf2_get_pc_bounds): ... here.  Use the base address from
+       cu_header.
+       (dwarf2_symbol_mark_computed): Handle location lists.
+
 2003-04-13  Daniel Jacobowitz  <drow@mvista.com>
 
        * minsyms.c (install_minimal_symbols): Only switch to gnu-v3 mode
index be965abd528127e524b8792a461d743aed59de5d..a87dfc6fb85162497839f3b7fd02c83da663f096 100644 (file)
@@ -170,13 +170,13 @@ read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r)
    BUF_END.  The address is returned, and *BYTES_READ is set to the
    number of bytes read from BUF.  */
 
-static CORE_ADDR
-read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read)
+CORE_ADDR
+dwarf2_read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read)
 {
   CORE_ADDR result;
 
   if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT)
-    error ("read_address: Corrupted DWARF expression.");
+    error ("dwarf2_read_address: Corrupted DWARF expression.");
 
   *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
   result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
@@ -277,7 +277,7 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
          break;
 
        case DW_OP_addr:
-         result = read_address (op_ptr, op_end, &bytes_read);
+         result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
          op_ptr += bytes_read;
          break;
 
@@ -467,9 +467,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
 
                (ctx->read_mem) (ctx->baton, buf, result,
                                 TARGET_ADDR_BIT / TARGET_CHAR_BIT);
-               result = read_address (buf,
-                                      buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
-                                      &bytes_read);
+               result = dwarf2_read_address (buf,
+                                             buf + (TARGET_ADDR_BIT
+                                                    / TARGET_CHAR_BIT),
+                                             &bytes_read);
              }
            result = result + offset;
            ctx->stack_len = before_stack_len;
@@ -528,9 +529,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
 
                (ctx->read_mem) (ctx->baton, buf, result,
                                 TARGET_ADDR_BIT / TARGET_CHAR_BIT);
-               result = read_address (buf,
-                                      buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
-                                      &bytes_read);
+               result = dwarf2_read_address (buf,
+                                             buf + (TARGET_ADDR_BIT
+                                                    / TARGET_CHAR_BIT),
+                                             &bytes_read);
              }
              break;
 
@@ -540,9 +542,10 @@ execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
                int bytes_read;
 
                (ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
-               result = read_address (buf,
-                                      buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT,
-                                      &bytes_read);
+               result = dwarf2_read_address (buf,
+                                             buf + (TARGET_ADDR_BIT
+                                                    / TARGET_CHAR_BIT),
+                                             &bytes_read);
              }
              break;
 
index 3d0fcb33e7b07f4109b2b2fd23dee7e06f388613..599800ce4823d9c4fd01ceec988f4cba2c519eda 100644 (file)
@@ -99,5 +99,7 @@ unsigned char *read_uleb128 (unsigned char *buf, unsigned char *buf_end,
                             ULONGEST * r);
 unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
                             LONGEST * r);
+CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
+                              int *bytes_read);
 
 #endif
index 7073549bf02daa5bed36c12d74a9273a4e113ea8..2f5cce5f0daec9e150a3ac7df156b56483d30aaa 100644 (file)
 #define DWARF2_REG_TO_REGNUM(REG) (REG)
 #endif
 
+/* A helper function for dealing with location lists.  Given a
+   symbol baton (BATON) and a pc value (PC), find the appropriate
+   location expression, set *LOCEXPR_LENGTH, and return a pointer
+   to the beginning of the expression.  Returns NULL on failure.
+
+   For now, only return the first matching location expression; there
+   can be more than one in the list.  */
+
+static char *
+find_location_expression (struct dwarf2_loclist_baton *baton,
+                         int *locexpr_length, CORE_ADDR pc)
+{
+  CORE_ADDR base_address = baton->base_address;
+  CORE_ADDR low, high;
+  char *loc_ptr, *buf_end;
+  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
+  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+
+  loc_ptr = baton->data;
+  buf_end = baton->data + baton->size;
+
+  while (1)
+    {
+      low = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+      high = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+
+      /* An end-of-list entry.  */
+      if (low == 0 && high == 0)
+       return NULL;
+
+      /* A base-address-selection entry.  */
+      if ((low & base_mask) == base_mask)
+       {
+         base_address = high;
+         continue;
+       }
+
+      /* Otherwise, a location expression entry.  */
+      low += base_address;
+      high += base_address;
+
+      length = extract_unsigned_integer (loc_ptr, 2);
+      loc_ptr += 2;
+
+      if (pc >= low && pc < high)
+       {
+         *locexpr_length = length;
+         return loc_ptr;
+       }
+
+      loc_ptr += length;
+    }
+}
+
 /* This is the baton used when performing dwarf2 expression
    evaluation.  */
 struct dwarf_expr_baton
@@ -91,12 +147,28 @@ dwarf_expr_frame_base (void *baton, unsigned char **start, size_t * length)
      get_frame_base_address(), and then implement a dwarf2 specific
      this_base method.  */
   struct symbol *framefunc;
-  struct dwarf2_locexpr_baton *symbaton;
   struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
+
   framefunc = get_frame_function (debaton->frame);
-  symbaton = SYMBOL_LOCATION_BATON (framefunc);
-  *start = symbaton->data;
-  *length = symbaton->size;
+
+  if (SYMBOL_LOCATION_FUNCS (framefunc) == &dwarf2_loclist_funcs)
+    {
+      struct dwarf2_loclist_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *start = find_location_expression (symbaton, length,
+                                        get_frame_pc (debaton->frame));
+    }
+  else
+    {
+      struct dwarf2_locexpr_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *length = symbaton->size;
+      *start = symbaton->data;
+    }
+
+  if (*start == NULL)
+    error ("Could not find the frame base for \"%s\".",
+          SYMBOL_NATURAL_NAME (framefunc));
 }
 
 /* Using the objfile specified in BATON, find the address for the
@@ -130,6 +202,13 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
   struct dwarf_expr_baton baton;
   struct dwarf_expr_context *ctx;
 
+  if (size == 0)
+    {
+      retval = allocate_value (SYMBOL_TYPE (var));
+      VALUE_LVAL (retval) = not_lval;
+      VALUE_OPTIMIZED_OUT (retval) = 1;
+    }
+
   baton.frame = frame;
   baton.objfile = objfile;
 
@@ -241,8 +320,55 @@ dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size)
   return baton.needs_frame;
 }
 
+static void
+dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+                          struct axs_value * value, unsigned char *data,
+                          int size)
+{
+  if (size == 0)
+    error ("Symbol \"%s\" has been optimized out.",
+          SYMBOL_PRINT_NAME (symbol));
+
+  if (size == 1
+      && data[0] >= DW_OP_reg0
+      && data[0] <= DW_OP_reg31)
+    {
+      value->kind = axs_lvalue_register;
+      value->u.reg = data[0] - DW_OP_reg0;
+    }
+  else if (data[0] == DW_OP_regx)
+    {
+      ULONGEST reg;
+      read_uleb128 (data + 1, data + size, &reg);
+      value->kind = axs_lvalue_register;
+      value->u.reg = reg;
+    }
+  else if (data[0] == DW_OP_fbreg)
+    {
+      /* And this is worse than just minimal; we should honor the frame base
+        as above.  */
+      int frame_reg;
+      LONGEST frame_offset;
+      unsigned char *buf_end;
+
+      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
+      if (buf_end != data + size)
+       error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
+              SYMBOL_PRINT_NAME (symbol));
 
+      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+      ax_reg (ax, frame_reg);
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
 
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
+      value->kind = axs_lvalue_memory;
+    }
+  else
+    error ("Unsupported DWARF opcode in the location of \"%s\".",
+          SYMBOL_PRINT_NAME (symbol));
+}
 \f
 /* Return the value of SYMBOL in FRAME using the DWARF-2 expression
    evaluator to calculate the location.  */
@@ -296,57 +422,13 @@ locexpr_describe_location (struct symbol *symbol, struct ui_file *stream)
    publicly available stub with tracepoint support for me to test
    against.  When there is one this function should be revisited.  */
 
-void
+static void
 locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
                            struct axs_value * value)
 {
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
 
-  if (dlbaton->size == 0)
-    error ("Symbol \"%s\" has been optimized out.",
-          SYMBOL_PRINT_NAME (symbol));
-
-  if (dlbaton->size == 1
-      && dlbaton->data[0] >= DW_OP_reg0
-      && dlbaton->data[0] <= DW_OP_reg31)
-    {
-      value->kind = axs_lvalue_register;
-      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
-    }
-  else if (dlbaton->data[0] == DW_OP_regx)
-    {
-      ULONGEST reg;
-      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-                   &reg);
-      value->kind = axs_lvalue_register;
-      value->u.reg = reg;
-    }
-  else if (dlbaton->data[0] == DW_OP_fbreg)
-    {
-      /* And this is worse than just minimal; we should honor the frame base
-        as above.  */
-      int frame_reg;
-      LONGEST frame_offset;
-      unsigned char *buf_end;
-
-      buf_end = read_sleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-                             &frame_offset);
-      if (buf_end != dlbaton->data + dlbaton->size)
-       error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
-              SYMBOL_PRINT_NAME (symbol));
-
-      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
-      ax_reg (ax, frame_reg);
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-      value->kind = axs_lvalue_memory;
-    }
-  else
-    error ("Unsupported DWARF opcode in the location of \"%s\".",
-          SYMBOL_PRINT_NAME (symbol));
+  dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size);
 }
 
 /* The set of location functions used with the DWARF-2 expression
@@ -357,3 +439,75 @@ struct location_funcs dwarf2_locexpr_funcs = {
   locexpr_describe_location,
   locexpr_tracepoint_var_ref
 };
+
+
+/* Wrapper functions for location lists.  These generally find
+   the appropriate location expression and call something above.  */
+
+/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
+   evaluator to calculate the location.  */
+static struct value *
+loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  struct value *val;
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size,
+                                  frame ? get_frame_pc (frame) : 0);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
+
+  return val;
+}
+
+/* Return non-zero iff we need a frame to evaluate SYMBOL.  */
+static int
+loclist_read_needs_frame (struct symbol *symbol)
+{
+  /* If there's a location list, then assume we need to have a frame
+     to choose the appropriate location expression.  With tracking of
+     global variables this is not necessarily true, but such tracking
+     is disabled in GCC at the moment until we figure out how to
+     represent it.  */
+
+  return 1;
+}
+
+/* Print a natural-language description of SYMBOL to STREAM.  */
+static int
+loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+  /* FIXME: Could print the entire list of locations.  */
+  fprintf_filtered (stream, "a variable with multiple locations");
+  return 1;
+}
+
+/* Describe the location of SYMBOL as an agent value in VALUE, generating
+   any necessary bytecode in AX.  */
+static void
+loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+                           struct axs_value * value)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size, ax->scope);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  dwarf2_tracepoint_var_ref (symbol, ax, value, data, size);
+}
+
+/* The set of location functions used with the DWARF-2 expression
+   evaluator and location lists.  */
+struct location_funcs dwarf2_loclist_funcs = {
+  loclist_read_variable,
+  loclist_read_needs_frame,
+  loclist_describe_location,
+  loclist_tracepoint_var_ref
+};
index fde132922ac4a5fb94fd63fb0c229ed955c28389..b6b4d3325e1a9cc53fd2033bb51c0f565b954e74 100644 (file)
 /* This header is private to the DWARF-2 reader.  It is shared between
    dwarf2read.c and dwarf2loc.c.  */
 
-/* The symbol location baton type used by the DWARF-2 reader (i.e.
-   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  */
+/* The symbol location baton types used by the DWARF-2 reader (i.e.
+   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
+   dwarf2_locexpr_baton" is for a symbol with a single location
+   expression; "struct dwarf2_loclist_baton" is for a symbol with a
+   location list.  */
 
 struct dwarf2_locexpr_baton
 {
+  /* Pointer to the start of the location expression.  */
   unsigned char *data;
+
+  /* Length of the location expression.  */
   unsigned short size;
+
+  /* The objfile containing the symbol whose location we're computing.  */
+  struct objfile *objfile;
+};
+
+struct dwarf2_loclist_baton
+{
+  /* The initial base address for the location list, based on the compilation
+     unit.  */
+  CORE_ADDR base_address;
+
+  /* Pointer to the start of the location list.  */
+  unsigned char *data;
+
+  /* Length of the location list.  */
+  unsigned short size;
+
+  /* The objfile containing the symbol whose location we're computing.  */
   struct objfile *objfile;
 };
 
 extern struct location_funcs dwarf2_locexpr_funcs;
+extern struct location_funcs dwarf2_loclist_funcs;
 
 #endif
index c77642d239a1a126e3e60ac3e5a657848b66442e..b5fd38982f3e670dadf074f450f23a529625fa90 100644 (file)
@@ -220,9 +220,13 @@ struct comp_unit_head
 
     struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
 
-    /* Pointer to the DIE associated with the compilation unit.  */
+    /* Base address of this compilation unit.  */
 
-    struct die_info *die;
+    CORE_ADDR base_address;
+
+    /* Non-zero if base_address has been set.  */
+
+    int base_known;
   };
 
 /* The line number information for a compilation unit (found in the
@@ -395,6 +399,7 @@ static char *dwarf_line_buffer;
 static char *dwarf_str_buffer;
 static char *dwarf_macinfo_buffer;
 static char *dwarf_ranges_buffer;
+static char *dwarf_loc_buffer;
 
 /* A zeroed version of a partial die for initialization purposes.  */
 static struct partial_die_info zeroed_partial_die;
@@ -511,6 +516,13 @@ struct dwarf2_pinfo
 
     unsigned int dwarf_ranges_size;
 
+    /* Pointer to start of dwarf locations buffer for the objfile.  */
+
+    char *dwarf_loc_buffer;
+
+    /* Size of dwarf locations buffer for the objfile.  */
+
+    unsigned int dwarf_loc_size;
   };
 
 #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
@@ -526,6 +538,8 @@ struct dwarf2_pinfo
 #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
 #define DWARF_RANGES_BUFFER(p)  (PST_PRIVATE(p)->dwarf_ranges_buffer)
 #define DWARF_RANGES_SIZE(p)    (PST_PRIVATE(p)->dwarf_ranges_size)
+#define DWARF_LOC_BUFFER(p)     (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p)       (PST_PRIVATE(p)->dwarf_loc_size)
 
 /* Maintain an array of referenced fundamental types for the current
    compilation unit being read.  For DWARF version 1, we have to construct
@@ -926,6 +940,7 @@ dwarf2_has_info (bfd *abfd)
   dwarf_frame_offset = 0;
   dwarf_eh_frame_offset = 0;
   dwarf_ranges_offset = 0;
+  dwarf_loc_offset = 0;
   
   bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
   if (dwarf_info_offset && dwarf_abbrev_offset)
@@ -1062,6 +1077,14 @@ dwarf2_build_psymtabs (struct objfile *objfile, int mainline)
   else
     dwarf_ranges_buffer = NULL;
 
+  if (dwarf_loc_offset)
+    dwarf_loc_buffer = dwarf2_read_section (objfile,
+                                           dwarf_loc_offset,
+                                           dwarf_loc_size,
+                                           dwarf_loc_section);
+  else
+    dwarf_loc_buffer = NULL;
+
   if (mainline
       || (objfile->global_psymbols.size == 0
          && objfile->static_psymbols.size == 0))
@@ -1283,6 +1306,8 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
       DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
       DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
       DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
+      DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+      DWARF_LOC_SIZE (pst) = dwarf_loc_size;
       baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
       /* Store the function that reads in the rest of the symbol table */
@@ -1607,6 +1632,7 @@ psymtab_to_symtab_1 (struct partial_symtab *pst)
   char *info_ptr;
   struct symtab *symtab;
   struct cleanup *back_to;
+  struct attribute *attr;
 
   /* Set local variables from the partial symbol table info.  */
   offset = DWARF_INFO_OFFSET (pst);
@@ -1621,6 +1647,8 @@ psymtab_to_symtab_1 (struct partial_symtab *pst)
   dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
   dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
   dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
+  dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+  dwarf_loc_size = DWARF_LOC_SIZE (pst);
   baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
   cu_header_offset = offset;
   info_ptr = dwarf_info_buffer + offset;
@@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symtab *pst)
 
   make_cleanup_free_die_list (dies);
 
+  /* Find the base address of the compilation unit for range lists and
+     location lists.  It will normally be specified by DW_AT_low_pc.
+     In DWARF-3 draft 4, the base address could be overridden by
+     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
+     compilation units with discontinuous ranges.  */
+
+  cu_header.base_known = 0;
+  cu_header.base_address = 0;
+
+  attr = dwarf_attr (dies, DW_AT_entry_pc);
+  if (attr)
+    {
+      cu_header.base_address = DW_ADDR (attr);
+      cu_header.base_known = 1;
+    }
+  else
+    {
+      attr = dwarf_attr (dies, DW_AT_low_pc);
+      if (attr)
+       {
+         cu_header.base_address = DW_ADDR (attr);
+         cu_header.base_known = 1;
+       }
+    }
+
   /* Do line number decoding in read_file_scope () */
-  cu_header.die = dies;
   process_die (dies, objfile, &cu_header);
 
   if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
@@ -2122,40 +2174,18 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
             .debug_renges section.  */
          unsigned int offset = DW_UNSND (attr);
          /* Base address selection entry.  */
-         CORE_ADDR base = 0;
-         int found_base = 0;
+         CORE_ADDR base;
+         int found_base;
          int dummy;
          unsigned int i;
          char *buffer;
          CORE_ADDR marker;
          int low_set;
  
-         /* The applicable base address is determined by (1) the closest
-            preceding base address selection entry in the range list or
-            (2) the DW_AT_low_pc of the compilation unit.  */
-
-         /* ??? Was in dwarf3 draft4, and has since been removed.
-            GCC still uses it though.  */
-         attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
-         if (attr)
-           {
-             base = DW_ADDR (attr);
-             found_base = 1;
-           }
-
-         if (!found_base)
-           {
-             attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
-             if (attr)
-               {
-                 base = DW_ADDR (attr);
-                 found_base = 1;
-               }
-           }
-
+         found_base = cu_header->base_known;
+         base = cu_header->base_address;
          buffer = dwarf_ranges_buffer + offset;
 
-
          /* Read in the largest possible address.  */
          marker = read_address (obfd, buffer, cu_header, &dummy);
          if ((marker & mask) == mask)
@@ -7328,26 +7358,53 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
                             const struct comp_unit_head *cu_header,
                             struct objfile *objfile)
 {
-  struct dwarf2_locexpr_baton *baton;
-
-  /* When support for location lists is added, this will go away.  */
-  if (!attr_form_is_block (attr))
+  if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
     {
-      dwarf2_complex_location_expr_complaint ();
-      return;
-    }
+      struct dwarf2_loclist_baton *baton;
 
-  baton = obstack_alloc (&objfile->symbol_obstack,
-                        sizeof (struct dwarf2_locexpr_baton));
-  baton->objfile = objfile;
+      baton = obstack_alloc (&objfile->symbol_obstack,
+                            sizeof (struct dwarf2_loclist_baton));
+      baton->objfile = objfile;
 
-  /* Note that we're just copying the block's data pointer here, not
-     the actual data.  We're still pointing into the dwarf_info_buffer
-     for SYM's objfile; right now we never release that buffer, but
-     when we do clean up properly this may need to change.  */
-  baton->size = DW_BLOCK (attr)->size;
-  baton->data = DW_BLOCK (attr)->data;
+      /* We don't know how long the location list is, but make sure we
+        don't run off the edge of the section.  */
+      baton->size = dwarf_loc_size - DW_UNSND (attr);
+      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
+      baton->base_address = cu_header->base_address;
+      if (cu_header->base_known == 0)
+       complaint (&symfile_complaints,
+                  "Location list used without specifying the CU base address.");
 
-  SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
-  SYMBOL_LOCATION_BATON (sym) = baton;
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_loclist_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
+    }
+  else
+    {
+      struct dwarf2_locexpr_baton *baton;
+
+      baton = obstack_alloc (&objfile->symbol_obstack,
+                            sizeof (struct dwarf2_locexpr_baton));
+      baton->objfile = objfile;
+
+      if (attr_form_is_block (attr))
+       {
+         /* Note that we're just copying the block's data pointer
+            here, not the actual data.  We're still pointing into the
+            dwarf_info_buffer for SYM's objfile; right now we never
+            release that buffer, but when we do clean up properly
+            this may need to change.  */
+         baton->size = DW_BLOCK (attr)->size;
+         baton->data = DW_BLOCK (attr)->data;
+       }
+      else
+       {
+         dwarf2_invalid_attrib_class_complaint ("location description",
+                                                SYMBOL_NATURAL_NAME (sym));
+         baton->size = 0;
+         baton->data = NULL;
+       }
+      
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
+    }
 }