summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2010-06-16 03:40:56 -0700
committerRoland McGrath <[email protected]>2010-06-16 11:16:45 -0700
commit3e4b5bbeca8987527c11a1ea048459a7ebd4ab5e (patch)
tree3d50b9a1c32c4c41eac398d9d6bd91b16e26c858
parent5f4b5089e1e3ca3c696cb420a6e215006691cf95 (diff)
Add new dwarf_cfi_validate_fde call.
-rw-r--r--NEWS2
-rw-r--r--libdw/ChangeLog9
-rw-r--r--libdw/cfi.c39
-rw-r--r--libdw/cfi.h5
-rw-r--r--libdw/fde.c21
-rw-r--r--libdw/libdw.h14
-rw-r--r--libdw/libdw.map5
7 files changed, 87 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index fe141380..9fc203e8 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Version 0.148:
libdw: Accept DWARF 4 format.
+libdw: New function dwarf_cfi_validate_fde.
+
libdwfl: Fixes in core-file handling, support cores from PIEs.
When working from build IDs, don't open a named file that mismatches.
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index f974e96d..7a107890 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,14 @@
2010-06-16 Roland McGrath <[email protected]>
+ * fde.c (fde_by_offset): Renamed to ...
+ (__libdw_fde_by_offset): ... this, made global and internal_function.
+ Don't take ADDRESS argument.
+ (__libdw_find_fde): Update caller. Do address sanity check here.
+ * cfi.h: Declare __libdw_fde_by_offset.
+ * cfi.c (dwarf_cfi_validate_fde): New function.
+ * libdw.h: Declare it.
+ * libdw.map (ELFUTILS_0.148): Add it.
+
* cie.c (intern_new_cie): Canonicalize DW_EH_PE_absptr FDE encoding to
either DW_EH_PE_udata8 or DW_EH_PE_udata4.
diff --git a/libdw/cfi.c b/libdw/cfi.c
index aeb48e69..e49335dd 100644
--- a/libdw/cfi.c
+++ b/libdw/cfi.c
@@ -504,3 +504,42 @@ __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
}
return result;
}
+
+int
+dwarf_cfi_validate_fde (cache, offset, start, end, signalp, encoding)
+ Dwarf_CFI *cache;
+ Dwarf_Off offset;
+ Dwarf_Addr *start;
+ Dwarf_Addr *end;
+ bool *signalp;
+ uint8_t *encoding;
+{
+ if (cache == NULL)
+ return -1;
+
+ struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
+ if (unlikely (fde == NULL))
+ return -1;
+
+ Dwarf_Frame *fs;
+ int result = __libdw_frame_at_address (cache, fde, fde->end, &fs);
+ if (unlikely (result != DWARF_E_NOERROR))
+ {
+ __libdw_seterrno (result);
+ return -1;
+ }
+
+ result = fs->nregs + 1;
+ free (fs);
+
+ if (start != NULL)
+ *start = fde->start;
+ if (end != NULL)
+ *end = fde->end;
+ if (signalp != NULL)
+ *signalp = fde->cie->signal_frame;
+ if (encoding != NULL)
+ *encoding = fde->cie->fde_encoding;
+
+ return result;
+}
diff --git a/libdw/cfi.h b/libdw/cfi.h
index 6aaa9c8a..ef9cd7e1 100644
--- a/libdw/cfi.h
+++ b/libdw/cfi.h
@@ -227,6 +227,11 @@ extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache,
Dwarf_Addr address)
__nonnull_attribute__ (1) internal_function;
+/* Look for an FDE by its offset in the section. */
+extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache,
+ Dwarf_Off offset)
+ __nonnull_attribute__ (1) internal_function;
+
/* Process the FDE that contains the given PC address,
to yield the frame state when stopped there.
The return value is a DWARF_E_* error code. */
diff --git a/libdw/fde.c b/libdw/fde.c
index c826114c..5685252b 100644
--- a/libdw/fde.c
+++ b/libdw/fde.c
@@ -1,5 +1,5 @@
/* FDE reading.
- Copyright (C) 2009 Red Hat, Inc.
+ Copyright (C) 2009-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -139,8 +139,9 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
return fde;
}
-static struct dwarf_fde *
-fde_by_offset (Dwarf_CFI *cache, Dwarf_Addr address, Dwarf_Off offset)
+struct dwarf_fde *
+internal_function
+__libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset)
{
Dwarf_CFI_Entry entry;
Dwarf_Off next_offset;
@@ -167,10 +168,6 @@ fde_by_offset (Dwarf_CFI *cache, Dwarf_Addr address, Dwarf_Off offset)
if (cache->next_offset == offset)
cache->next_offset = next_offset;
- /* Sanity check the address range. */
- if (address < fde->start || address >= fde->end)
- goto invalid;
-
return fde;
}
@@ -254,7 +251,15 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
Dwarf_Off offset = binary_search_fde (cache, address);
if (offset == (Dwarf_Off) -1l)
goto no_match;
- return fde_by_offset (cache, address, offset);
+ struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
+ if (unlikely (fde != NULL)
+ /* Sanity check the address range. */
+ && unlikely (address < fde->start || address >= fde->end))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
+ return fde;
}
/* It's not there. Read more CFI entries until we find it. */
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 252361fc..75998e1a 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -799,6 +799,20 @@ extern int dwarf_frame_register (Dwarf_Frame *frame, int regno,
Dwarf_Op **ops, size_t *nops)
__nonnull_attribute__ (3, 4, 5);
+/* Look up the FDE described at OFFSET bytes into the CFI section,
+ and validate it by decoding the FDE fully. Returns -1 for errors.
+ On success, returns the maximum DWARF register number that this
+ FDE describes and fills *START and *END with the PC address range
+ this FDE covers, *SIGNALP with whether this is a signal frame, and
+ *ENCODING with the pointer encoding used in this FDE. This is not
+ necessarily the exact encoding byte given in the augmentation string;
+ it will describe the exact address size used (DW_EH_PE_udata4 or
+ DW_EH_PE_udata8) if a DW_EH_PE_absptr encoding is being used. */
+extern int dwarf_cfi_validate_fde (Dwarf_CFI *cache,
+ Dwarf_Off offset,
+ Dwarf_Addr *start, Dwarf_Addr *end,
+ bool *signalp, uint8_t *encoding);
+
/* Return error code of last failing function call. This value is kept
separately for each thread. */
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 1a9afb13..89897acd 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -237,3 +237,8 @@ ELFUTILS_0.146 {
global:
dwfl_core_file_report;
} ELFUTILS_0.144;
+
+ELFUTILS_0.148 {
+ global:
+ dwarf_cfi_validate_fde;
+} ELFUTILS_0.146;