summaryrefslogtreecommitdiff
path: root/src/x86_64/Gstep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/x86_64/Gstep.c')
-rw-r--r--src/x86_64/Gstep.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c
index 4216d188..1dc440e3 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -25,6 +25,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+#ifdef HAVE_ASM_VSYSCALL_H
+#include <asm/vsyscall.h>
+#endif
+
#include "libunwind_i.h"
#include "unwind_i.h"
#include <signal.h>
@@ -53,6 +57,20 @@ is_plt_entry (struct dwarf_cursor *c)
return ret;
}
+static int
+is_vsyscall (struct dwarf_cursor *c)
+{
+#if defined(VSYSCALL_START) && defined(VSYSCALL_END)
+ return c->ip >= VSYSCALL_START && c->ip < VSYSCALL_END;
+#elif defined(VSYSCALL_ADDR)
+ /* Linux 3.16 removes `VSYSCALL_START` and `VSYSCALL_END`. Assume
+ a single page is mapped for vsyscalls. */
+ return c->ip >= VSYSCALL_ADDR && c->ip < VSYSCALL_ADDR + sysconf(_SC_PAGESIZE);
+#else
+ return 0;
+#endif
+}
+
int
unw_step (unw_cursor_t *cursor)
{
@@ -141,6 +159,15 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
c->dwarf.cfa += 8;
}
+ else if (is_vsyscall (&c->dwarf))
+ {
+ Debug (2, "in vsyscall region\n");
+ c->frame_info.cfa_reg_offset = 8;
+ c->frame_info.cfa_reg_rsp = -1;
+ c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+ c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.cfa += 8;
+ }
else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)