From 4390d26b708236220190ac7b6d923be1ec928fd5 Mon Sep 17 00:00:00 2001
From: Chih-Hung Hsieh <chh@google.com>
Date: Fri, 11 Sep 2015 14:33:36 -0700
Subject: [PATCH] Replace inline nested functions with macros.

If a nested function has no return value, replace it with
a macro that expands to a block, otherwise, use a "statement expression".
Both clang and gcc have "statement expression" but clang does
not support gnu nested functions.

Copy macro arguments to a local variable before use to enforce type
checking/casting and avoid multiple evaluation of the arguments.
Rename local variables if they shadow outer scope local variables.

For larger nested functions, change them to local static functions
and pass them all required parameters in a "closure" list.

Signed-off-by: Chih-Hung Hsieh <chh@google.com>
---
 src/ChangeLog    |  19 +++
 src/addr2line.c  |  27 ++--
 src/ar.c         |  30 +++--
 src/arlib-argp.c |  14 +-
 src/elflint.c    |  11 +-
 src/readelf.c    |  74 ++++++-----
 src/strip.c      | 392 +++++++++++++++++++++++++++++--------------------------
 src/unstrip.c    |  94 +++++++------
 8 files changed, 359 insertions(+), 302 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 238c416..2538b84 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
+2015-09-11  Chih-Hung Hsieh  <chh@google.com>
+
+	* addr2line.c (handle_address): Replace inline nested functions
+	with macros expanding to a block or statement expression.
+	* ar.c (do_oper_extract): Likewise.
+	* arlib-argp.c (parse_opt): Likewise.
+	* elflint.c (check_attributes): Likewise.
+	* readelf.c (parse_opt): Likewise.
+	(print_attributes): Likewise.
+	(print_cfa_program): Likewise.
+	(print_debug_line_section): Likewise.
+	(handle_core_registers): Likewise.
+	* strip.c (handle_elf): Likewise.
+	* unstrip.c (adjust_relocs): Likewise.
+	(find_alloc_sections_prelink): Likewise.
+	(copy_elided_sections): Likewise.
+	(handle_explicit_files): Likewise.
+	(match_module): Likewise.
+
 2015-09-09  Chih-Hung Hsieh  <chh@google.com>
 
 	* readelf.c (print_debug_exception_table): Initialize variable before
diff --git a/src/addr2line.c b/src/addr2line.c
index 0ce854f..bc34009 100644
--- a/src/addr2line.c
+++ b/src/addr2line.c
@@ -705,19 +705,22 @@ handle_address (const char *string, Dwfl *dwfl)
 	  Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
 	  assert (info != NULL);
 
-	  inline void show (int (*get) (Dwarf_Line *, bool *),
-			    const char *note)
-	  {
-	    bool flag;
-	    if ((*get) (info, &flag) == 0 && flag)
-	      fputs (note, stdout);
+	  #define show(get_arg, note_arg) \
+	  { \
+	    int (*get) (Dwarf_Line *, bool *) = get_arg; \
+	    const char *note = note_arg; \
+	    bool flag; \
+	    if ((*get) (info, &flag) == 0 && flag) \
+	      fputs (note, stdout); \
 	  }
-	  inline void show_int (int (*get) (Dwarf_Line *, unsigned int *),
-				const char *name)
-	  {
-	    unsigned int val;
-	    if ((*get) (info, &val) == 0 && val != 0)
-	      printf (" (%s %u)", name, val);
+
+	  #define show_int(get_arg, name_arg) \
+	  { \
+	    int (*get) (Dwarf_Line *, unsigned int *) = get_arg; \
+	    const char *name = name_arg; \
+	    unsigned int val; \
+	    if ((*get) (info, &val) == 0 && val != 0) \
+	      printf (" (%s %u)", name, val); \
 	  }
 
 	  show (&dwarf_linebeginstatement, " (is_stmt)");
diff --git a/src/ar.c b/src/ar.c
index 1320d07..b3428d6 100644
--- a/src/ar.c
+++ b/src/ar.c
@@ -460,20 +460,22 @@ do_oper_extract (int oper, const char *arfname, char **argv, int argc,
   memset (found, '\0', sizeof (found));
 
   size_t name_max = 0;
-  inline bool should_truncate_fname (void)
-  {
-    if (errno == ENAMETOOLONG && allow_truncate_fname)
-      {
-	if (name_max == 0)
-	  {
-	    long int len = pathconf (".", _PC_NAME_MAX);
-	    if (len > 0)
-	      name_max = len;
-	  }
-	return name_max != 0;
-      }
-    return false;
-  }
+
+  #define should_truncate_fname() \
+  ( { \
+    bool result = false; \
+    if (errno == ENAMETOOLONG && allow_truncate_fname) \
+      { \
+	if (name_max == 0) \
+	  { \
+	    long int len = pathconf (".", _PC_NAME_MAX); \
+	    if (len > 0) \
+	      name_max = len; \
+	  } \
+	result = (name_max != 0); \
+      } \
+    result; \
+  } )
 
   off_t index_off = -1;
   size_t index_size = 0;
diff --git a/src/arlib-argp.c b/src/arlib-argp.c
index 1bdd8d0..59ad89a 100644
--- a/src/arlib-argp.c
+++ b/src/arlib-argp.c
@@ -59,13 +59,13 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
 static char *
 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
 {
-  inline char *text_for_default (void)
-  {
-    char *new_text;
-    if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0))
-      return (char *) text;
-    return new_text;
-  }
+  #define text_for_default() \
+  ( { \
+    char *new_text; \
+    if (unlikely (asprintf (&new_text, gettext ("%s (default)"), text) < 0)) \
+      new_text = (char *) text; \
+    new_text; \
+  } ) \
 
   switch (key)
     {
diff --git a/src/elflint.c b/src/elflint.c
index c1f0be5..6545415 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -3395,10 +3395,8 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       return;
     }
 
-  inline size_t pos (const unsigned char *p)
-  {
-    return p - (const unsigned char *) data->d_buf;
-  }
+  #define pos(p) \
+    ((const unsigned char *) (p) - (const unsigned char *) data->d_buf)
 
   const unsigned char *p = data->d_buf;
   if (*p++ != 'A')
@@ -3408,10 +3406,7 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
       return;
     }
 
-  inline size_t left (void)
-  {
-    return (const unsigned char *) data->d_buf + data->d_size - p;
-  }
+  #define left() ((const unsigned char *) data->d_buf + data->d_size - p)
 
   while (left () >= 4)
     {
diff --git a/src/readelf.c b/src/readelf.c
index 33274f3..be343d3 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -308,16 +308,18 @@ static error_t
 parse_opt (int key, char *arg,
 	   struct argp_state *state __attribute__ ((unused)))
 {
-  void add_dump_section (const char *name, bool implicit)
-  {
-    struct section_argument *a = xmalloc (sizeof *a);
-    a->arg = name;
-    a->next = NULL;
-    a->implicit = implicit;
-    struct section_argument ***tailp
-      = key == 'x' ? &dump_data_sections_tail : &string_sections_tail;
-    **tailp = a;
-    *tailp = &a->next;
+  #define add_dump_section(name_arg, implicit_arg) \
+  { \
+    const char *name = name_arg; \
+    bool implicit = implicit_arg; \
+    struct section_argument *a = xmalloc (sizeof *a); \
+    a->arg = name; \
+    a->next = NULL; \
+    a->implicit = implicit; \
+    struct section_argument ***tailp \
+      = key == 'x' ? &dump_data_sections_tail : &string_sections_tail; \
+    **tailp = a; \
+    *tailp = &a->next; \
   }
 
   switch (key)
@@ -3330,10 +3332,7 @@ print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr)
 
       fputs_unlocked (gettext ("  Owner          Size\n"), stdout);
 
-      inline size_t left (void)
-      {
-	return (const unsigned char *) data->d_buf + data->d_size - p;
-      }
+      #define left() ((const unsigned char *) data->d_buf + data->d_size - p)
 
       /* Loop over the sections.  */
       while (left () >= 4)
@@ -4944,11 +4943,13 @@ print_cfa_program (const unsigned char *readp, const unsigned char *const endp,
 		   Dwfl_Module *dwflmod, Ebl *ebl, Dwarf *dbg)
 {
   char regnamebuf[REGNAMESZ];
-  const char *regname (unsigned int regno)
-  {
-    register_info (ebl, regno, NULL, regnamebuf, NULL, NULL);
-    return regnamebuf;
-  }
+
+  #define regname(regno_arg) \
+  ( { \
+    unsigned int regno = regno_arg; \
+    register_info (ebl, regno, NULL, regnamebuf, NULL, NULL); \
+    regnamebuf; \
+  } )
 
   puts ("\n   Program:");
   Dwarf_Word pc = vma_base;
@@ -6573,14 +6574,16 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
 	 or DW_LNS_advance_pc (as per DWARF4 6.2.5.1).  */
       unsigned int op_addr_advance;
       bool show_op_index;
-      inline void advance_pc (unsigned int op_advance)
-      {
-	op_addr_advance = minimum_instr_len * ((op_index + op_advance)
-					       / max_ops_per_instr);
-	address += op_advance;
-	show_op_index = (op_index > 0 ||
-			 (op_index + op_advance) % max_ops_per_instr > 0);
-	op_index = (op_index + op_advance) % max_ops_per_instr;
+
+      #define advance_pc(op_advance_arg) \
+      { \
+        unsigned int op_advance = op_advance_arg; \
+	op_addr_advance = minimum_instr_len * ((op_index + (op_advance)) \
+					       / max_ops_per_instr); \
+	address += (op_advance); \
+	show_op_index = (op_index > 0 || \
+			 (op_index + (op_advance)) % max_ops_per_instr > 0); \
+	op_index = (op_index + (op_advance)) % max_ops_per_instr; \
       }
 
       if (max_ops_per_instr == 0)
@@ -8922,14 +8925,15 @@ handle_core_registers (Ebl *ebl, Elf *core, const void *desc,
   qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers);
 
   /* Collect the unique sets and sort them.  */
-  inline bool same_set (const struct register_info *a,
-			const struct register_info *b)
-  {
-    return (a < &regs[maxnreg] && a->regloc != NULL
-	    && b < &regs[maxnreg] && b->regloc != NULL
-	    && a->bits == b->bits
-	    && (a->set == b->set || !strcmp (a->set, b->set)));
-  }
+  #define same_set(a_arg, b_arg) \
+  ( { \
+    const struct register_info *a = a_arg; \
+    const struct register_info *b = b_arg; \
+    (a < &regs[maxnreg] && a->regloc != NULL \
+	    && b < &regs[maxnreg] && b->regloc != NULL \
+	    && a->bits == b->bits \
+	    && (a->set == b->set || !strcmp (a->set, b->set))); \
+  } )
   struct register_info *sets[maxreg + 1];
   sets[0] = &regs[0];
   size_t nsets = 1;
diff --git a/src/strip.c b/src/strip.c
index 5e69334..3e84192 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -405,21 +405,8 @@ process_file (const char *fname)
 /* Maximum size of array allocated on stack.  */
 #define MAX_STACK_ALLOC	(400 * 1024)
 
-static int
-handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
-	    mode_t mode, struct timespec tvp[2])
+struct shdr_info
 {
-  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
-  size_t fname_len = strlen (fname) + 1;
-  char *fullname = alloca (prefix_len + 1 + fname_len);
-  char *cp = fullname;
-  Elf *debugelf = NULL;
-  tmp_debug_fname = NULL;
-  int result = 0;
-  size_t shdridx = 0;
-  size_t shstrndx;
-  struct shdr_info
-  {
     Elf_Scn *scn;
     GElf_Shdr shdr;
     Elf_Data *data;
@@ -434,7 +421,165 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     Elf_Scn *newscn;
     struct Ebl_Strent *se;
     Elf32_Word *newsymidx;
-  } *shdr_info = NULL;
+};
+
+#define declare_relocate_closure \
+  Ebl * const ebl, \
+  Elf_Data * const symdata, \
+  Elf_Data * const xndxdata, \
+  size_t const shnum, \
+  const char * const fname, \
+  struct shdr_info * const shdr_info, \
+  Elf_Data * const tdata, \
+  Elf * const debugelf, \
+  GElf_Ehdr * const ehdr
+
+#define pass_relocate_closure \
+  ebl, symdata, xndxdata, shnum, fname, shdr_info, tdata, debugelf, ehdr
+
+/* Apply one relocation.  Returns true when trivial
+  relocation actually done.  */
+static bool
+relocate (declare_relocate_closure, GElf_Addr offset,
+          const GElf_Sxword addend, bool is_rela, int rtype, int symndx)
+{
+		/* R_*_NONE relocs can always just be removed.  */
+		if (rtype == 0)
+		  return true;
+
+		/* We only do simple absolute relocations.  */
+		Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
+		if (type == ELF_T_NUM)
+		  return false;
+
+		/* These are the types we can relocate.  */
+#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
+		DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
+		DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
+
+		/* And only for relocations against other debug sections.  */
+		GElf_Sym sym_mem;
+		Elf32_Word xndx;
+		GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
+						  symndx, &sym_mem,
+						  &xndx);
+		Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
+				  ? xndx : sym->st_shndx);
+		if (sec >= shnum + 2)
+		  INTERNAL_ERROR (fname);
+
+		if (ebl_debugscn_p (ebl, shdr_info[sec].name))
+		  {
+		    size_t size;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+		    union { TYPES; } tmpbuf;
+#undef DO_TYPE
+
+		    switch (type)
+		      {
+#define DO_TYPE(NAME, Name)				\
+			case ELF_T_##NAME:		\
+			  size = sizeof (GElf_##Name);	\
+			  tmpbuf.Name = 0;		\
+			  break;
+			TYPES;
+#undef DO_TYPE
+		      default:
+			return false;
+		      }
+
+		    if (offset > tdata->d_size
+			|| tdata->d_size - offset < size)
+		      {
+			cleanup_debug ();
+			error (EXIT_FAILURE, 0, gettext ("bad relocation"));
+		      }
+
+		    /* When the symbol value is zero then for SHT_REL
+		       sections this is all that needs to be checked.
+		       The addend is contained in the original data at
+		       the offset already.  So if the (section) symbol
+		       address is zero and the given addend is zero
+		       just remove the relocation, it isn't needed
+		       anymore.  */
+		    if (addend == 0 && sym->st_value == 0)
+		      return true;
+
+		    Elf_Data tmpdata =
+		      {
+			.d_type = type,
+			.d_buf = &tmpbuf,
+			.d_size = size,
+			.d_version = EV_CURRENT,
+		      };
+		    Elf_Data rdata =
+		      {
+			.d_type = type,
+			.d_buf = tdata->d_buf + offset,
+			.d_size = size,
+			.d_version = EV_CURRENT,
+		      };
+
+		    GElf_Addr value = sym->st_value;
+		    if (is_rela)
+		      {
+			/* For SHT_RELA sections we just take the
+			   given addend and add it to the value.  */
+			value += addend;
+		      }
+		    else
+		      {
+			/* For SHT_REL sections we have to peek at
+			   what is already in the section at the given
+			   offset to get the addend.  */
+			Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
+						     &rdata,
+						     ehdr->e_ident[EI_DATA]);
+			if (d == NULL)
+			  INTERNAL_ERROR (fname);
+			assert (d == &tmpdata);
+		      }
+
+		    switch (type)
+		      {
+#define DO_TYPE(NAME, Name)					\
+			case ELF_T_##NAME:			\
+			  tmpbuf.Name += (GElf_##Name) value;	\
+			  break;
+			TYPES;
+#undef DO_TYPE
+		      default:
+			abort ();
+		      }
+
+		    /* Now finally put in the new value.  */
+		    Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
+						 &tmpdata,
+						 ehdr->e_ident[EI_DATA]);
+		    if (s == NULL)
+		      INTERNAL_ERROR (fname);
+		    assert (s == &rdata);
+
+		    return true;
+		  }
+		return false;
+}
+
+static int
+handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
+	    mode_t mode, struct timespec tvp[2])
+{
+  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
+  size_t fname_len = strlen (fname) + 1;
+  char *fullname = alloca (prefix_len + 1 + fname_len);
+  char *cp = fullname;
+  Elf *debugelf = NULL;
+  tmp_debug_fname = NULL;
+  int result = 0;
+  size_t shdridx = 0;
+  size_t shstrndx;
+  struct shdr_info *shdr_info = NULL;
   Elf_Scn *scn;
   size_t cnt;
   size_t idx;
@@ -929,19 +1074,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		 file's .data pointer.  Below, we'll copy the section
 		 contents.  */
 
-	      inline void check_preserved (size_t i)
-	      {
-		if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0
-		    && shdr_info[i].debug_data == NULL)
-		  {
-		    if (shdr_info[i].data == NULL)
-		      shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL);
-		    if (shdr_info[i].data == NULL)
-		      INTERNAL_ERROR (fname);
-
-		    shdr_info[i].debug_data = shdr_info[i].data;
-		    changes |= i < cnt;
-		  }
+	      #define check_preserved(i_arg) \
+	      { \
+		size_t i = i_arg; \
+		if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0 \
+		    && shdr_info[i].debug_data == NULL) \
+		  { \
+		    if (shdr_info[i].data == NULL) \
+		      shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL); \
+		    if (shdr_info[i].data == NULL) \
+		      INTERNAL_ERROR (fname); \
+		    shdr_info[i].debug_data = shdr_info[i].data; \
+		    changes |= i < cnt; \
+		  } \
 	      }
 
 	      check_preserved (shdr_info[cnt].shdr.sh_link);
@@ -1433,21 +1578,22 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	/* Update section headers when the data size has changed.
 	   We also update the SHT_NOBITS section in the debug
 	   file so that the section headers match in sh_size.  */
-	inline void update_section_size (const Elf_Data *newdata)
-	{
-	  GElf_Shdr shdr_mem;
-	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-	  shdr->sh_size = newdata->d_size;
-	  (void) gelf_update_shdr (scn, shdr);
-	  if (debugelf != NULL)
-	    {
-	      /* libelf will use d_size to set sh_size.  */
-	      Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
-							     cnt), NULL);
-	      if (debugdata == NULL)
-		INTERNAL_ERROR (fname);
-	      debugdata->d_size = newdata->d_size;
-	    }
+	#define update_section_size(newdata_arg) \
+	{ \
+	  const Elf_Data *newdata = newdata_arg; \
+	  GElf_Shdr shdr_mem; \
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); \
+	  shdr->sh_size = newdata->d_size; \
+	  (void) gelf_update_shdr (scn, shdr); \
+	  if (debugelf != NULL) \
+	    { \
+	      /* libelf will use d_size to set sh_size.  */ \
+	      Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, \
+							     cnt), NULL); \
+	      if (debugdata == NULL) \
+		INTERNAL_ERROR (fname); \
+	      debugdata->d_size = newdata->d_size; \
+	    } \
 	}
 
 	if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
@@ -1461,18 +1607,21 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
 	switch (shdr_info[cnt].shdr.sh_type)
 	  {
-	    inline bool no_symtab_updates (void)
-	    {
-	      /* If the symbol table hasn't changed, do not do anything.  */
-	      if (shdr_info[symtabidx].newsymidx == NULL)
-		return true;
-
-	      /* If the symbol table is not discarded, but additionally
-		 duplicated in the separate debug file and this section
-		 is discarded, don't adjust anything.  */
-	      return (shdr_info[cnt].idx == 0
-		      && shdr_info[symtabidx].debug_data != NULL);
-	    }
+	    #define no_symtab_updates() \
+	    ( { \
+	        bool no_updates; \
+	        /* If the symbol table hasn't changed, do not do anything.  */ \
+	        if (shdr_info[symtabidx].newsymidx == NULL) { \
+	          no_updates = true; \
+	        } else { \
+	          /* If the symbol table is not discarded, but additionally */ \
+	          /* duplicated in the separate debug file and this section */ \
+	          /* is discarded, don't adjust anything. */ \
+	          no_updates = (shdr_info[cnt].idx == 0 \
+	                        && shdr_info[symtabidx].debug_data != NULL); \
+	        } \
+	        no_updates; \
+	    } )
 
 	  case SHT_REL:
 	  case SHT_RELA:
@@ -1798,133 +1947,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	      xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data
 			  ?: shdr_info[shdr_info[symt].symtab_idx].data);
 
-	      /* Apply one relocation.  Returns true when trivial
-		 relocation actually done.  */
-	      bool relocate (GElf_Addr offset, const GElf_Sxword addend,
-			     bool is_rela, int rtype, int symndx)
-	      {
-		/* R_*_NONE relocs can always just be removed.  */
-		if (rtype == 0)
-		  return true;
-
-		/* We only do simple absolute relocations.  */
-		Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
-		if (type == ELF_T_NUM)
-		  return false;
-
-		/* These are the types we can relocate.  */
-#define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);		\
-		DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);		\
-		DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
-
-		/* And only for relocations against other debug sections.  */
-		GElf_Sym sym_mem;
-		Elf32_Word xndx;
-		GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
-						  symndx, &sym_mem,
-						  &xndx);
-		Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
-				  ? xndx : sym->st_shndx);
-		if (sec >= shnum + 2)
-		  INTERNAL_ERROR (fname);
-
-		if (ebl_debugscn_p (ebl, shdr_info[sec].name))
-		  {
-		    size_t size;
-
-#define DO_TYPE(NAME, Name) GElf_##Name Name;
-		    union { TYPES; } tmpbuf;
-#undef DO_TYPE
-
-		    switch (type)
-		      {
-#define DO_TYPE(NAME, Name)				\
-			case ELF_T_##NAME:		\
-			  size = sizeof (GElf_##Name);	\
-			  tmpbuf.Name = 0;		\
-			  break;
-			TYPES;
-#undef DO_TYPE
-		      default:
-			return false;
-		      }
-
-		    if (offset > tdata->d_size
-			|| tdata->d_size - offset < size)
-		      {
-			cleanup_debug ();
-			error (EXIT_FAILURE, 0, gettext ("bad relocation"));
-		      }
-
-		    /* When the symbol value is zero then for SHT_REL
-		       sections this is all that needs to be checked.
-		       The addend is contained in the original data at
-		       the offset already.  So if the (section) symbol
-		       address is zero and the given addend is zero
-		       just remove the relocation, it isn't needed
-		       anymore.  */
-		    if (addend == 0 && sym->st_value == 0)
-		      return true;
-
-		    Elf_Data tmpdata =
-		      {
-			.d_type = type,
-			.d_buf = &tmpbuf,
-			.d_size = size,
-			.d_version = EV_CURRENT,
-		      };
-		    Elf_Data rdata =
-		      {
-			.d_type = type,
-			.d_buf = tdata->d_buf + offset,
-			.d_size = size,
-			.d_version = EV_CURRENT,
-		      };
-
-		    GElf_Addr value = sym->st_value;
-		    if (is_rela)
-		      {
-			/* For SHT_RELA sections we just take the
-			   given addend and add it to the value.  */
-			value += addend;
-		      }
-		    else
-		      {
-			/* For SHT_REL sections we have to peek at
-			   what is already in the section at the given
-			   offset to get the addend.  */
-			Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
-						     &rdata,
-						     ehdr->e_ident[EI_DATA]);
-			if (d == NULL)
-			  INTERNAL_ERROR (fname);
-			assert (d == &tmpdata);
-		      }
-
-		    switch (type)
-		      {
-#define DO_TYPE(NAME, Name)					\
-			case ELF_T_##NAME:			\
-			  tmpbuf.Name += (GElf_##Name) value;	\
-			  break;
-			TYPES;
-#undef DO_TYPE
-		      default:
-			abort ();
-		      }
-
-		    /* Now finally put in the new value.  */
-		    Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
-						 &tmpdata,
-						 ehdr->e_ident[EI_DATA]);
-		    if (s == NULL)
-		      INTERNAL_ERROR (fname);
-		    assert (s == &rdata);
-
-		    return true;
-		  }
-		return false;
-	      }
 
 	      if (shdr->sh_entsize == 0)
 		INTERNAL_ERROR (fname);
@@ -1936,7 +1958,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		  {
 		    GElf_Rel rel_mem;
 		    GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
-		    if (! relocate (r->r_offset, 0, false,
+		    if (! relocate (pass_relocate_closure,
+				    r->r_offset, 0, false,
 				    GELF_R_TYPE (r->r_info),
 				    GELF_R_SYM (r->r_info)))
 		      {
@@ -1950,7 +1973,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 		  {
 		    GElf_Rela rela_mem;
 		    GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
-		    if (! relocate (r->r_offset, r->r_addend, true,
+		    if (! relocate (pass_relocate_closure,
+				    r->r_offset, r->r_addend, true,
 				    GELF_R_TYPE (r->r_info),
 				    GELF_R_SYM (r->r_info)))
 		      {
diff --git a/src/unstrip.c b/src/unstrip.c
index 82bcdd8..c4d68d2 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -397,11 +397,12 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
 {
   Elf_Data *data = elf_getdata (outscn, NULL);
 
-  inline void adjust_reloc (GElf_Xword *info)
-    {
-      size_t ndx = GELF_R_SYM (*info);
-      if (ndx != STN_UNDEF)
-	*info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
+  #define adjust_reloc(info_arg) \
+    { \
+      GElf_Xword *info = info_arg; \
+      size_t ndx = GELF_R_SYM (*info); \
+      if (ndx != STN_UNDEF) \
+        *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info)); \
     }
 
   switch (shdr->sh_type)
@@ -1060,14 +1061,17 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
     }
 
   bool fail = false;
-  inline void check_match (bool match, Elf_Scn *scn, const char *name)
-    {
-      if (!match)
-	{
-	  fail = true;
-	  error (0, 0, _("cannot find matching section for [%zu] '%s'"),
-		 elf_ndxscn (scn), name);
-	}
+  #define check_match(match_arg, scn_arg, name_arg) \
+    { \
+      bool match = match_arg; \
+      Elf_Scn *scnp = scn_arg; \
+      const char *sect_name = name_arg; \
+      if (!match) \
+      { \
+        fail = true; \
+        error (0, 0, _("cannot find matching section for [%zu] '%s'"), \
+               elf_ndxscn (scnp), sect_name); \
+      } \
     }
 
   Elf_Scn *scn = NULL;
@@ -1292,25 +1296,29 @@ more sections in stripped file than debug file -- arguments reversed?"));
     }
 
   /* Locate a matching unallocated section in SECTIONS.  */
-  inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
-					       const char *name)
-    {
-      size_t l = nalloc, u = stripped_shnum - 1;
-      while (l < u)
-	{
-	  size_t i = (l + u) / 2;
-	  struct section *sec = &sections[i];
-	  int cmp = compare_unalloc_sections (shdr, &sec->shdr,
-					      name, sec->name);
-	  if (cmp < 0)
-	    u = i;
-	  else if (cmp > 0)
-	    l = i + 1;
-	  else
-	    return sec;
-	}
-      return NULL;
-    }
+  #define find_unalloc_section(shdr_arg, name_arg) \
+    ( { \
+        const GElf_Shdr *shdr_p = shdr_arg; \
+        const char *sect_name = name_arg; \
+        struct section * result = NULL; \
+        size_t l = nalloc, u = stripped_shnum - 1; \
+        while (l < u) \
+        { \
+          size_t i = (l + u) / 2; \
+          struct section *secp = &sections[i]; \
+          int cmp = compare_unalloc_sections (shdr_p, &secp->shdr, \
+                                              sect_name, secp->name); \
+          if (cmp < 0) \
+            u = i; \
+          else if (cmp > 0) \
+            l = i + 1; \
+          else { \
+            result = secp; \
+            break; \
+          } \
+        } \
+      result; \
+    } )
 
   Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
 						unstripped_shstrndx), NULL);
@@ -1984,12 +1992,13 @@ handle_explicit_files (const char *output_file, bool create_dirs, bool force,
 
   /* Warn, and exit if not forced to continue, if some ELF header
      sanity check for the stripped and unstripped files failed.  */
-  void warn (const char *msg)
-  {
-    error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.",
-	   force ? _("WARNING: ") : "",
-	   stripped_file, unstripped_file, msg,
-	   force ? "" : _(", use --force"));
+  #define warn(msg_arg) \
+  { \
+    const char *msg = msg_arg; \
+    error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.", \
+	   force ? _("WARNING: ") : "", \
+	   stripped_file, unstripped_file, msg, \
+	   force ? "" : _(", use --force")); \
   }
 
   int stripped_fd = open_file (stripped_file, false);
@@ -2245,10 +2254,11 @@ static void
 handle_implicit_modules (const struct arg_info *info)
 {
   struct match_module_info mmi = { info->args, NULL, info->match_files };
-  inline ptrdiff_t next (ptrdiff_t offset)
-    {
-      return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
-    }
+  #define next(offset_arg) \
+    ( { \
+      ptrdiff_t old_offset = offset_arg; \
+      dwfl_getmodules (info->dwfl, &match_module, &mmi, old_offset); \
+    } )
   ptrdiff_t offset = next (0);
   if (offset == 0)
     error (EXIT_FAILURE, 0, _("no matching modules found"));
-- 
2.6.0.rc0.131.gf624c3d

