]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
2005-09-09 Roland McGrath <roland@redhat.com>
authorRoland McGrath <roland@redhat.com>
Sun, 11 Sep 2005 08:49:19 +0000 (08:49 +0000)
committerRoland McGrath <roland@redhat.com>
Sun, 11 Sep 2005 08:49:19 +0000 (08:49 +0000)
* elf_update.c (write_file): Stat the file and fchmod it after update
if its mode had S_ISUID or S_ISGID bits set.

libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf_entry_breakpoints.c [new file with mode: 0644]
libdw/dwarf_entrypc.c [new file with mode: 0644]
libdw/libdw.h
libdw/libdwP.h
libelf/ChangeLog
libelf/elf_update.c

index db069c94a0350911a9a4552126ac444d1af23ece..006da6d6ec97bb633c01f872b7ea42930b822b0a 100644 (file)
@@ -1,3 +1,14 @@
+2005-09-07  Roland McGrath  <roland@redhat.com>
+
+       * dwarf_entry_breakpoints.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add it.
+       * libdw.h: Declare dwarf_entry_breakpoints.
+
+       * dwarf_entrypc.c: New file.
+       * Makefile.am (libdw_a_SOURCES): Add it.
+       * libdw.h: Declare dwarf_entrypc.
+       * libdwP.h: Add INTDECL.
+
 2005-08-28  Ulrich Drepper  <drepper@redhat.com>
 
        * Makefile.am: Use $(LINK) not $(CC) when creating DSO.
index a35f5dcc1750c2ffbba5c6c8237987ef410d0fd0..4121b0f7e0c2209e8046e45bdf11b973b65e4eb4 100644 (file)
@@ -42,7 +42,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_attr_integrate.c dwarf_hasattr_integrate.c \
                  dwarf_child.c dwarf_haschildren.c dwarf_formaddr.c \
                  dwarf_formudata.c dwarf_formsdata.c dwarf_lowpc.c \
-                 dwarf_haspc.c dwarf_highpc.c \
+                 dwarf_entrypc.c dwarf_haspc.c dwarf_highpc.c \
                  dwarf_formref.c dwarf_formref_die.c dwarf_siblingof.c \
                  dwarf_dieoffset.c dwarf_cuoffset.c dwarf_hasattr.c \
                  dwarf_hasform.c dwarf_whatform.c dwarf_whatattr.c \
@@ -68,8 +68,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_func_line.c dwarf_func_col.c dwarf_func_die.c \
                  dwarf_func_inline.c dwarf_getsrc_file.c \
                  libdw_findcu.c libdw_form.c libdw_alloc.c memory-access.c \
-                 libdw_visit_scopes.c
-
+                 libdw_visit_scopes.c \
+                 dwarf_entry_breakpoints.c
 
 if !MUDFLAP
 libdw_pic_a_SOURCES =
diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c
new file mode 100644 (file)
index 0000000..a8fb294
--- /dev/null
@@ -0,0 +1,200 @@
+/* Find entry breakpoint locations for a function.
+   Copyright (C) 2005 Red Hat, Inc.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libdwP.h"
+#include <dwarf.h>
+#include <stdlib.h>
+
+
+int
+dwarf_entry_breakpoints (die, bkpts)
+     Dwarf_Die *die;
+     Dwarf_Addr **bkpts;
+{
+  int nbkpts = 0;
+  *bkpts = NULL;
+
+  /* Add one breakpoint location to the result vector.  */
+  inline int add_bkpt (Dwarf_Addr pc)
+    {
+      Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]);
+      if (newlist == NULL)
+       {
+         free (*bkpts);
+         *bkpts = NULL;
+         __libdw_seterrno (DWARF_E_NOMEM);
+         return -1;
+       }
+      newlist[nbkpts - 1] = pc;
+      *bkpts = newlist;
+      return nbkpts;
+    }
+
+  /* Fallback result, break at the entrypc/lowpc value.  */
+  inline int entrypc_bkpt (void)
+    {
+      Dwarf_Addr pc;
+      return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc);
+    }
+
+  /* Fetch the CU's line records to look for this DIE's addresses.  */
+  Dwarf_Die cudie =
+    {
+      .cu = die->cu,
+      .addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+              + die->cu->start + 3 * die->cu->offset_size - 4 + 3),
+    };
+  Dwarf_Lines *lines;
+  size_t nlines;
+  if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
+    {
+      int error = INTUSE (dwarf_errno) ();
+      if (error == DWARF_E_NO_DEBUG_LINE)
+       return entrypc_bkpt ();
+      __libdw_seterrno (error);
+      return -1;
+    }
+
+  /* Search a contiguous PC range for prologue-end markers.
+     If DWARF, look for proper markers.
+     Failing that, if ADHOC, look for the ad hoc convention.  */
+  inline int search_range (Dwarf_Addr low, Dwarf_Addr high,
+                          bool dwarf, bool adhoc)
+    {
+      size_t l = 0, u = nlines;
+      while (l < u)
+       {
+         size_t idx = (l + u) / 2;
+         if (low < lines->info[idx].addr)
+           u = idx;
+         else
+           {
+             l = idx;
+             if (low > lines->info[idx].addr)
+               {
+                 if (lines->info[idx].addr < high)
+                   break;
+                 ++l;
+               }
+             else
+               break;
+           }
+       }
+      if (l < u)
+       {
+         if (dwarf)
+           while (l < u && lines->info[l].addr < high)
+             if (lines->info[l].prologue_end
+                 && add_bkpt (lines->info[l].addr) < 0)
+               return -1;
+         if (adhoc && nbkpts == 0
+             && l + 1 < nlines
+             && lines->info[l + 1].line == lines->info[l].line
+             && lines->info[l + 1].file == lines->info[l].file
+             && lines->info[l + 1].column == lines->info[l].column)
+           return add_bkpt (lines->info[l + 1].addr);
+         return nbkpts;
+       }
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return -1;
+    }
+
+  /* Most often there is a single contiguous PC range for the DIE.  */
+  Dwarf_Addr lowpc;
+  Dwarf_Addr highpc;
+  if (INTUSE(dwarf_lowpc) (die, &lowpc) == 0)
+    return (INTUSE(dwarf_highpc) (die, &highpc)
+           ?: search_range (lowpc, highpc, true, true));
+
+
+  /* We have to look for a noncontiguous range.  */
+  Dwarf_Attribute attr_mem;
+  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem);
+  if (attr == NULL)
+    return -1;
+
+  /* Must have the form data4 or data8 which act as an offset.  */
+  Dwarf_Word offset;
+  if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
+    return -1;
+
+  const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
+  if (d == NULL)
+    {
+      __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
+      return -1;
+    }
+
+  /* Fetch the CU's base address.  */
+  Dwarf_Addr base;
+  if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
+    return -1;
+
+  /* Search each contiguous address range for DWARF prologue_end markers.  */
+  unsigned char *readp = d->d_buf + offset;
+  Dwarf_Addr begin;
+  Dwarf_Addr end;
+  lowpc = highpc = (Dwarf_Addr) -1l;
+  do
+    {
+    next:
+      if ((unsigned char *) d->d_buf + d->d_size - readp
+         < die->cu->address_size * 2)
+       {
+         __libdw_seterrno (DWARF_E_INVALID_DWARF);
+         free (*bkpts);
+         *bkpts = NULL;
+         return -1;
+       }
+
+      if (die->cu->address_size == 8)
+       {
+         begin = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
+         end = read_8ubyte_unaligned_inc (die->cu->dbg, readp);
+       }
+      else
+       {
+         begin = (Dwarf_Sword) read_4sbyte_unaligned_inc (die->cu->dbg,
+                                                          readp);
+         end = read_4ubyte_unaligned_inc (die->cu->dbg, readp);
+       }
+
+      if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
+       {
+         base = end;
+         goto next;
+       }
+
+      if (begin == 0 && end == 0) /* End of list entry.  */
+       break;
+
+      /* We have an address range entry.  */
+      if (begin < lowpc)
+       {
+         lowpc = begin;
+         highpc = end;
+       }
+    }
+  while (search_range (begin, end, true, false) >= 0);
+
+  /* If we didn't find any proper DWARF markers, then look in the
+     lowest-addressed range for an ad hoc marker.  Failing that,
+     fall back to just using the entrypc value.  */
+  return (nbkpts
+         ?: (lowpc == (Dwarf_Addr) -1l ? 0
+             : search_range (lowpc, highpc, false, true))
+         ?: entrypc_bkpt ());
+}
diff --git a/libdw/dwarf_entrypc.c b/libdw/dwarf_entrypc.c
new file mode 100644 (file)
index 0000000..61a1d4b
--- /dev/null
@@ -0,0 +1,35 @@
+/* Return entry PC attribute of DIE.
+   Copyright (C) 2003, 2005 Red Hat, Inc.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include "libdwP.h"
+
+
+int
+dwarf_entrypc (die, return_addr)
+     Dwarf_Die *die;
+     Dwarf_Addr *return_addr;
+{
+  Dwarf_Attribute attr_mem;
+
+  return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_entry_pc,
+                                                    &attr_mem)
+                                ?: INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+                                                       &attr_mem),
+                                return_addr);
+}
+INTDEF(dwarf_entrypc)
index 350aa440ee6f8c45b42ccb8e9ae78abe2da91a83..b76d43272a79f47fcea69f6a8c608d7dba06a7b8 100644 (file)
@@ -292,6 +292,10 @@ extern int dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
 extern int dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
      __nonnull_attribute__ (2);
 
+/* Return entry_pc or low_pc attribute of DIE.  */
+extern int dwarf_entrypc (Dwarf_Die *die, Dwarf_Addr *return_addr)
+     __nonnull_attribute__ (2);
+
 /* Return 1 if DIE's lowpc/highpc or ranges attributes match the PC address,
    0 if not, or -1 for errors.  */
 extern int dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc);
@@ -530,6 +534,12 @@ extern int dwarf_func_inline_instances (Dwarf_Func *func,
                                        void *arg);
 
 
+/* Find the appropriate PC location or locations for function entry
+   breakpoints for the given DW_TAG_subprogram DIE.  Returns -1 for errors.
+   On success, returns the number of breakpoint locations (never zero)
+   and sets *BKPTS to a malloc'd vector of addresses.  */
+extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
+
 
 /* Call callback function for each of the macro information entry for
    the CU.  */
index 37f287212b2113409f7c9aba1c6e2e4d2fbbde32..d7ae776e99bfbb7b9abca921e9a43c8b4841efb8 100644 (file)
@@ -373,6 +373,7 @@ INTDECL (dwarf_child)
 INTDECL (dwarf_dieoffset)
 INTDECL (dwarf_diename)
 INTDECL (dwarf_end)
+INTDECL (dwarf_entrypc)
 INTDECL (dwarf_errmsg)
 INTDECL (dwarf_formaddr)
 INTDECL (dwarf_formblock)
index bd710aeece7c29d3fc85c3066001105f15ee2ad3..35667cee3c5731763dc71faa4c09f9b779fb0ffa 100644 (file)
@@ -1,3 +1,8 @@
+2005-09-09  Roland McGrath  <roland@redhat.com>
+
+       * elf_update.c (write_file): Stat the file and fchmod it after update
+       if its mode had S_ISUID or S_ISGID bits set.
+
 2005-08-28  Ulrich Drepper  <drepper@redhat.com>
 
        * elf32_getphdr.c: Include <system.h>.  Use pread_retry instead of
index 5d6c6b7a1af4838e8dba7df9f0bb649c8e415bbc..f380e2b9d162d3174daab4c602f4eb992a3917c2 100644 (file)
@@ -22,6 +22,7 @@
 #include <libelf.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 
 #include "libelfP.h"
 
@@ -31,6 +32,14 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
 {
   int class = elf->class;
 
+  /* Check the mode bits now, before modification might change them.  */
+  struct stat st;
+  if (unlikely (fstat (elf->fildes, &st) != 0))
+    {
+      __libelf_seterrno (ELF_E_WRITE_ERROR);
+      return -1;
+    }
+
   /* Adjust the size in any case.  We do this even if we use `write'.
      We cannot do this if this file is in an archive.  We also don't
      do it *now* if we are shortening the file since this would
@@ -87,6 +96,18 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
       size = -1;
     }
 
+  /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
+     mode bits.  So make sure we restore them afterwards if they were set.
+     This is not atomic if someone else chmod's the file while we operate.  */
+  if (size != -1
+      && unlikely (st.st_mode & (S_ISUID | S_ISGID))
+      /* fchmod ignores the bits we cannot change.  */
+      && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
+    {
+      __libelf_seterrno (ELF_E_WRITE_ERROR);
+      size = -1;
+    }
+
   if (size != -1 && elf->parent == NULL)
     elf->maximum_size = size;