From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30471 invoked by alias); 19 Jun 2002 13:48:07 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 30369 invoked from network); 19 Jun 2002 13:47:59 -0000 Received: from unknown (HELO cygnus.com) (205.180.83.203) by sources.redhat.com with SMTP; 19 Jun 2002 13:47:59 -0000 Received: from localhost.redhat.com (remus.sfbay.redhat.com [172.16.27.252]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id GAA17661 for ; Wed, 19 Jun 2002 06:47:58 -0700 (PDT) Received: by localhost.redhat.com (Postfix, from userid 469) id 1F4E5107D4; Wed, 19 Jun 2002 09:47:16 -0400 (EDT) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <15632.35683.995382.743112@localhost.redhat.com> Date: Wed, 19 Jun 2002 06:48:00 -0000 To: gdb-patches@sources.redhat.com, Michal Ludvig Subject: Re: [RFA] dwarf2cfi.c improvements In-Reply-To: <3D08EB06.9030200@suse.cz> References: <3CF79DA0.9040404@suse.cz> <3CFB727E.10005@cygnus.com> <3CFCA5ED.7010201@suse.cz> <15621.27804.562409.937859@localhost.redhat.com> <3D06171B.3040709@suse.cz> <15622.25798.905178.867470@localhost.redhat.com> <3D08EB06.9030200@suse.cz> X-SW-Source: 2002-06/txt/msg00362.txt.bz2 Michal Ludvig writes: > Elena Zannoni wrote: > > > Could you send me a unified diff? (don't need to send it to the list > > just to me). I'd appreciate that. > > Yes. Included. It's against cvs rev 1.9. > Since the diff had substantial changes from the previous one, I am copying it to the list as well. Elena > Index: dwarf2cfi.c > =================================================================== > RCS file: /cvs/src/src/gdb/dwarf2cfi.c,v > retrieving revision 1.9 > diff -u -r1.9 dwarf2cfi.c > --- dwarf2cfi.c 11 Jun 2002 08:45:05 -0000 1.9 > +++ dwarf2cfi.c 13 Jun 2002 18:27:18 -0000 > @@ -34,7 +34,7 @@ > Frame Descriptors. */ > struct cie_unit > { > - /* Offset of this unit in dwarf_frame_buffer. */ > + /* Offset of this unit in .debug_frame or .eh_frame. */ > ULONGEST offset; > > /* A null-terminated string that identifies the augmentation to this CIE or > @@ -176,6 +176,14 @@ > struct objfile *objfile; > }; > > +enum ptr_encoding { > + PE_absptr = DW_EH_PE_absptr, > + PE_pcrel = DW_EH_PE_pcrel, > + PE_textrel = DW_EH_PE_textrel, > + PE_datarel = DW_EH_PE_datarel, > + PE_funcrel = DW_EH_PE_funcrel > +}; > + > #define UNWIND_CONTEXT(fi) ((struct context *) (fi->context)) > > > @@ -188,8 +196,6 @@ > extern unsigned int dwarf_frame_size; > extern file_ptr dwarf_eh_frame_offset; > extern unsigned int dwarf_eh_frame_size; > - > -static char *dwarf_frame_buffer; > > > extern char *dwarf2_read_section (struct objfile *objfile, file_ptr offset, > @@ -219,6 +225,7 @@ > static CORE_ADDR read_pointer (bfd * abfd, char **p); > static CORE_ADDR read_encoded_pointer (bfd * abfd, char **p, > unsigned char encoding); > +static enum ptr_encoding pointer_encoding (unsigned char encoding); > > static LONGEST read_initial_length (bfd * abfd, char *buf, int *bytes_read); > static ULONGEST read_length (bfd * abfd, char *buf, int *bytes_read, > @@ -494,6 +501,9 @@ > } > } > > +/* This functions only reads appropriate amount of data from *p > + * and returns the resulting value. Calling function must handle > + * different encoding possibilities itself! */ > static CORE_ADDR > read_encoded_pointer (bfd * abfd, char **p, unsigned char encoding) > { > @@ -537,22 +547,30 @@ > "read_encoded_pointer: unknown pointer encoding"); > } > > - if (ret != 0) > - switch (encoding & 0xf0) > - { > - case DW_EH_PE_absptr: > - break; > - case DW_EH_PE_pcrel: > - ret += (CORE_ADDR) * p; > - break; > - case DW_EH_PE_textrel: > - case DW_EH_PE_datarel: > - case DW_EH_PE_funcrel: > - default: > - internal_error (__FILE__, __LINE__, > - "read_encoded_pointer: unknown pointer encoding"); > - } > + return ret; > +} > + > +enum ptr_encoding > +pointer_encoding (unsigned char encoding) > +{ > + int ret; > > + if (encoding & DW_EH_PE_indirect) > + warning ("CFI: Unsupported pointer encoding: DW_EH_PE_indirect"); > + > + switch (encoding & 0x70) > + { > + case DW_EH_PE_absptr: > + case DW_EH_PE_pcrel: > + case DW_EH_PE_textrel: > + case DW_EH_PE_datarel: > + case DW_EH_PE_funcrel: > + ret = encoding & 0x70; > + break; > + default: > + internal_error (__FILE__, __LINE__, > + "read_encoded_pointer: unknown pointer encoding"); > + } > return ret; > } > > @@ -627,6 +645,10 @@ > case DW_CFA_set_loc: > fs->pc = read_encoded_pointer (objfile->obfd, &insn_ptr, > fs->addr_encoding); > + > + if (pointer_encoding (fs->addr_encoding) != PE_absptr) > + warning ("CFI: DW_CFA_set_loc uses relative addressing"); > + > break; > > case DW_CFA_advance_loc1: > @@ -1381,38 +1403,31 @@ > > /* Build the cie_chunks and fde_chunks tables from informations > in .debug_frame section. */ > -void > -dwarf2_build_frame_info (struct objfile *objfile) > +static void > +parse_frame_info (struct objfile *objfile, file_ptr frame_offset, > + unsigned int frame_size, int eh_frame) > { > bfd *abfd = objfile->obfd; > + asection *curr_section_ptr; > char *start = NULL; > char *end = NULL; > - int from_eh = 0; > + char *frame_buffer = NULL; > + char *curr_section_name, *aug_data; > + struct cie_unit *last_cie = NULL; > + int last_dup_fde = 0, aug_len, i; > + CORE_ADDR curr_section_vma = 0; > > unwind_tmp_obstack_init (); > > - dwarf_frame_buffer = 0; > - > - if (dwarf_frame_offset) > - { > - dwarf_frame_buffer = dwarf2_read_section (objfile, > - dwarf_frame_offset, > - dwarf_frame_size); > - > - start = dwarf_frame_buffer; > - end = dwarf_frame_buffer + dwarf_frame_size; > - } > - else if (dwarf_eh_frame_offset) > - { > - dwarf_frame_buffer = dwarf2_read_section (objfile, > - dwarf_eh_frame_offset, > - dwarf_eh_frame_size); > + frame_buffer = dwarf2_read_section (objfile, frame_offset, frame_size); > > - start = dwarf_frame_buffer; > - end = dwarf_frame_buffer + dwarf_eh_frame_size; > + start = frame_buffer; > + end = frame_buffer + frame_size; > > - from_eh = 1; > - } > + curr_section_name = eh_frame ? ".eh_frame" : ".debug_frame"; > + curr_section_ptr = bfd_get_section_by_name (abfd, curr_section_name); > + if (curr_section_ptr) > + curr_section_vma = curr_section_ptr->vma; > > if (start) > { > @@ -1420,9 +1435,8 @@ > { > unsigned long length; > ULONGEST cie_id; > - ULONGEST unit_offset = start - dwarf_frame_buffer; > - int bytes_read; > - int dwarf64; > + ULONGEST unit_offset = start - frame_buffer; > + int bytes_read, dwarf64, flag_pcrel; > char *block_end; > > length = read_initial_length (abfd, start, &bytes_read); > @@ -1430,10 +1444,16 @@ > dwarf64 = (bytes_read == 12); > block_end = start + length; > > + if (length == 0) > + { > + start = block_end; > + continue; > + } > + > cie_id = read_length (abfd, start, &bytes_read, dwarf64); > start += bytes_read; > > - if ((from_eh && cie_id == 0) || is_cie (cie_id, dwarf64)) > + if ((eh_frame && cie_id == 0) || is_cie (cie_id, dwarf64)) > { > struct cie_unit *cie = cie_unit_alloc (); > char *aug; > @@ -1449,87 +1469,185 @@ > start++; /* version */ > > cie->augmentation = aug = start; > - while (*start) > - start++; > - start++; /* skip past NUL */ > + while (*start++); /* Skips last NULL as well */ > > cie->code_align = read_uleb128 (abfd, &start); > cie->data_align = read_sleb128 (abfd, &start); > cie->ra = read_1u (abfd, &start); > > + /* Augmentation: > + z Indicates that a uleb128 is present to size the > + augmentation section. > + L Indicates the encoding (and thus presence) of > + an LSDA pointer in the FDE augmentation. > + R Indicates a non-default pointer encoding for > + FDE code pointers. > + P Indicates the presence of an encoding + language > + personality routine in the CIE augmentation. > + > + [This info comes from GCC's dwarf2out.c] > + */ > if (*aug == 'z') > { > - int xtra = read_uleb128 (abfd, &start); > - start += xtra; > + aug_len = read_uleb128 (abfd, &start); > + aug_data = start; > + start += aug_len; > ++aug; > } > > + cie->data = start; > + cie->data_length = block_end - cie->data; > + > while (*aug != '\0') > { > if (aug[0] == 'e' && aug[1] == 'h') > { > - start += sizeof (void *); > - aug += 2; > + aug_data += sizeof (void *); > + aug++; > } > else if (aug[0] == 'R') > + cie->addr_encoding = *aug_data++; > + else if (aug[0] == 'P') > { > - cie->addr_encoding = *start++; > - aug += 1; > + CORE_ADDR pers_addr; > + int pers_addr_enc; > + > + pers_addr_enc = *aug_data++; > + /* We don't need pers_addr value and so we > + don't care about it's encoding. */ > + pers_addr = read_encoded_pointer (abfd, &aug_data, > + pers_addr_enc); > } > - else if (aug[0] == 'P') > + else if (aug[0] == 'L' && eh_frame) > { > - CORE_ADDR ptr; > - ptr = read_encoded_pointer (abfd, &start, > - cie->addr_encoding); > - aug += 1; > + int lsda_addr_enc; > + > + /* Perhaps we should save this to CIE for later use? > + Do we need it for something in GDB? */ > + lsda_addr_enc = *aug_data++; > } > else > - warning ("%s(): unknown augmentation", __func__); > + warning ("CFI warning: unknown augmentation \"%c\"" > + " in \"%s\" of\n" > + "\t%s", aug[0], curr_section_name, > + objfile->name); > + aug++; > } > > - cie->data = start; > - cie->data_length = block_end - start; > + last_cie = cie; > } > else > { > struct fde_unit *fde; > struct cie_unit *cie; > + int dup = 0; > + CORE_ADDR init_loc; > > - fde_chunks_need_space (); > - fde = fde_unit_alloc (); > + /* We assume that debug_frame is in order > + CIE,FDE,CIE,FDE,FDE,... and thus the CIE for this FDE > + should be stored in last_cie pointer. If not, we'll > + try to find it by the older way. */ > + if (last_cie) > + cie = last_cie; > + else > + { > + warning ("CFI: last_cie == NULL. " > + "Perhaps a malformed %s section in '%s'...?\n", > + curr_section_name, objfile->name); > + > + cie = cie_chunks; > + while (cie) > + { > + if (cie->objfile == objfile) > + { > + if (eh_frame && > + (cie->offset == > + (unit_offset + bytes_read - cie_id))) > + break; > + if (!eh_frame && (cie->offset == cie_id)) > + break; > + } > > - fde_chunks.array[fde_chunks.elems++] = fde; > + cie = cie->next; > + } > + if (!cie) > + error ("CFI: can't find CIE pointer"); > + } > > - fde->initial_location = read_pointer (abfd, &start) > - + ANOFFSET (objfile->section_offsets, > - SECT_OFF_TEXT (objfile)); > - fde->address_range = read_pointer (abfd, &start); > + init_loc = read_encoded_pointer (abfd, &start, > + cie->addr_encoding); > > - cie = cie_chunks; > - while (cie) > - { > - if (cie->objfile == objfile) > - { > - if (from_eh > - && (cie->offset == > - (unit_offset + bytes_read - cie_id))) > + switch (pointer_encoding (cie->addr_encoding)) > + { > + case PE_absptr: > break; > - if (!from_eh && (cie->offset == cie_id)) > + case PE_pcrel: > + /* start-frame_buffer gives offset from > + the beginning of actual section. */ > + init_loc += curr_section_vma + start - frame_buffer; > break; > - } > + default: > + warning ("CFI: Unsupported pointer encoding\n"); > + } > > - cie = cie->next; > + /* For relocatable objects we must add an offset telling > + where the section is actually mapped in the memory. */ > + init_loc += ANOFFSET (objfile->section_offsets, > + SECT_OFF_TEXT (objfile)); > + > + /* If we have both .debug_frame and .eh_frame present in > + a file, we must eliminate duplicate FDEs. For now we'll > + run through all entries in fde_chunks and check it one > + by one. Perhaps in the future we can implement a faster > + searching algorithm. */ > + /* eh_frame==2 indicates, that this file has an already > + parsed .debug_frame too. When eh_frame==1 it means, that no > + .debug_frame is present and thus we don't need to check for > + duplicities. eh_frame==0 means, that we parse .debug_frame > + and don't need to care about duplicate FDEs, because > + .debug_frame is parsed first. */ > + for (i = 0; eh_frame == 2 && i < fde_chunks.elems; i++) > + { > + /* We assume that FDEs in .debug_frame and .eh_frame > + have the same order (if they are present, of course). > + If we find a duplicate entry for one FDE and save > + it's index to last_dup_fde it's very likely, that > + we'll find an entry for the following FDE right after > + the previous one. Thus in many cases we'll run this > + loop only once. */ > + last_dup_fde = (last_dup_fde + i) % fde_chunks.elems; > + if (fde_chunks.array[last_dup_fde]->initial_location > + == init_loc) > + { > + dup = 1; > + break; > + } > } > > - if (!cie) > - error ("%s(): can't find CIE pointer", __func__); > - fde->cie_ptr = cie; > + /* Allocate a new entry only if this FDE isn't a duplicate of > + something we have already seen. */ > + if (!dup) > + { > + fde_chunks_need_space (); > + fde = fde_unit_alloc (); > + > + fde_chunks.array[fde_chunks.elems++] = fde; > + > + fde->initial_location = init_loc; > + fde->address_range = read_encoded_pointer (abfd, &start, > + cie-> > + addr_encoding); > + > + fde->cie_ptr = cie; > > - if (cie->augmentation[0] == 'z') > - read_uleb128 (abfd, &start); > + /* Here we intentionally ignore augmentation data > + from FDE, because we don't need them. */ > + if (cie->augmentation[0] == 'z') > + start += read_uleb128 (abfd, &start); > > - fde->data = start; > - fde->data_length = block_end - start; > + fde->data = start; > + fde->data_length = block_end - start; > + } > } > start = block_end; > } > @@ -1537,7 +1655,30 @@ > sizeof (struct fde_unit *), compare_fde_unit); > } > } > - > + > +/* We must parse both .debug_frame section and .eh_frame because > + not all frames must be present in both of these sections. */ > +void > +dwarf2_build_frame_info (struct objfile *objfile) > +{ > + int after_debug_frame=0; > + > + /* If we have .debug_frame then the parser is called with > + eh_frame==0 for .debug_frame and eh_frame==2 for .eh_frame, > + otherwise it's only called once for .eh_frame with argument > + eh_frame==1 */ > + > + if (dwarf_frame_offset) > + { > + parse_frame_info (objfile, dwarf_frame_offset, > + dwarf_frame_size, 0 /* = debug_frame */); > + after_debug_frame = 1; > + } > + > + if (dwarf_eh_frame_offset) > + parse_frame_info (objfile, dwarf_eh_frame_offset, dwarf_eh_frame_size, > + 1 /* = eh_frame */ + after_debug_frame); > +} > > /* Return the frame address. */ > CORE_ADDR