Sanitize interface of arch_get_sym_info/elf_get_sym_info

- <0 for errors, ==0 for OK, 1 for skip.  Errors are now propagated
  and can be handled as necessary without cancelling tracing.

- Clarify the comment at arch_get_sym_info.
diff --git a/backend.h b/backend.h
index 6edc948..44eea6d 100644
--- a/backend.h
+++ b/backend.h
@@ -277,17 +277,17 @@
 /* The following callback has to be implemented in backend if arch.h
  * defines ARCH_HAVE_GET_SYM_INFO.
  *
- * This is called for every PLT relocation R in ELF file LTE, that
- * ltrace is about to add to it's internal representation of the
- * program under trace.
- * The corresponding PLT entry is for SYM_INDEX-th relocation in the file.
+ * This is called for every PLT relocation RELA in ELF file LTE (which
+ * is named FILENAME), that ltrace is about to add.  The corresponding
+ * PLT entry is for SYM_INDEX-th relocation in the file.  This call is
+ * supposed to initialize SYM and RELA.  It returns 0 if there were no
+ * errors and given symbol should be used, 1 if the symbol should not
+ * be used, or a negative value if there were errors.
  *
- * The callback is responsible for initializing RELA and SYM.
- *
- * Return 0 if OK.
- * Return a negative value if this symbol (SYM_INDEX) should be ignored.  */
-int arch_get_sym_info(struct ltelf *lte, const char *filename,
-		      size_t sym_index, GElf_Rela *rela, GElf_Sym *sym);
+ * The backend implementation can delegate some of the work to default
+ * implementation in elf_get_sym_info.  */
+int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index,
+		      GElf_Rela *rela, GElf_Sym *sym);
 
 enum plt_status {
 	PLT_FAIL,
diff --git a/ltrace-elf.c b/ltrace-elf.c
index 93e0d5e..b42f27a 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -548,28 +548,23 @@
 elf_get_sym_info(struct ltelf *lte, const char *filename,
 		 size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
 {
-	int i = sym_index;
 	GElf_Rel rel;
-	void *ret;
 
 	if (lte->relplt->d_type == ELF_T_REL) {
-		ret = gelf_getrel(lte->relplt, i, &rel);
+		if (gelf_getrel(lte->relplt, sym_index, &rel) == NULL)
+			return -1;
 		rela->r_offset = rel.r_offset;
 		rela->r_info = rel.r_info;
 		rela->r_addend = 0;
-	} else {
-		ret = gelf_getrela(lte->relplt, i, rela);
+
+	} else if (gelf_getrela(lte->relplt, sym_index, rela) == NULL) {
+		return -1;
 	}
 
-	if (ret == NULL
-	    || ELF64_R_SYM(rela->r_info) >= lte->dynsym_count
-	    || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela->r_info),
-			   sym) == NULL) {
-		fprintf(stderr,
-			"Couldn't get relocation from \"%s\": %s\n",
-			filename, elf_errmsg(-1));
-		exit(EXIT_FAILURE);
-	}
+	if (ELF64_R_SYM(rela->r_info) >= lte->dynsym_count
+	    || gelf_getsym(lte->dynsym,
+			   ELF64_R_SYM(rela->r_info), sym) == NULL)
+		return -1;
 
 	return 0;
 }
@@ -602,8 +597,18 @@
 		GElf_Rela rela;
 		GElf_Sym sym;
 
-		if (arch_get_sym_info(lte, filename, i, &rela, &sym) < 0)
+		switch (arch_get_sym_info(lte, filename, i, &rela, &sym)) {
+		default:
+			fprintf(stderr,
+				"Couldn't get relocation for symbol #%zd"
+				" from \"%s\": %s\n",
+				i, filename, elf_errmsg(-1));
+			/* Fall through.  */
+		case 1:
 			continue; /* Skip this entry.  */
+		case 0:
+			break;
+		}
 
 		char const *name = lte->dynstr + sym.st_name;
 
diff --git a/ltrace-elf.h b/ltrace-elf.h
index 5bf72ed..1287bc1 100644
--- a/ltrace-elf.h
+++ b/ltrace-elf.h
@@ -91,8 +91,8 @@
 
 /* The base implementation of backend.h (arch_get_sym_info).
  * See backend.h for details.  */
-int elf_get_sym_info(struct ltelf *lte, const char *filename,
-		     size_t sym_index, GElf_Rela *rela, GElf_Sym *sym);
+int elf_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index,
+		     GElf_Rela *rela, GElf_Sym *sym);
 
 Elf_Data *elf_loaddata(Elf_Scn *scn, GElf_Shdr *shdr);
 
diff --git a/sysdeps/linux-gnu/mips/plt.c b/sysdeps/linux-gnu/mips/plt.c
index e8527d7..3a95089 100644
--- a/sysdeps/linux-gnu/mips/plt.c
+++ b/sysdeps/linux-gnu/mips/plt.c
@@ -1,7 +1,7 @@
 /*
  * This file is part of ltrace.
+ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
  * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
  * Copyright (C) 2008,2009 Juan Cespedes
  * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc.
  *
@@ -157,24 +157,19 @@
 arch_get_sym_info(struct ltelf *lte, const char *filename,
 		  size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
 {
-	const char *name;
-
-	if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
+	if (mips_elf_is_cpic(lte->ehdr.e_flags))
 		return elf_get_sym_info(lte, filename, sym_index, rela, sym);
-	}
 
 	/* Fixup the offset.  */
 	sym_index += lte->arch.mips_gotsym;
 
-	if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL){
-		error(EXIT_FAILURE, 0,
-			"Couldn't get relocation from \"%s\"", filename);
-	}
-
-	name = lte->dynstr + sym->st_name;
-	if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) {
-		debug(2, "sym %s not a function", name);
+	if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL)
 		return -1;
+
+	if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) {
+		const char *name = lte->dynstr + sym->st_name;
+		debug(2, "sym %s not a function", name);
+		return 1;
 	}
 
 	return 0;