+ {
+ attr = dwarf_attr (die, DW_AT_ranges);
+ if (attr != NULL)
+ {
+ unsigned int addr_size = cu_header->addr_size;
+ CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+ /* Value of the DW_AT_ranges attribute is the offset in the
+ .debug_renges section. */
+ unsigned int offset = DW_UNSND (attr);
+ /* Base address selection entry. */
+ CORE_ADDR base = 0;
+ int found_base = 0;
+ 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;
+ }
+ }
+
+ buffer = dwarf_ranges_buffer + offset;
+
+
+ /* Read in the largest possible address. */
+ marker = read_address (obfd, buffer, cu_header, &dummy);
+ if ((marker & mask) == mask)
+ {
+ /* If we found the largest possible address, then
+ read the base address. */
+ base = read_address (obfd, buffer + addr_size,
+ cu_header, &dummy);
+ buffer += 2 * addr_size;
+ offset += 2 * addr_size;
+ found_base = 1;
+ }
+
+ low_set = 0;
+
+ while (1)
+ {
+ CORE_ADDR range_beginning, range_end;
+
+ range_beginning = read_address (obfd, buffer,
+ cu_header, &dummy);
+ buffer += addr_size;
+ range_end = read_address (obfd, buffer, cu_header, &dummy);
+ buffer += addr_size;
+ offset += 2 * addr_size;
+
+ /* An end of list marker is a pair of zero addresses. */
+ if (range_beginning == 0 && range_end == 0)
+ /* Found the end of list entry. */
+ break;
+
+ /* Each base address selection entry is a pair of 2 values.
+ The first is the largest possible address, the second is
+ the base address. Check for a base address here. */
+ if ((range_beginning & mask) == mask)
+ {
+ /* If we found the largest possible address, then
+ read the base address. */
+ base = read_address (obfd, buffer + addr_size,
+ cu_header, &dummy);
+ found_base = 1;
+ continue;
+ }
+
+ if (!found_base)
+ {
+ /* We have no valid base address for the ranges
+ data. */
+ complaint (&symfile_complaints,
+ "Invalid .debug_ranges data (no base address)");
+ return 0;
+ }
+
+ /* FIXME: This is recording everything as a low-high
+ segment of consecutive addresses. We should have a
+ data structure for discontiguous block ranges
+ instead. */
+ if (! low_set)
+ {
+ low = range_beginning;
+ high = range_end;
+ low_set = 1;
+ }
+ else
+ {
+ if (range_beginning < low)
+ low = range_beginning;
+ if (range_end > high)
+ high = range_end;
+ }
+ }
+
+ if (! low_set)
+ /* If the first entry is an end-of-list marker, the range
+ describes an empty scope, i.e. no instructions. */
+ return 0;
+
+ ret = -1;
+ }
+ }