|
Petr Machata |
4b23d2c |
diff --git a/Makefile.am b/Makefile.am
|
|
Petr Machata |
4b23d2c |
index c3356de..141ff85 100644
|
|
Petr Machata |
4b23d2c |
--- a/Makefile.am
|
|
Petr Machata |
4b23d2c |
+++ b/Makefile.am
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,5 @@
|
|
Petr Machata |
4b23d2c |
# This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
-# Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+# Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix
|
|
Petr Machata |
4b23d2c |
# Copyright (C) 2010 Zachary T Welch, CodeSourcery
|
|
Petr Machata |
4b23d2c |
#
|
|
Petr Machata |
4b23d2c |
@@ -33,6 +33,7 @@ noinst_LTLIBRARIES = \
|
|
Petr Machata |
4b23d2c |
libltrace.la
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
libltrace_la_SOURCES = \
|
|
Petr Machata |
4b23d2c |
+ bits.c \
|
|
Petr Machata |
4b23d2c |
breakpoints.c \
|
|
Petr Machata |
4b23d2c |
debug.c \
|
|
Petr Machata |
4b23d2c |
demangle.c \
|
|
Petr Machata |
4b23d2c |
@@ -83,6 +84,7 @@ ltrace_LDADD = \
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
noinst_HEADERS = \
|
|
Petr Machata |
4b23d2c |
+ bits.h \
|
|
Petr Machata |
4b23d2c |
backend.h \
|
|
Petr Machata |
4b23d2c |
breakpoint.h \
|
|
Petr Machata |
4b23d2c |
common.h \
|
|
Petr Machata |
cb74839 |
diff --git a/README b/README
|
|
Petr Machata |
cb74839 |
index 3db5bc8..95871d1 100644
|
|
Petr Machata |
cb74839 |
--- a/README
|
|
Petr Machata |
cb74839 |
+++ b/README
|
|
Petr Machata |
cb74839 |
@@ -24,6 +24,8 @@ The following targets are currently (at least somewhat) supported.
|
|
Petr Machata |
cb74839 |
Some of them may be more or less broken in reality, it is not feasible
|
|
Petr Machata |
cb74839 |
to test each release comprehensively on each target.
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+ armv6l-*-linux-gnueabi
|
|
Petr Machata |
cb74839 |
+ armv7l-*-linux-gnueabihf
|
|
Petr Machata |
cb74839 |
i[4567]86-*-linux-gnu
|
|
Petr Machata |
cb74839 |
ia64-*-linux-gnu
|
|
Petr Machata |
cb74839 |
m68k-*-linux-gnu
|
|
Petr Machata |
cb74839 |
@@ -41,11 +43,6 @@ current status is unknown:
|
|
Petr Machata |
cb74839 |
sparc64*-*-linux-gnu
|
|
Petr Machata |
cb74839 |
alpha*-*-linux-gnu
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-Support of the following systems is known to be broken and requires
|
|
Petr Machata |
cb74839 |
-fixing:
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
- arm-*-linux-gnueabi
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
Bug Reports
|
|
Petr Machata |
cb74839 |
-----------
|
|
Petr Machata |
cb74839 |
@@ -83,7 +80,7 @@ quick one-liner), it is advisable to send an e-mail beforehand.
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-------------------------------------------------------------------------------
|
|
Petr Machata |
cb74839 |
-Copyright (C) 2012 Petr Machata <pmachata@redhat.com>
|
|
Petr Machata |
cb74839 |
+Copyright (C) 2012,2013 Petr Machata <pmachata@redhat.com>
|
|
Petr Machata |
cb74839 |
Copyright (C) 1997-2009 Juan Cespedes <cespedes@debian.org>
|
|
Petr Machata |
cb74839 |
This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
4b23d2c |
diff --git a/backend.h b/backend.h
|
|
Petr Machata |
4b23d2c |
index cfac65e..a9de3b4 100644
|
|
Petr Machata |
4b23d2c |
--- a/backend.h
|
|
Petr Machata |
4b23d2c |
+++ b/backend.h
|
|
Petr Machata |
4b23d2c |
@@ -107,10 +107,6 @@ void *get_stack_pointer(struct process *proc);
|
|
Petr Machata |
4b23d2c |
* function returns. */
|
|
Petr Machata |
4b23d2c |
void *get_return_addr(struct process *proc, void *stack_pointer);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-/* Adjust PROC so that when the current function returns, it returns
|
|
Petr Machata |
4b23d2c |
- * to ADDR. */
|
|
Petr Machata |
4b23d2c |
-void set_return_addr(struct process *proc, void *addr);
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
/* Enable breakpoint SBP in process PROC. */
|
|
Petr Machata |
4b23d2c |
void enable_breakpoint(struct process *proc, struct breakpoint *sbp);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
diff --git a/bits.c b/bits.c
|
|
Petr Machata |
4b23d2c |
new file mode 100644
|
|
Petr Machata |
4b23d2c |
index 0000000..bde2e71
|
|
Petr Machata |
4b23d2c |
--- /dev/null
|
|
Petr Machata |
4b23d2c |
+++ b/bits.c
|
|
Petr Machata |
4b23d2c |
@@ -0,0 +1,34 @@
|
|
Petr Machata |
4b23d2c |
+/*
|
|
Petr Machata |
4b23d2c |
+ * This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
+ * modify it under the terms of the GNU General Public License as
|
|
Petr Machata |
4b23d2c |
+ * published by the Free Software Foundation; either version 2 of the
|
|
Petr Machata |
4b23d2c |
+ * License, or (at your option) any later version.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is distributed in the hope that it will be useful, but
|
|
Petr Machata |
4b23d2c |
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Petr Machata |
4b23d2c |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Petr Machata |
4b23d2c |
+ * General Public License for more details.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * You should have received a copy of the GNU General Public License
|
|
Petr Machata |
4b23d2c |
+ * along with this program; if not, write to the Free Software
|
|
Petr Machata |
4b23d2c |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
4b23d2c |
+ * 02110-1301 USA
|
|
Petr Machata |
4b23d2c |
+ */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+#include "bits.h"
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* This is called rarely, and any overhead will be lost in ptrace
|
|
Petr Machata |
4b23d2c |
+ * noise, so the algorithm doesn't need to be terribly clever. For
|
|
Petr Machata |
4b23d2c |
+ * the same reason we don't bother defining the corresponding _32
|
|
Petr Machata |
4b23d2c |
+ * variant. */
|
|
Petr Machata |
4b23d2c |
+unsigned
|
|
Petr Machata |
4b23d2c |
+bitcount(uint64_t u)
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ int c = 0;
|
|
Petr Machata |
4b23d2c |
+ for (; u > 0; u &= u - 1)
|
|
Petr Machata |
4b23d2c |
+ c++;
|
|
Petr Machata |
4b23d2c |
+ return c;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
4b23d2c |
diff --git a/bits.h b/bits.h
|
|
Petr Machata |
4b23d2c |
new file mode 100644
|
|
Petr Machata |
4b23d2c |
index 0000000..7dbe478
|
|
Petr Machata |
4b23d2c |
--- /dev/null
|
|
Petr Machata |
4b23d2c |
+++ b/bits.h
|
|
Petr Machata |
4b23d2c |
@@ -0,0 +1,29 @@
|
|
Petr Machata |
4b23d2c |
+/*
|
|
Petr Machata |
4b23d2c |
+ * This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
+ * modify it under the terms of the GNU General Public License as
|
|
Petr Machata |
4b23d2c |
+ * published by the Free Software Foundation; either version 2 of the
|
|
Petr Machata |
4b23d2c |
+ * License, or (at your option) any later version.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is distributed in the hope that it will be useful, but
|
|
Petr Machata |
4b23d2c |
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Petr Machata |
4b23d2c |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Petr Machata |
4b23d2c |
+ * General Public License for more details.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * You should have received a copy of the GNU General Public License
|
|
Petr Machata |
4b23d2c |
+ * along with this program; if not, write to the Free Software
|
|
Petr Machata |
4b23d2c |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
4b23d2c |
+ * 02110-1301 USA
|
|
Petr Machata |
4b23d2c |
+ */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+#ifndef _BITS_H_
|
|
Petr Machata |
4b23d2c |
+#define _BITS_H_
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+#include <stdint.h>
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* Count bits in U that are 1. */
|
|
Petr Machata |
4b23d2c |
+unsigned bitcount(uint64_t u);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+#endif /* _BITS_H_ */
|
|
Petr Machata |
4b23d2c |
diff --git a/breakpoint.h b/breakpoint.h
|
|
Petr Machata |
4b23d2c |
index 18af7a9..963cc66 100644
|
|
Petr Machata |
4b23d2c |
--- a/breakpoint.h
|
|
Petr Machata |
4b23d2c |
+++ b/breakpoint.h
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
@@ -82,11 +82,10 @@ int breakpoint_init(struct breakpoint *bp, struct process *proc,
|
|
Petr Machata |
4b23d2c |
arch_addr_t addr, struct library_symbol *libsym);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
/* Make a clone of breakpoint BP into the area of memory pointed to by
|
|
Petr Machata |
4b23d2c |
- * RETP. The original breakpoint was assigned to process OLD_PROC,
|
|
Petr Machata |
4b23d2c |
- * the cloned breakpoint will be attached to process NEW_PROC.
|
|
Petr Machata |
4b23d2c |
+ * RETP. Symbols of cloned breakpoint are looked up in NEW_PROC.
|
|
Petr Machata |
4b23d2c |
* Returns 0 on success or a negative value on failure. */
|
|
Petr Machata |
4b23d2c |
int breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
|
|
Petr Machata |
4b23d2c |
- struct breakpoint *bp, struct process *old_proc);
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *bp);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
/* Set callbacks. If CBS is non-NULL, then BP->cbs shall be NULL. */
|
|
Petr Machata |
4b23d2c |
void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);
|
|
Petr Machata |
4b23d2c |
diff --git a/breakpoints.c b/breakpoints.c
|
|
Petr Machata |
4b23d2c |
index 8db4e26..7b5530a 100644
|
|
Petr Machata |
4b23d2c |
--- a/breakpoints.c
|
|
Petr Machata |
4b23d2c |
+++ b/breakpoints.c
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2006,2007,2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2006,2007,2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
@@ -117,7 +117,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
|
|
Petr Machata |
4b23d2c |
#endif
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
static void
|
|
Petr Machata |
4b23d2c |
-breakpoint_init_base(struct breakpoint *bp, struct process *proc,
|
|
Petr Machata |
4b23d2c |
+breakpoint_init_base(struct breakpoint *bp,
|
|
Petr Machata |
4b23d2c |
arch_addr_t addr, struct library_symbol *libsym)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
bp->cbs = NULL;
|
|
Petr Machata |
4b23d2c |
@@ -135,7 +135,7 @@ int
|
|
Petr Machata |
4b23d2c |
breakpoint_init(struct breakpoint *bp, struct process *proc,
|
|
Petr Machata |
4b23d2c |
arch_addr_t addr, struct library_symbol *libsym)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
- breakpoint_init_base(bp, proc, addr, libsym);
|
|
Petr Machata |
4b23d2c |
+ breakpoint_init_base(bp, addr, libsym);
|
|
Petr Machata |
4b23d2c |
return arch_breakpoint_init(proc, bp);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
@@ -157,7 +157,7 @@ breakpoint_destroy(struct breakpoint *bp)
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
int
|
|
Petr Machata |
4b23d2c |
breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
|
|
Petr Machata |
4b23d2c |
- struct breakpoint *bp, struct process *old_proc)
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *bp)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
struct library_symbol *libsym = NULL;
|
|
Petr Machata |
4b23d2c |
if (bp->libsym != NULL) {
|
|
Petr Machata |
4b23d2c |
@@ -165,7 +165,7 @@ breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
|
|
Petr Machata |
4b23d2c |
assert(rc == 0);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- breakpoint_init_base(retp, new_proc, bp->addr, libsym);
|
|
Petr Machata |
4b23d2c |
+ breakpoint_init_base(retp, bp->addr, libsym);
|
|
Petr Machata |
4b23d2c |
memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value));
|
|
Petr Machata |
4b23d2c |
retp->enabled = bp->enabled;
|
|
Petr Machata |
4b23d2c |
if (arch_breakpoint_clone(retp, bp) < 0)
|
|
Petr Machata |
4b23d2c |
@@ -211,6 +211,22 @@ insert_breakpoint(struct process *proc, void *addr,
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
assert(addr != 0);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
+ /* We first create the breakpoint to find out what it's real
|
|
Petr Machata |
4b23d2c |
+ * address is. This makes a difference on ARM.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * XXX The real problem here is that to create a return
|
|
Petr Machata |
4b23d2c |
+ * breakpoint ltrace calls get_return_addr and then
|
|
Petr Machata |
4b23d2c |
+ * insert_breakpoint. So get_return_addr needs to encode all
|
|
Petr Machata |
4b23d2c |
+ * the information necessary for breakpoint_init into the
|
|
Petr Machata |
4b23d2c |
+ * address itself, so ADDR is potentially mangled. We filter
|
|
Petr Machata |
4b23d2c |
+ * the noise out by first creating the breakpoint on stack,
|
|
Petr Machata |
4b23d2c |
+ * and then looking at the address of the created breakpoint.
|
|
Petr Machata |
4b23d2c |
+ * Replacing get_return_addr with get_return_breakpoint might
|
|
Petr Machata |
4b23d2c |
+ * be a better solution. */
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint bp;
|
|
Petr Machata |
4b23d2c |
+ if (breakpoint_init(&bp, proc, addr, libsym) < 0)
|
|
Petr Machata |
4b23d2c |
+ return NULL;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
/* XXX what we need to do instead is have a list of
|
|
Petr Machata |
4b23d2c |
* breakpoints that are enabled at this address. The
|
|
Petr Machata |
4b23d2c |
* following works if every breakpoint is the same and there's
|
|
Petr Machata |
4b23d2c |
@@ -218,20 +234,21 @@ insert_breakpoint(struct process *proc, void *addr,
|
|
Petr Machata |
4b23d2c |
* will suffice, about the only realistic case where we need
|
|
Petr Machata |
4b23d2c |
* to have more than one breakpoint per address is return from
|
|
Petr Machata |
4b23d2c |
* a recursive library call. */
|
|
Petr Machata |
4b23d2c |
- struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
|
|
Petr Machata |
4b23d2c |
- if (sbp == NULL) {
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *sbp = dict_find_entry(leader->breakpoints, bp.addr);
|
|
Petr Machata |
4b23d2c |
+ if (sbp != NULL) {
|
|
Petr Machata |
4b23d2c |
+ breakpoint_destroy(&bp);
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ //fprintf(stderr, "new BP at %p\n", addr);
|
|
Petr Machata |
4b23d2c |
sbp = malloc(sizeof(*sbp));
|
|
Petr Machata |
4b23d2c |
- if (sbp == NULL
|
|
Petr Machata |
4b23d2c |
- || breakpoint_init(sbp, proc, addr, libsym) < 0) {
|
|
Petr Machata |
4b23d2c |
- free(sbp);
|
|
Petr Machata |
4b23d2c |
- return NULL;
|
|
Petr Machata |
4b23d2c |
- }
|
|
Petr Machata |
4b23d2c |
- if (proc_add_breakpoint(leader, sbp) < 0) {
|
|
Petr Machata |
4b23d2c |
+ if (sbp == NULL) {
|
|
Petr Machata |
4b23d2c |
fail:
|
|
Petr Machata |
4b23d2c |
- breakpoint_destroy(sbp);
|
|
Petr Machata |
4b23d2c |
free(sbp);
|
|
Petr Machata |
4b23d2c |
+ breakpoint_destroy(&bp);
|
|
Petr Machata |
4b23d2c |
return NULL;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
+ memcpy(sbp, &bp, sizeof(*sbp));
|
|
Petr Machata |
4b23d2c |
+ if (proc_add_breakpoint(leader, sbp) < 0)
|
|
Petr Machata |
4b23d2c |
+ goto fail;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
if (breakpoint_turn_on(sbp, proc) < 0) {
|
|
Petr Machata |
4b23d2c |
diff --git a/handle_event.c b/handle_event.c
|
|
Petr Machata |
4b23d2c |
index 9dbb696..1eaea09 100644
|
|
Petr Machata |
4b23d2c |
--- a/handle_event.c
|
|
Petr Machata |
4b23d2c |
+++ b/handle_event.c
|
|
Petr Machata |
4b23d2c |
@@ -607,7 +607,6 @@ handle_breakpoint(Event *event)
|
|
Petr Machata |
4b23d2c |
calc_time_spent(event->proc);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
- event->proc->return_addr = brk_addr;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
struct library_symbol *libsym =
|
|
Petr Machata |
4b23d2c |
event->proc->callstack[i].c_un.libfunc;
|
|
Petr Machata |
4b23d2c |
@@ -663,8 +662,6 @@ handle_breakpoint(Event *event)
|
|
Petr Machata |
4b23d2c |
if (event->proc->state != STATE_IGNORED
|
|
Petr Machata |
4b23d2c |
&& sbp->libsym != NULL) {
|
|
Petr Machata |
4b23d2c |
event->proc->stack_pointer = get_stack_pointer(event->proc);
|
|
Petr Machata |
4b23d2c |
- event->proc->return_addr =
|
|
Petr Machata |
4b23d2c |
- get_return_addr(event->proc, event->proc->stack_pointer);
|
|
Petr Machata |
4b23d2c |
callstack_push_symfunc(event->proc, sbp->libsym);
|
|
Petr Machata |
4b23d2c |
output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
@@ -722,9 +719,11 @@ callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
|
|
Petr Machata |
4b23d2c |
elem->is_syscall = 0;
|
|
Petr Machata |
4b23d2c |
elem->c_un.libfunc = sym;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- elem->return_addr = proc->return_addr;
|
|
Petr Machata |
4b23d2c |
- if (elem->return_addr)
|
|
Petr Machata |
4b23d2c |
- insert_breakpoint(proc, elem->return_addr, NULL);
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t return_addr = get_return_addr(proc, proc->stack_pointer);
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *rbp = NULL;
|
|
Petr Machata |
4b23d2c |
+ if (return_addr != 0)
|
|
Petr Machata |
4b23d2c |
+ rbp = insert_breakpoint(proc, return_addr, NULL);
|
|
Petr Machata |
4b23d2c |
+ elem->return_addr = rbp != NULL ? rbp->addr : 0;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
if (opt_T || options.summary) {
|
|
Petr Machata |
4b23d2c |
struct timezone tz;
|
|
Petr Machata |
4b23d2c |
diff --git a/lens_default.c b/lens_default.c
|
|
Petr Machata |
4b23d2c |
index ed3d0e1..47b8c70 100644
|
|
Petr Machata |
4b23d2c |
--- a/lens_default.c
|
|
Petr Machata |
4b23d2c |
+++ b/lens_default.c
|
|
Petr Machata |
4b23d2c |
@@ -29,6 +29,7 @@
|
|
Petr Machata |
4b23d2c |
#include <stdio.h>
|
|
Petr Machata |
4b23d2c |
#include <string.h>
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
+#include "bits.h"
|
|
Petr Machata |
4b23d2c |
#include "proc.h"
|
|
Petr Machata |
4b23d2c |
#include "lens_default.h"
|
|
Petr Machata |
4b23d2c |
#include "value.h"
|
|
Petr Machata |
4b23d2c |
@@ -608,15 +609,6 @@ out_bits(FILE *stream, size_t low, size_t high)
|
|
Petr Machata |
4b23d2c |
return fprintf(stream, "%zd-%zd", low, high);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-static unsigned
|
|
Petr Machata |
4b23d2c |
-bitcount(unsigned u)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- int c = 0;
|
|
Petr Machata |
4b23d2c |
- for (; u > 0; u &= u - 1)
|
|
Petr Machata |
4b23d2c |
- c++;
|
|
Petr Machata |
4b23d2c |
- return c;
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
static int
|
|
Petr Machata |
4b23d2c |
bitvect_lens_format_cb(struct lens *lens, FILE *stream,
|
|
Petr Machata |
4b23d2c |
struct value *value, struct value_dict *arguments)
|
|
Petr Machata |
cb74839 |
diff --git a/ltrace-elf.c b/ltrace-elf.c
|
|
Petr Machata |
cb74839 |
index 1d0f769..af25f8f 100644
|
|
Petr Machata |
cb74839 |
--- a/ltrace-elf.c
|
|
Petr Machata |
cb74839 |
+++ b/ltrace-elf.c
|
|
Petr Machata |
cb74839 |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
cb74839 |
/*
|
|
Petr Machata |
cb74839 |
* This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
- * Copyright (C) 2006,2010,2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2006,2010,2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2010 Zachary T Welch, CodeSourcery
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2010 Joe Damato
|
|
Petr Machata |
cb74839 |
* Copyright (C) 1997,1998,2001,2004,2007,2008,2009 Juan Cespedes
|
|
Petr Machata |
cb74839 |
@@ -141,8 +141,9 @@ elf_get_section_if(struct ltelf *lte, Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr,
|
|
Petr Machata |
cb74839 |
return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
- return -1;
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+ *tgt_sec = NULL;
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
static int
|
|
Petr Machata |
cb74839 |
@@ -203,23 +204,23 @@ elf_get_section_named(struct ltelf *lte, const char *name,
|
|
Petr Machata |
cb74839 |
&name_p, &data);
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-static int
|
|
Petr Machata |
cb74839 |
-need_data(Elf_Data *data, GElf_Xword offset, GElf_Xword size)
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword size)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
assert(data != NULL);
|
|
Petr Machata |
cb74839 |
if (data->d_size < size || offset > data->d_size - size) {
|
|
Petr Machata |
cb74839 |
debug(1, "Not enough data to read %"PRId64"-byte value"
|
|
Petr Machata |
cb74839 |
" at offset %"PRId64".", size, offset);
|
|
Petr Machata |
cb74839 |
- return -1;
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
- return 0;
|
|
Petr Machata |
cb74839 |
+ return 1;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
#define DEF_READER(NAME, SIZE) \
|
|
Petr Machata |
cb74839 |
int \
|
|
Petr Machata |
cb74839 |
NAME(Elf_Data *data, GElf_Xword offset, uint##SIZE##_t *retp) \
|
|
Petr Machata |
cb74839 |
{ \
|
|
Petr Machata |
cb74839 |
- if (!need_data(data, offset, SIZE / 8) < 0) \
|
|
Petr Machata |
cb74839 |
+ if (!elf_can_read_next(data, offset, SIZE / 8)) \
|
|
Petr Machata |
cb74839 |
return -1; \
|
|
Petr Machata |
cb74839 |
\
|
|
Petr Machata |
cb74839 |
if (data->d_buf == NULL) /* NODATA section */ { \
|
|
Petr Machata |
cb74839 |
@@ -236,12 +237,63 @@ need_data(Elf_Data *data, GElf_Xword offset, GElf_Xword size)
|
|
Petr Machata |
cb74839 |
return 0; \
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+DEF_READER(elf_read_u8, 8)
|
|
Petr Machata |
cb74839 |
DEF_READER(elf_read_u16, 16)
|
|
Petr Machata |
cb74839 |
DEF_READER(elf_read_u32, 32)
|
|
Petr Machata |
cb74839 |
DEF_READER(elf_read_u64, 64)
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
#undef DEF_READER
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+#define DEF_READER(NAME, SIZE) \
|
|
Petr Machata |
cb74839 |
+ int \
|
|
Petr Machata |
cb74839 |
+ NAME(Elf_Data *data, GElf_Xword *offset, uint##SIZE##_t *retp) \
|
|
Petr Machata |
cb74839 |
+ { \
|
|
Petr Machata |
cb74839 |
+ int rc = elf_read_u##SIZE(data, *offset, retp); \
|
|
Petr Machata |
cb74839 |
+ if (rc < 0) \
|
|
Petr Machata |
cb74839 |
+ return rc; \
|
|
Petr Machata |
cb74839 |
+ *offset += SIZE / 8; \
|
|
Petr Machata |
cb74839 |
+ return 0; \
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+DEF_READER(elf_read_next_u8, 8)
|
|
Petr Machata |
cb74839 |
+DEF_READER(elf_read_next_u16, 16)
|
|
Petr Machata |
cb74839 |
+DEF_READER(elf_read_next_u32, 32)
|
|
Petr Machata |
cb74839 |
+DEF_READER(elf_read_next_u64, 64)
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#undef DEF_READER
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ uint64_t result = 0;
|
|
Petr Machata |
cb74839 |
+ int shift = 0;
|
|
Petr Machata |
cb74839 |
+ int size = 8 * sizeof result;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ while (1) {
|
|
Petr Machata |
cb74839 |
+ uint8_t byte;
|
|
Petr Machata |
cb74839 |
+ if (elf_read_next_u8(data, offset, &byte) < 0)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ uint8_t payload = byte & 0x7f;
|
|
Petr Machata |
cb74839 |
+ result |= (uint64_t)payload << shift;
|
|
Petr Machata |
cb74839 |
+ shift += 7;
|
|
Petr Machata |
cb74839 |
+ if (shift > size && byte != 0x1)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+ if ((byte & 0x80) == 0)
|
|
Petr Machata |
cb74839 |
+ break;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (retp != NULL)
|
|
Petr Machata |
cb74839 |
+ *retp = result;
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+elf_read_uleb128(Elf_Data *data, GElf_Xword offset, uint64_t *retp)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ return elf_read_next_uleb128(data, &offset, retp);
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
int
|
|
Petr Machata |
cb74839 |
open_elf(struct ltelf *lte, const char *filename)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
diff --git a/ltrace-elf.h b/ltrace-elf.h
|
|
Petr Machata |
cb74839 |
index b76d1eb..178258b 100644
|
|
Petr Machata |
cb74839 |
--- a/ltrace-elf.h
|
|
Petr Machata |
cb74839 |
+++ b/ltrace-elf.h
|
|
Petr Machata |
cb74839 |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
cb74839 |
/*
|
|
Petr Machata |
cb74839 |
* This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
- * Copyright (C) 2006,2010,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2006,2010,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2010 Zachary T Welch
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2001,2004,2007,2009 Juan Cespedes
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
cb74839 |
@@ -95,6 +95,12 @@ int elf_get_sym_info(struct ltelf *lte, const char *filename,
|
|
Petr Machata |
cb74839 |
size_t sym_index, GElf_Rela *rela, GElf_Sym *sym);
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
Elf_Data *elf_loaddata(Elf_Scn *scn, GElf_Shdr *shdr);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+/* The following three look for sections based on various criteria.
|
|
Petr Machata |
cb74839 |
+ * They return 0 if there was no error, or a negative value if there
|
|
Petr Machata |
cb74839 |
+ * was. If the section was found, it is returned in *TGT_SEC, and the
|
|
Petr Machata |
cb74839 |
+ * header is stored te TGT_SHDR. If it wasn't found, *TGT_SEC is set
|
|
Petr Machata |
cb74839 |
+ * to NULL. */
|
|
Petr Machata |
cb74839 |
int elf_get_section_covering(struct ltelf *lte, GElf_Addr addr,
|
|
Petr Machata |
cb74839 |
Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr);
|
|
Petr Machata |
cb74839 |
int elf_get_section_type(struct ltelf *lte, GElf_Word type,
|
|
Petr Machata |
cb74839 |
@@ -102,13 +108,29 @@ int elf_get_section_type(struct ltelf *lte, GElf_Word type,
|
|
Petr Machata |
cb74839 |
int elf_get_section_named(struct ltelf *lte, const char *name,
|
|
Petr Machata |
cb74839 |
Elf_Scn **tgt_sec, GElf_Shdr *tgt_shdr);
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-/* Read, respectively, 2, 4, or 8 bytes from Elf data at given OFFSET,
|
|
Petr Machata |
cb74839 |
- * and store it in *RETP. Returns 0 on success or a negative value if
|
|
Petr Machata |
cb74839 |
- * there's not enough data. */
|
|
Petr Machata |
cb74839 |
+/* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given
|
|
Petr Machata |
cb74839 |
+ * OFFSET, and store it in *RETP. Returns 0 on success or a negative
|
|
Petr Machata |
cb74839 |
+ * value if there's not enough data. */
|
|
Petr Machata |
cb74839 |
+int elf_read_u8(Elf_Data *data, GElf_Xword offset, uint8_t *retp);
|
|
Petr Machata |
cb74839 |
int elf_read_u16(Elf_Data *data, GElf_Xword offset, uint16_t *retp);
|
|
Petr Machata |
cb74839 |
int elf_read_u32(Elf_Data *data, GElf_Xword offset, uint32_t *retp);
|
|
Petr Machata |
cb74839 |
int elf_read_u64(Elf_Data *data, GElf_Xword offset, uint64_t *retp);
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+/* Read at most 64-bit quantity recorded in an ULEB128 variable-length
|
|
Petr Machata |
cb74839 |
+ * encoding. */
|
|
Petr Machata |
cb74839 |
+int elf_read_uleb128(Elf_Data *data, GElf_Xword offset, uint64_t *retp);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+/* These are same as above, but update *OFFSET with the width
|
|
Petr Machata |
cb74839 |
+ * of read datum. */
|
|
Petr Machata |
cb74839 |
+int elf_read_next_u8(Elf_Data *data, GElf_Xword *offset, uint8_t *retp);
|
|
Petr Machata |
cb74839 |
+int elf_read_next_u16(Elf_Data *data, GElf_Xword *offset, uint16_t *retp);
|
|
Petr Machata |
cb74839 |
+int elf_read_next_u32(Elf_Data *data, GElf_Xword *offset, uint32_t *retp);
|
|
Petr Machata |
cb74839 |
+int elf_read_next_u64(Elf_Data *data, GElf_Xword *offset, uint64_t *retp);
|
|
Petr Machata |
cb74839 |
+int elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+/* Return whether there's AMOUNT more bytes after OFFSET in DATA. */
|
|
Petr Machata |
cb74839 |
+int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
#if __WORDSIZE == 32
|
|
Petr Machata |
cb74839 |
#define PRI_ELF_ADDR PRIx32
|
|
Petr Machata |
cb74839 |
#define GELF_ADDR_CAST(x) (void *)(uint32_t)(x)
|
|
Petr Machata |
4b23d2c |
diff --git a/output.c b/output.c
|
|
Petr Machata |
4b23d2c |
index fe62bb4..f046df8 100644
|
|
Petr Machata |
4b23d2c |
--- a/output.c
|
|
Petr Machata |
4b23d2c |
+++ b/output.c
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2010 Joe Damato
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1997,1998,1999,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Paul Gilliam, IBM Corporation
|
|
Petr Machata |
4b23d2c |
@@ -119,12 +119,15 @@ begin_of_line(struct process *proc, int is_func, int indent)
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
if (opt_i) {
|
|
Petr Machata |
4b23d2c |
- if (is_func)
|
|
Petr Machata |
4b23d2c |
+ if (is_func) {
|
|
Petr Machata |
4b23d2c |
+ struct callstack_element *stel
|
|
Petr Machata |
4b23d2c |
+ = &proc->callstack[proc->callstack_depth - 1];
|
|
Petr Machata |
4b23d2c |
current_column += fprintf(options.output, "[%p] ",
|
|
Petr Machata |
4b23d2c |
- proc->return_addr);
|
|
Petr Machata |
4b23d2c |
- else
|
|
Petr Machata |
4b23d2c |
+ stel->return_addr);
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
current_column += fprintf(options.output, "[%p] ",
|
|
Petr Machata |
4b23d2c |
proc->instruction_pointer);
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
if (options.indent > 0 && indent) {
|
|
Petr Machata |
4b23d2c |
output_indent(proc);
|
|
Petr Machata |
4b23d2c |
diff --git a/proc.c b/proc.c
|
|
Petr Machata |
4b23d2c |
index db3f645..7dfde7c 100644
|
|
Petr Machata |
4b23d2c |
--- a/proc.c
|
|
Petr Machata |
4b23d2c |
+++ b/proc.c
|
|
Petr Machata |
4b23d2c |
@@ -314,8 +314,7 @@ clone_single_bp(void *key, void *value, void *u)
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
struct breakpoint *clone = malloc(sizeof(*clone));
|
|
Petr Machata |
4b23d2c |
if (clone == NULL
|
|
Petr Machata |
4b23d2c |
- || breakpoint_clone(clone, data->new_proc,
|
|
Petr Machata |
4b23d2c |
- bp, data->old_proc) < 0) {
|
|
Petr Machata |
4b23d2c |
+ || breakpoint_clone(clone, data->new_proc, bp) < 0) {
|
|
Petr Machata |
4b23d2c |
fail:
|
|
Petr Machata |
4b23d2c |
free(clone);
|
|
Petr Machata |
4b23d2c |
data->error = -1;
|
|
Petr Machata |
4b23d2c |
@@ -1050,6 +1049,7 @@ proc_each_symbol(struct process *proc, struct library_symbol *start_after,
|
|
Petr Machata |
4b23d2c |
return 0; \
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
+DEF_READER(proc_read_8, 8)
|
|
Petr Machata |
4b23d2c |
DEF_READER(proc_read_16, 16)
|
|
Petr Machata |
4b23d2c |
DEF_READER(proc_read_32, 32)
|
|
Petr Machata |
4b23d2c |
DEF_READER(proc_read_64, 64)
|
|
Petr Machata |
4b23d2c |
diff --git a/proc.h b/proc.h
|
|
Petr Machata |
4b23d2c |
index 04c0ef7..03708dc 100644
|
|
Petr Machata |
4b23d2c |
--- a/proc.h
|
|
Petr Machata |
4b23d2c |
+++ b/proc.h
|
|
Petr Machata |
4b23d2c |
@@ -65,7 +65,7 @@ struct callstack_element {
|
|
Petr Machata |
4b23d2c |
struct library_symbol * libfunc;
|
|
Petr Machata |
4b23d2c |
} c_un;
|
|
Petr Machata |
4b23d2c |
int is_syscall;
|
|
Petr Machata |
4b23d2c |
- void * return_addr;
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t return_addr;
|
|
Petr Machata |
4b23d2c |
struct timeval time_spent;
|
|
Petr Machata |
4b23d2c |
struct fetch_context *fetch_context;
|
|
Petr Machata |
4b23d2c |
struct value_dict *arguments;
|
|
Petr Machata |
4b23d2c |
@@ -106,7 +106,6 @@ struct process {
|
|
Petr Machata |
4b23d2c |
/* Arch-dependent: */
|
|
Petr Machata |
4b23d2c |
void * instruction_pointer;
|
|
Petr Machata |
4b23d2c |
void * stack_pointer; /* To get return addr, args... */
|
|
Petr Machata |
4b23d2c |
- void * return_addr;
|
|
Petr Machata |
4b23d2c |
void * arch_ptr;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
/* XXX We would like to replace this with a pointer to ABI
|
|
Petr Machata |
4b23d2c |
@@ -116,11 +115,6 @@ struct process {
|
|
Petr Machata |
4b23d2c |
short e_machine;
|
|
Petr Machata |
4b23d2c |
char e_class;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- /* XXX this shoudl go to ARM's arch_process_data. */
|
|
Petr Machata |
4b23d2c |
-#ifdef __arm__
|
|
Petr Machata |
4b23d2c |
- int thumb_mode; /* ARM execution mode: 0: ARM, 1: Thumb */
|
|
Petr Machata |
4b23d2c |
-#endif
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
#if defined(HAVE_LIBUNWIND)
|
|
Petr Machata |
4b23d2c |
/* libunwind address space */
|
|
Petr Machata |
4b23d2c |
unw_addr_space_t unwind_as;
|
|
Petr Machata |
4b23d2c |
@@ -254,10 +248,11 @@ struct library_symbol *proc_each_symbol
|
|
Petr Machata |
4b23d2c |
enum callback_status (*cb)(struct library_symbol *, void *),
|
|
Petr Machata |
4b23d2c |
void *data);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-/* Read 16, 32 or 64-bit quantity located at ADDR in PROC. The
|
|
Petr Machata |
4b23d2c |
+/* Read 8, 16, 32 or 64-bit quantity located at ADDR in PROC. The
|
|
Petr Machata |
4b23d2c |
* resulting value is stored in *LP. 0 is returned on success or a
|
|
Petr Machata |
4b23d2c |
* negative value on failure. This uses umovebytes under the hood
|
|
Petr Machata |
4b23d2c |
* (see backend.h). */
|
|
Petr Machata |
4b23d2c |
+int proc_read_8(struct process *proc, arch_addr_t addr, uint8_t *lp);
|
|
Petr Machata |
4b23d2c |
int proc_read_16(struct process *proc, arch_addr_t addr, uint16_t *lp);
|
|
Petr Machata |
4b23d2c |
int proc_read_32(struct process *proc, arch_addr_t addr, uint32_t *lp);
|
|
Petr Machata |
4b23d2c |
int proc_read_64(struct process *proc, arch_addr_t addr, uint64_t *lp);
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
|
|
Petr Machata |
4b23d2c |
index c197225..9ccd8f2 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/alpha/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/alpha/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
@@ -58,9 +59,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, 26 /* RA */ , addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/Makefile.am b/sysdeps/linux-gnu/arm/Makefile.am
|
|
Petr Machata |
cb74839 |
index 385424c..2c180c6 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/arm/Makefile.am
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/Makefile.am
|
|
Petr Machata |
4b23d2c |
@@ -1,4 +1,5 @@
|
|
Petr Machata |
4b23d2c |
# This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+# Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix
|
|
Petr Machata |
4b23d2c |
#
|
|
Petr Machata |
4b23d2c |
# This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
@@ -16,21 +17,11 @@
|
|
Petr Machata |
4b23d2c |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
4b23d2c |
# 02110-1301 USA
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-noinst_LTLIBRARIES = \
|
|
Petr Machata |
4b23d2c |
- ../libcpu.la
|
|
Petr Machata |
4b23d2c |
+noinst_LTLIBRARIES = ../libcpu.la
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-___libcpu_la_SOURCES = \
|
|
Petr Machata |
4b23d2c |
- breakpoint.c \
|
|
Petr Machata |
4b23d2c |
- plt.c \
|
|
Petr Machata |
4b23d2c |
- regs.c \
|
|
Petr Machata |
4b23d2c |
- trace.c
|
|
Petr Machata |
cb74839 |
+___libcpu_la_SOURCES = breakpoint.c fetch.c plt.c regs.c trace.c
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-noinst_HEADERS = \
|
|
Petr Machata |
4b23d2c |
- arch.h \
|
|
Petr Machata |
4b23d2c |
- arch_syscallent.h \
|
|
Petr Machata |
4b23d2c |
- ptrace.h \
|
|
Petr Machata |
4b23d2c |
- signalent.h \
|
|
Petr Machata |
4b23d2c |
- syscallent.h
|
|
Petr Machata |
4b23d2c |
+noinst_HEADERS = arch.h arch_syscallent.h ptrace.h regs.h signalent.h \
|
|
Petr Machata |
4b23d2c |
+ syscallent.h
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-MAINTAINERCLEANFILES = \
|
|
Petr Machata |
4b23d2c |
- Makefile.in
|
|
Petr Machata |
4b23d2c |
+MAINTAINERCLEANFILES = Makefile.in
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
|
|
Petr Machata |
cb74839 |
index 291443a..58a7fdf 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/arm/arch.h
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/arch.h
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2004,2008 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
cb74839 |
@@ -18,6 +19,9 @@
|
|
Petr Machata |
cb74839 |
* 02110-1301 USA
|
|
Petr Machata |
cb74839 |
*/
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+#ifndef LTRACE_ARM_ARCH_H
|
|
Petr Machata |
cb74839 |
+#define LTRACE_ARM_ARCH_H
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
#define ARCH_HAVE_ENABLE_BREAKPOINT 1
|
|
Petr Machata |
cb74839 |
#define ARCH_HAVE_DISABLE_BREAKPOINT 1
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
@@ -31,7 +35,24 @@
|
|
Petr Machata |
4b23d2c |
#define LT_ELFCLASS ELFCLASS32
|
|
Petr Machata |
4b23d2c |
#define LT_ELF_MACHINE EM_ARM
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
+#define ARCH_HAVE_SW_SINGLESTEP
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_FETCH_ARG
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_FETCH_PACK
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_SIZEOF
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_ALIGNOF
|
|
Petr Machata |
4b23d2c |
#define ARCH_HAVE_BREAKPOINT_DATA
|
|
Petr Machata |
4b23d2c |
struct arch_breakpoint_data {
|
|
Petr Machata |
4b23d2c |
int thumb_mode;
|
|
Petr Machata |
cb74839 |
};
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_LTELF_DATA
|
|
Petr Machata |
cb74839 |
+struct arch_ltelf_data {
|
|
Petr Machata |
cb74839 |
+ /* We have this only for the hooks. */
|
|
Petr Machata |
cb74839 |
+};
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#define ARCH_HAVE_LIBRARY_DATA
|
|
Petr Machata |
cb74839 |
+struct arch_library_data {
|
|
Petr Machata |
cb74839 |
+ unsigned int hardfp:1;
|
|
Petr Machata |
cb74839 |
+};
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#endif /* LTRACE_ARM_ARCH_H */
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
|
|
Petr Machata |
4b23d2c |
index 2fb9578..fcd43a7 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/arm/breakpoint.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/breakpoint.c
|
|
Petr Machata |
4b23d2c |
@@ -94,14 +94,11 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
|
|
Petr Machata |
4b23d2c |
int
|
|
Petr Machata |
4b23d2c |
arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
- /* XXX That uintptr_t cast is there temporarily until
|
|
Petr Machata |
4b23d2c |
- * arch_addr_t becomes integral type. */
|
|
Petr Machata |
4b23d2c |
- int thumb_mode = ((uintptr_t)sbp->addr) & 1;
|
|
Petr Machata |
4b23d2c |
- if (thumb_mode)
|
|
Petr Machata |
4b23d2c |
- sbp->addr = (void *)((uintptr_t)sbp->addr & ~1);
|
|
Petr Machata |
4b23d2c |
- sbp->arch.thumb_mode = thumb_mode | proc->thumb_mode;
|
|
Petr Machata |
4b23d2c |
- /* XXX This doesn't seem like it belongs here. */
|
|
Petr Machata |
4b23d2c |
- proc->thumb_mode = 0;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ sbp->arch.thumb_mode = ((uintptr_t)sbp->addr) & 1;
|
|
Petr Machata |
4b23d2c |
+ if (sbp->arch.thumb_mode)
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ sbp->addr = (arch_addr_t)((uintptr_t)sbp->addr & ~1);
|
|
Petr Machata |
4b23d2c |
return 0;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
cb74839 |
diff --git a/sysdeps/linux-gnu/arm/fetch.c b/sysdeps/linux-gnu/arm/fetch.c
|
|
Petr Machata |
cb74839 |
new file mode 100644
|
|
Petr Machata |
cb74839 |
index 0000000..0064d91
|
|
Petr Machata |
cb74839 |
--- /dev/null
|
|
Petr Machata |
cb74839 |
+++ b/sysdeps/linux-gnu/arm/fetch.c
|
|
Petr Machata |
cb74839 |
@@ -0,0 +1,529 @@
|
|
Petr Machata |
cb74839 |
+/*
|
|
Petr Machata |
cb74839 |
+ * This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ *
|
|
Petr Machata |
cb74839 |
+ * This program is free software; you can redistribute it and/or
|
|
Petr Machata |
cb74839 |
+ * modify it under the terms of the GNU General Public License as
|
|
Petr Machata |
cb74839 |
+ * published by the Free Software Foundation; either version 2 of the
|
|
Petr Machata |
cb74839 |
+ * License, or (at your option) any later version.
|
|
Petr Machata |
cb74839 |
+ *
|
|
Petr Machata |
cb74839 |
+ * This program is distributed in the hope that it will be useful, but
|
|
Petr Machata |
cb74839 |
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Petr Machata |
cb74839 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Petr Machata |
cb74839 |
+ * General Public License for more details.
|
|
Petr Machata |
cb74839 |
+ *
|
|
Petr Machata |
cb74839 |
+ * You should have received a copy of the GNU General Public License
|
|
Petr Machata |
cb74839 |
+ * along with this program; if not, write to the Free Software
|
|
Petr Machata |
cb74839 |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
cb74839 |
+ * 02110-1301 USA
|
|
Petr Machata |
cb74839 |
+ */
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#include <sys/ptrace.h>
|
|
Petr Machata |
cb74839 |
+#include <asm/ptrace.h>
|
|
Petr Machata |
cb74839 |
+#include <assert.h>
|
|
Petr Machata |
cb74839 |
+#include <elf.h>
|
|
Petr Machata |
cb74839 |
+#include <libelf.h>
|
|
Petr Machata |
cb74839 |
+#include <stdint.h>
|
|
Petr Machata |
cb74839 |
+#include <stdio.h>
|
|
Petr Machata |
cb74839 |
+#include <stdlib.h>
|
|
Petr Machata |
cb74839 |
+#include <string.h>
|
|
Petr Machata |
cb74839 |
+#include <stdbool.h>
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+#include "backend.h"
|
|
Petr Machata |
cb74839 |
+#include "fetch.h"
|
|
Petr Machata |
cb74839 |
+#include "library.h"
|
|
Petr Machata |
cb74839 |
+#include "ltrace-elf.h"
|
|
Petr Machata |
cb74839 |
+#include "proc.h"
|
|
Petr Machata |
cb74839 |
+#include "ptrace.h"
|
|
Petr Machata |
cb74839 |
+#include "regs.h"
|
|
Petr Machata |
cb74839 |
+#include "type.h"
|
|
Petr Machata |
cb74839 |
+#include "value.h"
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+static int
|
|
Petr Machata |
cb74839 |
+get_hardfp(uint64_t abi_vfp_args)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ if (abi_vfp_args == 2)
|
|
Petr Machata |
cb74839 |
+ fprintf(stderr,
|
|
Petr Machata |
cb74839 |
+ "Tag_ABI_VFP_args value 2 (tool chain-specific "
|
|
Petr Machata |
cb74839 |
+ "conventions) not supported.\n");
|
|
Petr Machata |
cb74839 |
+ return abi_vfp_args == 1;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+arch_elf_init(struct ltelf *lte, struct library *lib)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ /* Nothing in this section is strictly critical. It's not
|
|
Petr Machata |
cb74839 |
+ * that much of a deal if we fail to guess right whether the
|
|
Petr Machata |
cb74839 |
+ * ABI is softfp or hardfp. */
|
|
Petr Machata |
cb74839 |
+ unsigned hardfp = 0;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ Elf_Scn *scn;
|
|
Petr Machata |
cb74839 |
+ Elf_Data *data;
|
|
Petr Machata |
cb74839 |
+ GElf_Shdr shdr;
|
|
Petr Machata |
cb74839 |
+ if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
|
|
Petr Machata |
cb74839 |
+ || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
|
|
Petr Machata |
cb74839 |
+ fprintf(stderr,
|
|
Petr Machata |
cb74839 |
+ "Error when obtaining ARM attribute section: %s\n",
|
|
Petr Machata |
cb74839 |
+ elf_errmsg(-1));
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ } else if (scn != NULL && data != NULL) {
|
|
Petr Machata |
cb74839 |
+ GElf_Xword offset = 0;
|
|
Petr Machata |
cb74839 |
+ uint8_t version;
|
|
Petr Machata |
cb74839 |
+ if (elf_read_next_u8(data, &offset, &version) < 0) {
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+ } else if (version != 'A') {
|
|
Petr Machata |
cb74839 |
+ fprintf(stderr, "Unsupported ARM attribute section "
|
|
Petr Machata |
cb74839 |
+ "version %d ('%c').\n", version, version);
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ do {
|
|
Petr Machata |
cb74839 |
+ const char signature[] = "aeabi";
|
|
Petr Machata |
cb74839 |
+ /* N.B. LEN is including the length field
|
|
Petr Machata |
cb74839 |
+ * itself. */
|
|
Petr Machata |
cb74839 |
+ uint32_t sec_len;
|
|
Petr Machata |
cb74839 |
+ if (elf_read_u32(data, offset, &sec_len) < 0
|
|
Petr Machata |
cb74839 |
+ || !elf_can_read_next(data, offset, sec_len)) {
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ const GElf_Xword next_offset = offset + sec_len;
|
|
Petr Machata |
cb74839 |
+ offset += 4;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (sec_len < 4 + sizeof signature
|
|
Petr Machata |
cb74839 |
+ || strcmp(signature, data->d_buf + offset) != 0)
|
|
Petr Machata |
cb74839 |
+ goto skip;
|
|
Petr Machata |
cb74839 |
+ offset += sizeof signature;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ const GElf_Xword offset0 = offset;
|
|
Petr Machata |
cb74839 |
+ uint64_t tag;
|
|
Petr Machata |
cb74839 |
+ uint32_t sub_len;
|
|
Petr Machata |
cb74839 |
+ if (elf_read_next_uleb128(data, &offset, &tag) < 0
|
|
Petr Machata |
cb74839 |
+ || elf_read_next_u32(data, &offset, &sub_len) < 0
|
|
Petr Machata |
cb74839 |
+ || !elf_can_read_next(data, offset0, sub_len))
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (tag != 1)
|
|
Petr Machata |
cb74839 |
+ /* IHI0045D_ABI_addenda: "section and
|
|
Petr Machata |
cb74839 |
+ * symbol attributes are deprecated
|
|
Petr Machata |
cb74839 |
+ * [...] consumers are permitted to
|
|
Petr Machata |
cb74839 |
+ * ignore them." */
|
|
Petr Machata |
cb74839 |
+ goto skip;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ while (offset < offset0 + sub_len) {
|
|
Petr Machata |
cb74839 |
+ if (elf_read_next_uleb128(data,
|
|
Petr Machata |
cb74839 |
+ &offset, &tag) < 0)
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ switch (tag) {
|
|
Petr Machata |
cb74839 |
+ uint64_t v;
|
|
Petr Machata |
cb74839 |
+ case 6: /* Tag_CPU_arch */
|
|
Petr Machata |
cb74839 |
+ case 7: /* Tag_CPU_arch_profile */
|
|
Petr Machata |
cb74839 |
+ case 8: /* Tag_ARM_ISA_use */
|
|
Petr Machata |
cb74839 |
+ case 9: /* Tag_THUMB_ISA_use */
|
|
Petr Machata |
cb74839 |
+ case 10: /* Tag_FP_arch */
|
|
Petr Machata |
cb74839 |
+ case 11: /* Tag_WMMX_arch */
|
|
Petr Machata |
cb74839 |
+ case 12: /* Tag_Advanced_SIMD_arch */
|
|
Petr Machata |
cb74839 |
+ case 13: /* Tag_PCS_config */
|
|
Petr Machata |
cb74839 |
+ case 14: /* Tag_ABI_PCS_R9_use */
|
|
Petr Machata |
cb74839 |
+ case 15: /* Tag_ABI_PCS_RW_data */
|
|
Petr Machata |
cb74839 |
+ case 16: /* Tag_ABI_PCS_RO_data */
|
|
Petr Machata |
cb74839 |
+ case 17: /* Tag_ABI_PCS_GOT_use */
|
|
Petr Machata |
cb74839 |
+ case 18: /* Tag_ABI_PCS_wchar_t */
|
|
Petr Machata |
cb74839 |
+ case 19: /* Tag_ABI_FP_rounding */
|
|
Petr Machata |
cb74839 |
+ case 20: /* Tag_ABI_FP_denormal */
|
|
Petr Machata |
cb74839 |
+ case 21: /* Tag_ABI_FP_exceptions */
|
|
Petr Machata |
cb74839 |
+ case 22: /* Tag_ABI_FP_user_exceptions */
|
|
Petr Machata |
cb74839 |
+ case 23: /* Tag_ABI_FP_number_model */
|
|
Petr Machata |
cb74839 |
+ case 24: /* Tag_ABI_align_needed */
|
|
Petr Machata |
cb74839 |
+ case 25: /* Tag_ABI_align_preserved */
|
|
Petr Machata |
cb74839 |
+ case 26: /* Tag_ABI_enum_size */
|
|
Petr Machata |
cb74839 |
+ case 27: /* Tag_ABI_HardFP_use */
|
|
Petr Machata |
cb74839 |
+ case 28: /* Tag_ABI_VFP_args */
|
|
Petr Machata |
cb74839 |
+ case 29: /* Tag_ABI_WMMX_args */
|
|
Petr Machata |
cb74839 |
+ case 30: /* Tag_ABI_optimization_goals */
|
|
Petr Machata |
cb74839 |
+ case 31: /* Tag_ABI_FP_optimization_goals */
|
|
Petr Machata |
cb74839 |
+ case 32: /* Tag_compatibility */
|
|
Petr Machata |
cb74839 |
+ case 34: /* Tag_CPU_unaligned_access */
|
|
Petr Machata |
cb74839 |
+ case 36: /* Tag_FP_HP_extension */
|
|
Petr Machata |
cb74839 |
+ case 38: /* Tag_ABI_FP_16bit_format */
|
|
Petr Machata |
cb74839 |
+ case 42: /* Tag_MPextension_use */
|
|
Petr Machata |
cb74839 |
+ case 70: /* Tag_MPextension_use as well */
|
|
Petr Machata |
cb74839 |
+ case 44: /* Tag_DIV_use */
|
|
Petr Machata |
cb74839 |
+ case 64: /* Tag_nodefaults */
|
|
Petr Machata |
cb74839 |
+ case 66: /* Tag_T2EE_use */
|
|
Petr Machata |
cb74839 |
+ case 68: /* Tag_Virtualization_use */
|
|
Petr Machata |
cb74839 |
+ uleb128:
|
|
Petr Machata |
cb74839 |
+ if (elf_read_next_uleb128
|
|
Petr Machata |
cb74839 |
+ (data, &offset, &v) < 0)
|
|
Petr Machata |
cb74839 |
+ goto done;
|
|
Petr Machata |
cb74839 |
+ if (tag == 28)
|
|
Petr Machata |
cb74839 |
+ hardfp = get_hardfp(v);
|
|
Petr Machata |
cb74839 |
+ if (tag != 32)
|
|
Petr Machata |
cb74839 |
+ continue;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* Tag 32 has two arguments,
|
|
Petr Machata |
cb74839 |
+ * fall through. */
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case 4: /* Tag_CPU_raw_name */
|
|
Petr Machata |
cb74839 |
+ case 5: /* Tag_CPU_name */
|
|
Petr Machata |
cb74839 |
+ case 65: /* Tag_also_compatible_with */
|
|
Petr Machata |
cb74839 |
+ case 67: /* Tag_conformance */
|
|
Petr Machata |
cb74839 |
+ ntbs:
|
|
Petr Machata |
cb74839 |
+ offset += strlen(data->d_buf
|
|
Petr Machata |
cb74839 |
+ + offset) + 1;
|
|
Petr Machata |
cb74839 |
+ continue;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* Handle unknown tags in a generic
|
|
Petr Machata |
cb74839 |
+ * manner, if possible. */
|
|
Petr Machata |
cb74839 |
+ if (tag <= 32) {
|
|
Petr Machata |
cb74839 |
+ fprintf(stderr,
|
|
Petr Machata |
cb74839 |
+ "Unknown tag %lld "
|
|
Petr Machata |
cb74839 |
+ "at offset %#llx "
|
|
Petr Machata |
cb74839 |
+ "of ARM attribute section.",
|
|
Petr Machata |
cb74839 |
+ tag, offset);
|
|
Petr Machata |
cb74839 |
+ goto skip;
|
|
Petr Machata |
cb74839 |
+ } else if (tag % 2 == 0) {
|
|
Petr Machata |
cb74839 |
+ goto uleb128;
|
|
Petr Machata |
cb74839 |
+ } else {
|
|
Petr Machata |
cb74839 |
+ goto ntbs;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ skip:
|
|
Petr Machata |
cb74839 |
+ offset = next_offset;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ } while (elf_can_read_next(data, offset, 1));
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+done:
|
|
Petr Machata |
cb74839 |
+ lib->arch.hardfp = hardfp;
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_elf_destroy(struct ltelf *lte)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_library_init(struct library *lib)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_library_destroy(struct library *lib)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_library_clone(struct library *retp, struct library *lib)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ retp->arch = lib->arch;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+enum {
|
|
Petr Machata |
cb74839 |
+ /* How many (double) VFP registers the AAPCS uses for
|
|
Petr Machata |
cb74839 |
+ * parameter passing. */
|
|
Petr Machata |
cb74839 |
+ NUM_VFP_REGS = 8,
|
|
Petr Machata |
cb74839 |
+};
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+struct fetch_context {
|
|
Petr Machata |
cb74839 |
+ struct pt_regs regs;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ struct {
|
|
Petr Machata |
cb74839 |
+ union {
|
|
Petr Machata |
cb74839 |
+ double d[32];
|
|
Petr Machata |
cb74839 |
+ float s[64];
|
|
Petr Machata |
cb74839 |
+ };
|
|
Petr Machata |
cb74839 |
+ uint32_t fpscr;
|
|
Petr Machata |
cb74839 |
+ } fpregs;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* VFP register allocation. ALLOC.S tracks whether the
|
|
Petr Machata |
cb74839 |
+ * corresponding FPREGS.S register is taken, ALLOC.D the same
|
|
Petr Machata |
cb74839 |
+ * for FPREGS.D. We only track 8 (16) registers, because
|
|
Petr Machata |
cb74839 |
+ * that's what the ABI uses for parameter passing. */
|
|
Petr Machata |
cb74839 |
+ union {
|
|
Petr Machata |
cb74839 |
+ int16_t d[NUM_VFP_REGS];
|
|
Petr Machata |
cb74839 |
+ int8_t s[NUM_VFP_REGS * 2];
|
|
Petr Machata |
cb74839 |
+ } alloc;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ unsigned ncrn;
|
|
Petr Machata |
cb74839 |
+ arch_addr_t sp;
|
|
Petr Machata |
cb74839 |
+ arch_addr_t nsaa;
|
|
Petr Machata |
cb74839 |
+ arch_addr_t ret_struct;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ bool hardfp:1;
|
|
Petr Machata |
cb74839 |
+ bool in_varargs:1;
|
|
Petr Machata |
cb74839 |
+};
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+static int
|
|
Petr Machata |
cb74839 |
+fetch_register_banks(struct process *proc, struct fetch_context *context)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ if (ptrace(PTRACE_GETREGS, proc->pid, NULL, &context->regs) == -1)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (context->hardfp
|
|
Petr Machata |
cb74839 |
+ && ptrace(PTRACE_GETVFPREGS, proc->pid,
|
|
Petr Machata |
cb74839 |
+ NULL, &context->fpregs) == -1)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ context->ncrn = 0;
|
|
Petr Machata |
cb74839 |
+ context->nsaa = context->sp = get_stack_pointer(proc);
|
|
Petr Machata |
cb74839 |
+ memset(&context->alloc, 0, sizeof(context->alloc));
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+struct fetch_context *
|
|
Petr Machata |
cb74839 |
+arch_fetch_arg_init(enum tof type, struct process *proc,
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *ret_info)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ struct fetch_context *context = malloc(sizeof(*context));
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ {
|
|
Petr Machata |
cb74839 |
+ struct process *mainp = proc;
|
|
Petr Machata |
cb74839 |
+ while (mainp->libraries == NULL && mainp->parent != NULL)
|
|
Petr Machata |
cb74839 |
+ mainp = mainp->parent;
|
|
Petr Machata |
cb74839 |
+ context->hardfp = mainp->libraries->arch.hardfp;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (context == NULL
|
|
Petr Machata |
cb74839 |
+ || fetch_register_banks(proc, context) < 0) {
|
|
Petr Machata |
cb74839 |
+ free(context);
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (ret_info->type == ARGTYPE_STRUCT
|
|
Petr Machata |
cb74839 |
+ || ret_info->type == ARGTYPE_ARRAY) {
|
|
Petr Machata |
cb74839 |
+ size_t sz = type_sizeof(proc, ret_info);
|
|
Petr Machata |
cb74839 |
+ assert(sz != (size_t)-1);
|
|
Petr Machata |
cb74839 |
+ if (sz > 4) {
|
|
Petr Machata |
cb74839 |
+ /* XXX double cast */
|
|
Petr Machata |
cb74839 |
+ context->ret_struct
|
|
Petr Machata |
cb74839 |
+ = (arch_addr_t)context->regs.uregs[0];
|
|
Petr Machata |
cb74839 |
+ context->ncrn++;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ return context;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+struct fetch_context *
|
|
Petr Machata |
cb74839 |
+arch_fetch_arg_clone(struct process *proc,
|
|
Petr Machata |
cb74839 |
+ struct fetch_context *context)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ struct fetch_context *clone = malloc(sizeof(*context));
|
|
Petr Machata |
cb74839 |
+ if (clone == NULL)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+ *clone = *context;
|
|
Petr Machata |
cb74839 |
+ return clone;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+/* 0 is success, 1 is failure, negative value is an error. */
|
|
Petr Machata |
cb74839 |
+static int
|
|
Petr Machata |
cb74839 |
+pass_in_vfp(struct fetch_context *ctx, struct process *proc,
|
|
Petr Machata |
cb74839 |
+ enum arg_type type, size_t count, struct value *valuep)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ assert(type == ARGTYPE_FLOAT || type == ARGTYPE_DOUBLE);
|
|
Petr Machata |
cb74839 |
+ unsigned max = type == ARGTYPE_DOUBLE ? NUM_VFP_REGS : 2 * NUM_VFP_REGS;
|
|
Petr Machata |
cb74839 |
+ if (count > max)
|
|
Petr Machata |
cb74839 |
+ return 1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ size_t i;
|
|
Petr Machata |
cb74839 |
+ size_t j;
|
|
Petr Machata |
cb74839 |
+ for (i = 0; i < max; ++i) {
|
|
Petr Machata |
cb74839 |
+ for (j = i; j < i + count; ++j)
|
|
Petr Machata |
cb74839 |
+ if ((type == ARGTYPE_DOUBLE && ctx->alloc.d[j] != 0)
|
|
Petr Machata |
cb74839 |
+ || (type == ARGTYPE_FLOAT && ctx->alloc.s[j] != 0))
|
|
Petr Machata |
cb74839 |
+ goto next;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* Found COUNT consecutive unallocated registers at I. */
|
|
Petr Machata |
cb74839 |
+ const size_t sz = (type == ARGTYPE_FLOAT ? 4 : 8) * count;
|
|
Petr Machata |
cb74839 |
+ unsigned char *data = value_reserve(valuep, sz);
|
|
Petr Machata |
cb74839 |
+ if (data == NULL)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ for (j = i; j < i + count; ++j)
|
|
Petr Machata |
cb74839 |
+ if (type == ARGTYPE_DOUBLE)
|
|
Petr Machata |
cb74839 |
+ ctx->alloc.d[j] = -1;
|
|
Petr Machata |
cb74839 |
+ else
|
|
Petr Machata |
cb74839 |
+ ctx->alloc.s[j] = -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (type == ARGTYPE_DOUBLE)
|
|
Petr Machata |
cb74839 |
+ memcpy(data, ctx->fpregs.d + i, sz);
|
|
Petr Machata |
cb74839 |
+ else
|
|
Petr Machata |
cb74839 |
+ memcpy(data, ctx->fpregs.s + i, sz);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ next:
|
|
Petr Machata |
cb74839 |
+ continue;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ return 1;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+/* 0 is success, 1 is failure, negative value is an error. */
|
|
Petr Machata |
cb74839 |
+static int
|
|
Petr Machata |
cb74839 |
+consider_vfp(struct fetch_context *ctx, struct process *proc,
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *info, struct value *valuep)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *float_info = NULL;
|
|
Petr Machata |
cb74839 |
+ size_t hfa_size = 1;
|
|
Petr Machata |
cb74839 |
+ if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE)
|
|
Petr Machata |
cb74839 |
+ float_info = info;
|
|
Petr Machata |
cb74839 |
+ else
|
|
Petr Machata |
cb74839 |
+ float_info = type_get_hfa_type(info, &hfa_size);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (float_info != NULL && hfa_size <= 4)
|
|
Petr Machata |
cb74839 |
+ return pass_in_vfp(ctx, proc, float_info->type,
|
|
Petr Machata |
cb74839 |
+ hfa_size, valuep);
|
|
Petr Machata |
cb74839 |
+ return 1;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
Petr Machata |
cb74839 |
+ struct process *proc,
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *info, struct value *valuep)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ const size_t sz = type_sizeof(proc, info);
|
|
Petr Machata |
cb74839 |
+ assert(sz != (size_t)-1);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (ctx->hardfp && !ctx->in_varargs) {
|
|
Petr Machata |
cb74839 |
+ int rc;
|
|
Petr Machata |
cb74839 |
+ if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1)
|
|
Petr Machata |
cb74839 |
+ return rc;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* IHI0042E_aapcs: If the argument requires double-word
|
|
Petr Machata |
cb74839 |
+ * alignment (8-byte), the NCRN is rounded up to the next even
|
|
Petr Machata |
cb74839 |
+ * register number. */
|
|
Petr Machata |
cb74839 |
+ const size_t al = type_alignof(proc, info);
|
|
Petr Machata |
cb74839 |
+ assert(al != (size_t)-1);
|
|
Petr Machata |
cb74839 |
+ if (al == 8)
|
|
Petr Machata |
cb74839 |
+ ctx->ncrn = ((ctx->ncrn + 1) / 2) * 2;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* If the size in words of the argument is not more than r4
|
|
Petr Machata |
cb74839 |
+ * minus NCRN, the argument is copied into core registers,
|
|
Petr Machata |
cb74839 |
+ * starting at the NCRN. */
|
|
Petr Machata |
cb74839 |
+ /* If the NCRN is less than r4 and the NSAA is equal to the
|
|
Petr Machata |
cb74839 |
+ * SP, the argument is split between core registers and the
|
|
Petr Machata |
cb74839 |
+ * stack. */
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ const size_t words = (sz + 3) / 4;
|
|
Petr Machata |
cb74839 |
+ if (ctx->ncrn < 4 && ctx->nsaa == ctx->sp) {
|
|
Petr Machata |
cb74839 |
+ unsigned char *data = value_reserve(valuep, words * 4);
|
|
Petr Machata |
cb74839 |
+ if (data == NULL)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+ size_t i;
|
|
Petr Machata |
cb74839 |
+ for (i = 0; i < words && ctx->ncrn < 4; ++i) {
|
|
Petr Machata |
cb74839 |
+ memcpy(data, &ctx->regs.uregs[ctx->ncrn++], 4);
|
|
Petr Machata |
cb74839 |
+ data += 4;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ const size_t rest = (words - i) * 4;
|
|
Petr Machata |
cb74839 |
+ if (rest > 0) {
|
|
Petr Machata |
cb74839 |
+ umovebytes(proc, ctx->nsaa, data, rest);
|
|
Petr Machata |
cb74839 |
+ ctx->nsaa += rest;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ assert(ctx->ncrn == 4);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ /* If the argument required double-word alignment (8-byte),
|
|
Petr Machata |
cb74839 |
+ * then the NSAA is rounded up to the next double-word
|
|
Petr Machata |
cb74839 |
+ * address. */
|
|
Petr Machata |
cb74839 |
+ if (al == 8)
|
|
Petr Machata |
cb74839 |
+ /* XXX double cast. */
|
|
Petr Machata |
cb74839 |
+ ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 7) / 8) * 8);
|
|
Petr Machata |
cb74839 |
+ else
|
|
Petr Machata |
cb74839 |
+ ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 3) / 4) * 4);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ value_in_inferior(valuep, ctx->nsaa);
|
|
Petr Machata |
cb74839 |
+ ctx->nsaa += sz;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+arch_fetch_retval(struct fetch_context *ctx, enum tof type,
|
|
Petr Machata |
cb74839 |
+ struct process *proc, struct arg_type_info *info,
|
|
Petr Machata |
cb74839 |
+ struct value *valuep)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ if (fetch_register_banks(proc, ctx) < 0)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ if (ctx->hardfp && !ctx->in_varargs) {
|
|
Petr Machata |
cb74839 |
+ int rc;
|
|
Petr Machata |
cb74839 |
+ if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1)
|
|
Petr Machata |
cb74839 |
+ return rc;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ size_t sz = type_sizeof(proc, info);
|
|
Petr Machata |
cb74839 |
+ assert(sz != (size_t)-1);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ switch (info->type) {
|
|
Petr Machata |
cb74839 |
+ unsigned char *data;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_VOID:
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_FLOAT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_DOUBLE:
|
|
Petr Machata |
cb74839 |
+ if (ctx->hardfp && !ctx->in_varargs) {
|
|
Petr Machata |
cb74839 |
+ unsigned char *data = value_reserve(valuep, sz);
|
|
Petr Machata |
cb74839 |
+ if (data == NULL)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+ memmove(data, &ctx->fpregs, sz);
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ goto pass_in_registers;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_ARRAY:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_STRUCT:
|
|
Petr Machata |
cb74839 |
+ if (sz > 4) {
|
|
Petr Machata |
cb74839 |
+ value_in_inferior(valuep, ctx->ret_struct);
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ /* Fall through. */
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_CHAR:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_SHORT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_USHORT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_INT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_UINT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_LONG:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_ULONG:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_POINTER:
|
|
Petr Machata |
cb74839 |
+ pass_in_registers:
|
|
Petr Machata |
cb74839 |
+ if ((data = value_reserve(valuep, sz)) == NULL)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+ memmove(data, ctx->regs.uregs, sz);
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ assert(info->type != info->type);
|
|
Petr Machata |
cb74839 |
+ abort();
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_fetch_arg_done(struct fetch_context *context)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ free(context);
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+arch_fetch_param_pack_start(struct fetch_context *context,
|
|
Petr Machata |
cb74839 |
+ enum param_pack_flavor ppflavor)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ if (ppflavor == PARAM_PACK_VARARGS)
|
|
Petr Machata |
cb74839 |
+ context->in_varargs = true;
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void
|
|
Petr Machata |
cb74839 |
+arch_fetch_param_pack_end(struct fetch_context *context)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ context->in_varargs = false;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c
|
|
Petr Machata |
cb74839 |
index 377df62..e9e825e 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/arm/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
@@ -24,9 +25,11 @@
|
|
Petr Machata |
4b23d2c |
#include <sys/types.h>
|
|
Petr Machata |
4b23d2c |
#include <sys/ptrace.h>
|
|
Petr Machata |
4b23d2c |
#include <asm/ptrace.h>
|
|
Petr Machata |
4b23d2c |
+#include <errno.h>
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
#include "proc.h"
|
|
Petr Machata |
4b23d2c |
#include "common.h"
|
|
Petr Machata |
4b23d2c |
+#include "regs.h"
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
|
|
Petr Machata |
4b23d2c |
# define PTRACE_PEEKUSER PTRACE_PEEKUSR
|
|
Petr Machata |
cb74839 |
@@ -36,50 +39,119 @@
|
|
Petr Machata |
cb74839 |
# define PTRACE_POKEUSER PTRACE_POKEUSR
|
|
Petr Machata |
4b23d2c |
#endif
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
cb74839 |
-#define off_pc ((void *)60)
|
|
Petr Machata |
4b23d2c |
-#define off_lr ((void *)56)
|
|
Petr Machata |
cb74839 |
-#define off_sp ((void *)52)
|
|
Petr Machata |
4b23d2c |
+int
|
|
Petr Machata |
4b23d2c |
+arm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp)
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ errno = 0;
|
|
Petr Machata |
4b23d2c |
+ long l = ptrace(PTRACE_PEEKUSER, proc->pid, (void *)(reg * 4L), 0);
|
|
Petr Machata |
4b23d2c |
+ if (l == -1 && errno != 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ *lp = (uint32_t)l;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-void *
|
|
Petr Machata |
cb74839 |
-get_instruction_pointer(struct process *proc)
|
|
Petr Machata |
cb74839 |
+int
|
|
Petr Machata |
cb74839 |
+arm_set_register(struct process *proc, enum arm_register reg, uint32_t lp)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
|
|
Petr Machata |
cb74839 |
+ return ptrace(PTRACE_PEEKUSER, proc->pid,
|
|
Petr Machata |
cb74839 |
+ (void *)(reg * 4L), (void *)lp);
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-void
|
|
Petr Machata |
cb74839 |
-set_instruction_pointer(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
+int
|
|
Petr Machata |
4b23d2c |
+arm_get_register_offpc(struct process *proc, enum arm_register reg,
|
|
Petr Machata |
4b23d2c |
+ uint32_t *lp)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
- ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, reg, lp) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ if (reg == ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ *lp += 8;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-void *
|
|
Petr Machata |
cb74839 |
-get_stack_pointer(struct process *proc)
|
|
Petr Machata |
4b23d2c |
+int
|
|
Petr Machata |
4b23d2c |
+arm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t pc_val, uint32_t *lp)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
|
|
Petr Machata |
4b23d2c |
+ enum arm_register rm = BITS(inst, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ unsigned long shifttype = BITS(inst, 5, 6);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t shift;
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst, 4)) {
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register_offpc(proc, BITS(inst, 8, 11), &shift) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ shift &= 0xff;
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ shift = BITS(inst, 7, 11);
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t res;
|
|
Petr Machata |
4b23d2c |
+ if (rm == ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ /* xxx double cast */
|
|
Petr Machata |
4b23d2c |
+ res = (uintptr_t)pc_val + (BIT(inst, 4) ? 12 : 8);
|
|
Petr Machata |
4b23d2c |
+ else if (arm_get_register(proc, rm, &res) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ switch (shifttype) {
|
|
Petr Machata |
4b23d2c |
+ case 0: /* LSL */
|
|
Petr Machata |
4b23d2c |
+ res = shift >= 32 ? 0 : res << shift;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 1: /* LSR */
|
|
Petr Machata |
4b23d2c |
+ res = shift >= 32 ? 0 : res >> shift;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 2: /* ASR */
|
|
Petr Machata |
4b23d2c |
+ if (shift >= 32)
|
|
Petr Machata |
4b23d2c |
+ shift = 31;
|
|
Petr Machata |
4b23d2c |
+ res = ((res & 0x80000000L)
|
|
Petr Machata |
4b23d2c |
+ ? ~((~res) >> shift) : res >> shift);
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 3: /* ROR/RRX */
|
|
Petr Machata |
4b23d2c |
+ shift &= 31;
|
|
Petr Machata |
4b23d2c |
+ if (shift == 0)
|
|
Petr Machata |
4b23d2c |
+ res = (res >> 1) | (carry ? 0x80000000L : 0);
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ res = (res >> shift) | (res << (32 - shift));
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ *lp = res & 0xffffffff;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-/* really, this is given the *stack_pointer expecting
|
|
Petr Machata |
4b23d2c |
- * a CISC architecture; in our case, we don't need that */
|
|
Petr Machata |
4b23d2c |
-void *
|
|
Petr Machata |
4b23d2c |
-get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
cb74839 |
+static arch_addr_t
|
|
Petr Machata |
cb74839 |
+get_register_nocheck(struct process *proc, enum arm_register r)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
4b23d2c |
- long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
- /* Remember & unset the thumb mode bit. XXX This is really a
|
|
Petr Machata |
4b23d2c |
- * bit of a hack, as we assume that the following
|
|
Petr Machata |
4b23d2c |
- * insert_breakpoint call will be related to this address.
|
|
Petr Machata |
4b23d2c |
- * This interface should really be get_return_breakpoint, or
|
|
Petr Machata |
4b23d2c |
- * maybe install_return_breakpoint. */
|
|
Petr Machata |
4b23d2c |
- proc->thumb_mode = addr & 1;
|
|
Petr Machata |
4b23d2c |
- if (proc->thumb_mode)
|
|
Petr Machata |
4b23d2c |
- addr &= ~1;
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
- return (void *)addr;
|
|
Petr Machata |
cb74839 |
+ uint32_t reg;
|
|
Petr Machata |
cb74839 |
+ if (arm_get_register(proc, r, ®) < 0)
|
|
Petr Machata |
cb74839 |
+ /* XXX double cast. */
|
|
Petr Machata |
cb74839 |
+ return (arch_addr_t)-1;
|
|
Petr Machata |
cb74839 |
+ /* XXX double cast. */
|
|
Petr Machata |
cb74839 |
+ return (arch_addr_t)(uintptr_t)reg;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+arch_addr_t
|
|
Petr Machata |
cb74839 |
+get_instruction_pointer(struct process *proc)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ return get_register_nocheck(proc, ARM_REG_PC);
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
cb74839 |
+set_instruction_pointer(struct process *proc, arch_addr_t addr)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ /* XXX double cast. */
|
|
Petr Machata |
cb74839 |
+ arm_set_register(proc, ARM_REG_PC, (uint32_t)addr);
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+void *
|
|
Petr Machata |
cb74839 |
+get_stack_pointer(struct process *proc)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ return get_register_nocheck(proc, ARM_REG_SP);
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
4b23d2c |
+arch_addr_t
|
|
Petr Machata |
4b23d2c |
+get_return_addr(struct process *proc, arch_addr_t stack_pointer)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
- long iaddr = (int)addr | proc->thumb_mode;
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr);
|
|
Petr Machata |
cb74839 |
+ return get_register_nocheck(proc, ARM_REG_LR);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/regs.h b/sysdeps/linux-gnu/arm/regs.h
|
|
Petr Machata |
4b23d2c |
new file mode 100644
|
|
Petr Machata |
cb74839 |
index 0000000..f9a5a86
|
|
Petr Machata |
4b23d2c |
--- /dev/null
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/regs.h
|
|
Petr Machata |
cb74839 |
@@ -0,0 +1,47 @@
|
|
Petr Machata |
4b23d2c |
+/*
|
|
Petr Machata |
4b23d2c |
+ * This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
+ * modify it under the terms of the GNU General Public License as
|
|
Petr Machata |
4b23d2c |
+ * published by the Free Software Foundation; either version 2 of the
|
|
Petr Machata |
4b23d2c |
+ * License, or (at your option) any later version.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * This program is distributed in the hope that it will be useful, but
|
|
Petr Machata |
4b23d2c |
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Petr Machata |
4b23d2c |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Petr Machata |
4b23d2c |
+ * General Public License for more details.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * You should have received a copy of the GNU General Public License
|
|
Petr Machata |
4b23d2c |
+ * along with this program; if not, write to the Free Software
|
|
Petr Machata |
4b23d2c |
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
4b23d2c |
+ * 02110-1301 USA
|
|
Petr Machata |
4b23d2c |
+ */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+#define SUBMASK(x) ((1L << ((x) + 1)) - 1)
|
|
Petr Machata |
4b23d2c |
+#define BIT(obj,st) (((obj) >> (st)) & 1)
|
|
Petr Machata |
4b23d2c |
+#define BITS(obj,st,fn) (((obj) >> (st)) & SUBMASK((fn) - (st)))
|
|
Petr Machata |
4b23d2c |
+#define SBITS(obj,st,fn) \
|
|
Petr Machata |
4b23d2c |
+ ((long) (BITS(obj,st,fn) | ((long) BIT(obj,fn) * ~ SUBMASK(fn - st))))
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+enum arm_register {
|
|
Petr Machata |
cb74839 |
+ ARM_REG_R7 = 7,
|
|
Petr Machata |
cb74839 |
+ ARM_REG_IP = 12,
|
|
Petr Machata |
4b23d2c |
+ ARM_REG_SP = 13,
|
|
Petr Machata |
4b23d2c |
+ ARM_REG_LR = 14,
|
|
Petr Machata |
4b23d2c |
+ ARM_REG_PC = 15,
|
|
Petr Machata |
4b23d2c |
+ ARM_REG_CPSR = 16,
|
|
Petr Machata |
4b23d2c |
+};
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* Write value of register REG to *LP. Return 0 on success or a
|
|
Petr Machata |
4b23d2c |
+ * negative value on failure. */
|
|
Petr Machata |
4b23d2c |
+int arm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* Same as above, but if REG==ARM_REG_PC, it returns the value +8. */
|
|
Petr Machata |
4b23d2c |
+int arm_get_register_offpc(struct process *proc, enum arm_register reg,
|
|
Petr Machata |
4b23d2c |
+ uint32_t *lp);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* Same as arm_get_register, but shift is performed depending on
|
|
Petr Machata |
4b23d2c |
+ * instruction INST. */
|
|
Petr Machata |
4b23d2c |
+int arm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t pc, uint32_t *lp);
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
|
|
Petr Machata |
cb74839 |
index fbbf676..5e51e91 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/arm/trace.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/arm/trace.c
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
cb74839 |
@@ -29,10 +29,13 @@
|
|
Petr Machata |
4b23d2c |
#include <sys/ptrace.h>
|
|
Petr Machata |
4b23d2c |
#include <asm/ptrace.h>
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-#include "proc.h"
|
|
Petr Machata |
4b23d2c |
+#include "bits.h"
|
|
Petr Machata |
4b23d2c |
#include "common.h"
|
|
Petr Machata |
4b23d2c |
+#include "proc.h"
|
|
Petr Machata |
4b23d2c |
#include "output.h"
|
|
Petr Machata |
4b23d2c |
#include "ptrace.h"
|
|
Petr Machata |
4b23d2c |
+#include "regs.h"
|
|
Petr Machata |
cb74839 |
+#include "type.h"
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
|
|
Petr Machata |
4b23d2c |
# define PTRACE_PEEKUSER PTRACE_PEEKUSR
|
|
Petr Machata |
cb74839 |
@@ -42,11 +45,6 @@
|
|
Petr Machata |
cb74839 |
# define PTRACE_POKEUSER PTRACE_POKEUSR
|
|
Petr Machata |
cb74839 |
#endif
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
cb74839 |
-#define off_r0 ((void *)0)
|
|
Petr Machata |
cb74839 |
-#define off_r7 ((void *)28)
|
|
Petr Machata |
cb74839 |
-#define off_ip ((void *)48)
|
|
Petr Machata |
cb74839 |
-#define off_pc ((void *)60)
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
4b23d2c |
void
|
|
Petr Machata |
4b23d2c |
get_arch_dep(struct process *proc)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
@@ -68,18 +66,24 @@ syscall_p(struct process *proc, int status, int *sysnum)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
if (WIFSTOPPED(status)
|
|
Petr Machata |
cb74839 |
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
|
|
Petr Machata |
cb74839 |
- /* get the user's pc (plus 8) */
|
|
Petr Machata |
cb74839 |
- unsigned pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
|
|
Petr Machata |
cb74839 |
+ uint32_t pc, ip;
|
|
Petr Machata |
cb74839 |
+ if (arm_get_register(proc, ARM_REG_PC, &pc) < 0
|
|
Petr Machata |
cb74839 |
+ || arm_get_register(proc, ARM_REG_IP, &ip) < 0)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
pc = pc - 4;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
/* fetch the SWI instruction */
|
|
Petr Machata |
cb74839 |
unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid,
|
|
Petr Machata |
cb74839 |
(void *)pc, 0);
|
|
Petr Machata |
cb74839 |
- int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
cb74839 |
if (insn == 0xef000000 || insn == 0x0f000000
|
|
Petr Machata |
cb74839 |
|| (insn & 0xffff0000) == 0xdf000000) {
|
|
Petr Machata |
cb74839 |
/* EABI syscall */
|
|
Petr Machata |
cb74839 |
- *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0);
|
|
Petr Machata |
cb74839 |
+ uint32_t r7;
|
|
Petr Machata |
cb74839 |
+ if (arm_get_register(proc, ARM_REG_R7, &r7) < 0)
|
|
Petr Machata |
cb74839 |
+ return -1;
|
|
Petr Machata |
cb74839 |
+ *sysnum = r7;
|
|
Petr Machata |
cb74839 |
} else if ((insn & 0xfff00000) == 0xef900000) {
|
|
Petr Machata |
cb74839 |
/* old ABI syscall */
|
|
Petr Machata |
cb74839 |
*sysnum = insn & 0xfffff;
|
|
Petr Machata |
cb74839 |
@@ -105,47 +109,605 @@ syscall_p(struct process *proc, int status, int *sysnum)
|
|
Petr Machata |
4b23d2c |
return 0;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-long
|
|
Petr Machata |
cb74839 |
-gimme_arg(enum tof type, struct process *proc, int arg_num,
|
|
Petr Machata |
cb74839 |
- struct arg_type_info *info)
|
|
Petr Machata |
4b23d2c |
+static arch_addr_t
|
|
Petr Machata |
4b23d2c |
+arm_branch_dest(const arch_addr_t pc, const uint32_t insn)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
- proc_archdep *a = (proc_archdep *) proc->arch_ptr;
|
|
Petr Machata |
4b23d2c |
+ /* Bits 0-23 are signed immediate value. */
|
|
Petr Machata |
4b23d2c |
+ return pc + ((((insn & 0xffffff) ^ 0x800000) - 0x800000) << 2) + 8;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
- if (arg_num == -1) { /* return value */
|
|
Petr Machata |
cb74839 |
- return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
|
|
Petr Machata |
cb74839 |
- }
|
|
Petr Machata |
4b23d2c |
+/* Addresses for calling Thumb functions have the bit 0 set.
|
|
Petr Machata |
4b23d2c |
+ Here are some macros to test, set, or clear bit 0 of addresses. */
|
|
Petr Machata |
4b23d2c |
+/* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+#define IS_THUMB_ADDR(addr) ((uintptr_t)(addr) & 1)
|
|
Petr Machata |
4b23d2c |
+#define MAKE_THUMB_ADDR(addr) ((arch_addr_t)((uintptr_t)(addr) | 1))
|
|
Petr Machata |
4b23d2c |
+#define UNMAKE_THUMB_ADDR(addr) ((arch_addr_t)((uintptr_t)(addr) & ~1))
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
- /* deal with the ARM calling conventions */
|
|
Petr Machata |
cb74839 |
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
|
|
Petr Machata |
cb74839 |
- if (arg_num < 4) {
|
|
Petr Machata |
cb74839 |
- if (a->valid && type == LT_TOF_FUNCTION)
|
|
Petr Machata |
cb74839 |
- return a->regs.uregs[arg_num];
|
|
Petr Machata |
cb74839 |
- if (a->valid && type == LT_TOF_FUNCTIONR)
|
|
Petr Machata |
cb74839 |
- return a->func_arg[arg_num];
|
|
Petr Machata |
cb74839 |
- return ptrace(PTRACE_PEEKUSER, proc->pid,
|
|
Petr Machata |
cb74839 |
- (void *)(4 * arg_num), 0);
|
|
Petr Machata |
cb74839 |
- } else {
|
|
Petr Machata |
cb74839 |
- return ptrace(PTRACE_PEEKDATA, proc->pid,
|
|
Petr Machata |
cb74839 |
- proc->stack_pointer + 4 * (arg_num - 4),
|
|
Petr Machata |
cb74839 |
- 0);
|
|
Petr Machata |
4b23d2c |
+enum {
|
|
Petr Machata |
4b23d2c |
+ COND_ALWAYS = 0xe,
|
|
Petr Machata |
4b23d2c |
+ COND_NV = 0xf,
|
|
Petr Machata |
4b23d2c |
+ FLAG_C = 0x20000000,
|
|
Petr Machata |
4b23d2c |
+};
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+static int
|
|
Petr Machata |
4b23d2c |
+arm_get_next_pcs(struct process *proc,
|
|
Petr Machata |
4b23d2c |
+ const arch_addr_t pc, arch_addr_t next_pcs[2])
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ uint32_t this_instr;
|
|
Petr Machata |
4b23d2c |
+ uint32_t status;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_32(proc, pc, &this_instr) < 0
|
|
Petr Machata |
4b23d2c |
+ || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* In theory, we sometimes don't even need to add any
|
|
Petr Machata |
4b23d2c |
+ * breakpoints at all. If the conditional bits of the
|
|
Petr Machata |
4b23d2c |
+ * instruction indicate that it should not be taken, then we
|
|
Petr Machata |
4b23d2c |
+ * can just skip it altogether without bothering. We could
|
|
Petr Machata |
4b23d2c |
+ * also emulate the instruction under the breakpoint.
|
|
Petr Machata |
4b23d2c |
+ *
|
|
Petr Machata |
4b23d2c |
+ * Here, we make it as simple as possible (though We Accept
|
|
Petr Machata |
4b23d2c |
+ * Patches). */
|
|
Petr Machata |
4b23d2c |
+ int nr = 0;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* ARM can branch either relatively by using a branch
|
|
Petr Machata |
4b23d2c |
+ * instruction, or absolutely, by doing arbitrary arithmetic
|
|
Petr Machata |
4b23d2c |
+ * with PC as the destination. */
|
|
Petr Machata |
4b23d2c |
+ const unsigned cond = BITS(this_instr, 28, 31);
|
|
Petr Machata |
4b23d2c |
+ const unsigned opcode = BITS(this_instr, 24, 27);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (cond == COND_NV)
|
|
Petr Machata |
4b23d2c |
+ switch (opcode) {
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t addr;
|
|
Petr Machata |
4b23d2c |
+ case 0xa:
|
|
Petr Machata |
4b23d2c |
+ case 0xb:
|
|
Petr Machata |
4b23d2c |
+ /* Branch with Link and change to Thumb. */
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast. */
|
|
Petr Machata |
4b23d2c |
+ addr = (arch_addr_t)
|
|
Petr Machata |
4b23d2c |
+ ((uint32_t)arm_branch_dest(pc, this_instr)
|
|
Petr Machata |
4b23d2c |
+ | (((this_instr >> 24) & 0x1) << 1));
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = MAKE_THUMB_ADDR(addr);
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
- } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
|
|
Petr Machata |
cb74839 |
- if (arg_num < 5) {
|
|
Petr Machata |
cb74839 |
- if (a->valid && type == LT_TOF_SYSCALL)
|
|
Petr Machata |
cb74839 |
- return a->regs.uregs[arg_num];
|
|
Petr Machata |
cb74839 |
- if (a->valid && type == LT_TOF_SYSCALLR)
|
|
Petr Machata |
cb74839 |
- return a->sysc_arg[arg_num];
|
|
Petr Machata |
cb74839 |
- return ptrace(PTRACE_PEEKUSER, proc->pid,
|
|
Petr Machata |
cb74839 |
- (void *)(4 * arg_num), 0);
|
|
Petr Machata |
cb74839 |
- } else {
|
|
Petr Machata |
cb74839 |
- return ptrace(PTRACE_PEEKDATA, proc->pid,
|
|
Petr Machata |
cb74839 |
- proc->stack_pointer + 4 * (arg_num - 5),
|
|
Petr Machata |
cb74839 |
- 0);
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ switch (opcode) {
|
|
Petr Machata |
4b23d2c |
+ uint32_t operand1, operand2, result = 0;
|
|
Petr Machata |
4b23d2c |
+ case 0x0:
|
|
Petr Machata |
4b23d2c |
+ case 0x1: /* data processing */
|
|
Petr Machata |
4b23d2c |
+ case 0x2:
|
|
Petr Machata |
4b23d2c |
+ case 0x3:
|
|
Petr Machata |
4b23d2c |
+ if (BITS(this_instr, 12, 15) != ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (BITS(this_instr, 22, 25) == 0
|
|
Petr Machata |
4b23d2c |
+ && BITS(this_instr, 4, 7) == 9) { /* multiply */
|
|
Petr Machata |
4b23d2c |
+ invalid:
|
|
Petr Machata |
4b23d2c |
+ fprintf(stderr,
|
|
Petr Machata |
4b23d2c |
+ "Invalid update to pc in instruction.\n");
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* BX <reg>, BLX <reg> */
|
|
Petr Machata |
4b23d2c |
+ if (BITS(this_instr, 4, 27) == 0x12fff1
|
|
Petr Machata |
4b23d2c |
+ || BITS(this_instr, 4, 27) == 0x12fff3) {
|
|
Petr Machata |
4b23d2c |
+ enum arm_register reg = BITS(this_instr, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast: no need to go
|
|
Petr Machata |
4b23d2c |
+ * through tmp. */
|
|
Petr Machata |
4b23d2c |
+ uint32_t tmp;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register_offpc(proc, reg, &tmp) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)tmp;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* Multiply into PC. */
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register_offpc
|
|
Petr Machata |
4b23d2c |
+ (proc, BITS(this_instr, 16, 19), &operand1) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int c = (status & FLAG_C) ? 1 : 0;
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 25)) {
|
|
Petr Machata |
4b23d2c |
+ uint32_t immval = BITS(this_instr, 0, 7);
|
|
Petr Machata |
4b23d2c |
+ uint32_t rotate = 2 * BITS(this_instr, 8, 11);
|
|
Petr Machata |
4b23d2c |
+ operand2 = (((immval >> rotate)
|
|
Petr Machata |
4b23d2c |
+ | (immval << (32 - rotate)))
|
|
Petr Machata |
4b23d2c |
+ & 0xffffffff);
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ /* operand 2 is a shifted register. */
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_shifted_register
|
|
Petr Machata |
4b23d2c |
+ (proc, this_instr, c, pc, &operand2) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ switch (BITS(this_instr, 21, 24)) {
|
|
Petr Machata |
4b23d2c |
+ case 0x0: /*and */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 & operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x1: /*eor */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 ^ operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x2: /*sub */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 - operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x3: /*rsb */
|
|
Petr Machata |
4b23d2c |
+ result = operand2 - operand1;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x4: /*add */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 + operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x5: /*adc */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 + operand2 + c;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x6: /*sbc */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 - operand2 + c;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x7: /*rsc */
|
|
Petr Machata |
4b23d2c |
+ result = operand2 - operand1 + c;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x8:
|
|
Petr Machata |
4b23d2c |
+ case 0x9:
|
|
Petr Machata |
4b23d2c |
+ case 0xa:
|
|
Petr Machata |
4b23d2c |
+ case 0xb: /* tst, teq, cmp, cmn */
|
|
Petr Machata |
4b23d2c |
+ /* Only take the default branch. */
|
|
Petr Machata |
4b23d2c |
+ result = 0;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xc: /*orr */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 | operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xd: /*mov */
|
|
Petr Machata |
4b23d2c |
+ /* Always step into a function. */
|
|
Petr Machata |
4b23d2c |
+ result = operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xe: /*bic */
|
|
Petr Machata |
4b23d2c |
+ result = operand1 & ~operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xf: /*mvn */
|
|
Petr Machata |
4b23d2c |
+ result = ~operand2;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)result;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x4:
|
|
Petr Machata |
4b23d2c |
+ case 0x5: /* data transfer */
|
|
Petr Machata |
4b23d2c |
+ case 0x6:
|
|
Petr Machata |
4b23d2c |
+ case 0x7:
|
|
Petr Machata |
4b23d2c |
+ /* Ignore if insn isn't load or Rn not PC. */
|
|
Petr Machata |
4b23d2c |
+ if (!BIT(this_instr, 20)
|
|
Petr Machata |
4b23d2c |
+ || BITS(this_instr, 12, 15) != ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 22))
|
|
Petr Machata |
4b23d2c |
+ goto invalid;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* byte write to PC */
|
|
Petr Machata |
4b23d2c |
+ uint32_t base;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register_offpc
|
|
Petr Machata |
4b23d2c |
+ (proc, BITS(this_instr, 16, 19), &base) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 24)) {
|
|
Petr Machata |
4b23d2c |
+ /* pre-indexed */
|
|
Petr Machata |
4b23d2c |
+ int c = (status & FLAG_C) ? 1 : 0;
|
|
Petr Machata |
4b23d2c |
+ uint32_t offset;
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 25)) {
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_shifted_register
|
|
Petr Machata |
4b23d2c |
+ (proc, this_instr, c,
|
|
Petr Machata |
4b23d2c |
+ pc, &offset) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ offset = BITS(this_instr, 0, 11);
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 23))
|
|
Petr Machata |
4b23d2c |
+ base += offset;
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ base -= offset;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* XXX two double casts. */
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_32(proc, (arch_addr_t)base, &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0x8:
|
|
Petr Machata |
4b23d2c |
+ case 0x9: /* block transfer */
|
|
Petr Machata |
4b23d2c |
+ if (!BIT(this_instr, 20))
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+ /* LDM */
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 15)) {
|
|
Petr Machata |
4b23d2c |
+ /* Loading pc. */
|
|
Petr Machata |
4b23d2c |
+ int offset = 0;
|
|
Petr Machata |
4b23d2c |
+ enum arm_register rn = BITS(this_instr, 16, 19);
|
|
Petr Machata |
4b23d2c |
+ uint32_t rn_val;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, rn, &rn_val) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int pre = BIT(this_instr, 24);
|
|
Petr Machata |
4b23d2c |
+ if (BIT(this_instr, 23)) {
|
|
Petr Machata |
4b23d2c |
+ /* Bit U = up. */
|
|
Petr Machata |
4b23d2c |
+ unsigned reglist
|
|
Petr Machata |
4b23d2c |
+ = BITS(this_instr, 0, 14);
|
|
Petr Machata |
4b23d2c |
+ offset = bitcount(reglist) * 4;
|
|
Petr Machata |
4b23d2c |
+ if (pre)
|
|
Petr Machata |
4b23d2c |
+ offset += 4;
|
|
Petr Machata |
4b23d2c |
+ } else if (pre) {
|
|
Petr Machata |
4b23d2c |
+ offset = -4;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast. */
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t addr
|
|
Petr Machata |
4b23d2c |
+ = (arch_addr_t)(rn_val + offset);
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_32(proc, addr, &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xb: /* branch & link */
|
|
Petr Machata |
4b23d2c |
+ case 0xa: /* branch */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = arm_branch_dest(pc, this_instr);
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ case 0xc:
|
|
Petr Machata |
4b23d2c |
+ case 0xd:
|
|
Petr Machata |
4b23d2c |
+ case 0xe: /* coproc ops */
|
|
Petr Machata |
4b23d2c |
+ case 0xf: /* SWI */
|
|
Petr Machata |
4b23d2c |
+ break;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* Otherwise take the next instruction. */
|
|
Petr Machata |
4b23d2c |
+ if (cond != COND_ALWAYS || nr == 0)
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + 4;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+/* Return the size in bytes of the complete Thumb instruction whose
|
|
Petr Machata |
4b23d2c |
+ * first halfword is INST1. */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+static int
|
|
Petr Machata |
4b23d2c |
+thumb_insn_size (unsigned short inst1)
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
|
|
Petr Machata |
4b23d2c |
+ return 4;
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ return 2;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+static int
|
|
Petr Machata |
4b23d2c |
+thumb_get_next_pcs(struct process *proc,
|
|
Petr Machata |
4b23d2c |
+ const arch_addr_t pc, arch_addr_t next_pcs[2])
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ uint16_t inst1;
|
|
Petr Machata |
4b23d2c |
+ uint32_t status;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_16(proc, pc, &inst1) < 0
|
|
Petr Machata |
4b23d2c |
+ || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int nr = 0;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* We currently ignore Thumb-2 conditional execution support
|
|
Petr Machata |
4b23d2c |
+ * (the IT instruction). No branches are allowed in IT block,
|
|
Petr Machata |
4b23d2c |
+ * and it's not legal to jump in the middle of it, so unless
|
|
Petr Machata |
4b23d2c |
+ * we need to singlestep through large swaths of code, which
|
|
Petr Machata |
4b23d2c |
+ * we currently don't, we can ignore them. */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if ((inst1 & 0xff00) == 0xbd00) { /* pop {rlist, pc} */
|
|
Petr Machata |
4b23d2c |
+ /* Fetch the saved PC from the stack. It's stored
|
|
Petr Machata |
4b23d2c |
+ * above all of the other registers. */
|
|
Petr Machata |
4b23d2c |
+ const unsigned offset = bitcount(BITS(inst1, 0, 7)) * 4;
|
|
Petr Machata |
4b23d2c |
+ uint32_t sp;
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ /* XXX two double casts */
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, ARM_REG_SP, &sp) < 0
|
|
Petr Machata |
4b23d2c |
+ || proc_read_32(proc, (arch_addr_t)(sp + offset),
|
|
Petr Machata |
4b23d2c |
+ &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xf000) == 0xd000) { /* conditional branch */
|
|
Petr Machata |
4b23d2c |
+ const unsigned long cond = BITS(inst1, 8, 11);
|
|
Petr Machata |
4b23d2c |
+ if (cond != 0x0f) { /* SWI */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + (SBITS(inst1, 0, 7) << 1);
|
|
Petr Machata |
4b23d2c |
+ if (cond == COND_ALWAYS)
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xf800) == 0xe000) { /* unconditional branch */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + (SBITS(inst1, 0, 10) << 1);
|
|
Petr Machata |
4b23d2c |
+ } else if (thumb_insn_size(inst1) == 4) { /* 32-bit instruction */
|
|
Petr Machata |
4b23d2c |
+ unsigned short inst2;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_16(proc, pc + 2, &inst2) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) {
|
|
Petr Machata |
4b23d2c |
+ /* Branches and miscellaneous control instructions. */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if ((inst2 & 0x1000) != 0
|
|
Petr Machata |
4b23d2c |
+ || (inst2 & 0xd001) == 0xc000) {
|
|
Petr Machata |
4b23d2c |
+ /* B, BL, BLX. */
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ const int imm1 = SBITS(inst1, 0, 10);
|
|
Petr Machata |
4b23d2c |
+ const unsigned imm2 = BITS(inst2, 0, 10);
|
|
Petr Machata |
4b23d2c |
+ const unsigned j1 = BIT(inst2, 13);
|
|
Petr Machata |
4b23d2c |
+ const unsigned j2 = BIT(inst2, 11);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int32_t offset
|
|
Petr Machata |
4b23d2c |
+ = ((imm1 << 12) + (imm2 << 1));
|
|
Petr Machata |
4b23d2c |
+ offset ^= ((!j2) << 22) | ((!j1) << 23);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ uint32_t next = (uint32_t)(pc + offset);
|
|
Petr Machata |
4b23d2c |
+ /* For BLX make sure to clear the low bits. */
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst2, 12) == 0)
|
|
Petr Machata |
4b23d2c |
+ next = next & 0xfffffffc;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+ } else if (inst1 == 0xf3de
|
|
Petr Machata |
4b23d2c |
+ && (inst2 & 0xff00) == 0x3f00) {
|
|
Petr Machata |
4b23d2c |
+ /* SUBS PC, LR, #imm8. */
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, ARM_REG_LR,
|
|
Petr Machata |
4b23d2c |
+ &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next -= inst2 & 0x00ff;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst2 & 0xd000) == 0x8000
|
|
Petr Machata |
4b23d2c |
+ && (inst1 & 0x0380) != 0x0380) {
|
|
Petr Machata |
4b23d2c |
+ /* Conditional branch. */
|
|
Petr Machata |
4b23d2c |
+ const int sign = SBITS(inst1, 10, 10);
|
|
Petr Machata |
4b23d2c |
+ const unsigned imm1 = BITS(inst1, 0, 5);
|
|
Petr Machata |
4b23d2c |
+ const unsigned imm2 = BITS(inst2, 0, 10);
|
|
Petr Machata |
4b23d2c |
+ const unsigned j1 = BIT(inst2, 13);
|
|
Petr Machata |
4b23d2c |
+ const unsigned j2 = BIT(inst2, 11);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int32_t offset = (sign << 20)
|
|
Petr Machata |
4b23d2c |
+ + (j2 << 19) + (j1 << 18);
|
|
Petr Machata |
4b23d2c |
+ offset += (imm1 << 12) + (imm2 << 1);
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + offset;
|
|
Petr Machata |
4b23d2c |
+ if (BITS(inst1, 6, 9) == COND_ALWAYS)
|
|
Petr Machata |
4b23d2c |
+ return 0;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xfe50) == 0xe810) {
|
|
Petr Machata |
4b23d2c |
+ int load_pc = 1;
|
|
Petr Machata |
4b23d2c |
+ int offset;
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register rn = BITS(inst1, 0, 3);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst1, 7) && !BIT(inst1, 8)) {
|
|
Petr Machata |
4b23d2c |
+ /* LDMIA or POP */
|
|
Petr Machata |
4b23d2c |
+ if (!BIT(inst2, 15))
|
|
Petr Machata |
4b23d2c |
+ load_pc = 0;
|
|
Petr Machata |
4b23d2c |
+ offset = bitcount(inst2) * 4 - 4;
|
|
Petr Machata |
4b23d2c |
+ } else if (!BIT(inst1, 7) && BIT(inst1, 8)) {
|
|
Petr Machata |
4b23d2c |
+ /* LDMDB */
|
|
Petr Machata |
4b23d2c |
+ if (!BIT(inst2, 15))
|
|
Petr Machata |
4b23d2c |
+ load_pc = 0;
|
|
Petr Machata |
4b23d2c |
+ offset = -4;
|
|
Petr Machata |
4b23d2c |
+ } else if (BIT(inst1, 7) && BIT(inst1, 8)) {
|
|
Petr Machata |
4b23d2c |
+ /* RFEIA */
|
|
Petr Machata |
4b23d2c |
+ offset = 0;
|
|
Petr Machata |
4b23d2c |
+ } else if (!BIT(inst1, 7) && !BIT(inst1, 8)) {
|
|
Petr Machata |
4b23d2c |
+ /* RFEDB */
|
|
Petr Machata |
4b23d2c |
+ offset = -8;
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ load_pc = 0;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (load_pc) {
|
|
Petr Machata |
4b23d2c |
+ uint32_t addr;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, rn, &addr) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t a = (arch_addr_t)(addr + offset);
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_32(proc, a, &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xffef) == 0xea4f
|
|
Petr Machata |
4b23d2c |
+ && (inst2 & 0xfff0) == 0x0f00) {
|
|
Petr Machata |
4b23d2c |
+ /* MOV PC or MOVS PC. */
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register rn = BITS(inst2, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, rn, &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xff70) == 0xf850
|
|
Petr Machata |
4b23d2c |
+ && (inst2 & 0xf000) == 0xf000) {
|
|
Petr Machata |
4b23d2c |
+ /* LDR PC. */
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register rn = BITS(inst1, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ uint32_t base;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, rn, &base) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int load_pc = 1;
|
|
Petr Machata |
4b23d2c |
+ if (rn == ARM_REG_PC) {
|
|
Petr Machata |
4b23d2c |
+ base = (base + 4) & ~(uint32_t)0x3;
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst1, 7))
|
|
Petr Machata |
4b23d2c |
+ base += BITS(inst2, 0, 11);
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ base -= BITS(inst2, 0, 11);
|
|
Petr Machata |
4b23d2c |
+ } else if (BIT(inst1, 7)) {
|
|
Petr Machata |
4b23d2c |
+ base += BITS(inst2, 0, 11);
|
|
Petr Machata |
4b23d2c |
+ } else if (BIT(inst2, 11)) {
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst2, 10)) {
|
|
Petr Machata |
4b23d2c |
+ if (BIT(inst2, 9))
|
|
Petr Machata |
4b23d2c |
+ base += BITS(inst2, 0, 7);
|
|
Petr Machata |
4b23d2c |
+ else
|
|
Petr Machata |
4b23d2c |
+ base -= BITS(inst2, 0, 7);
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst2 & 0x0fc0) == 0x0000) {
|
|
Petr Machata |
4b23d2c |
+ const int shift = BITS(inst2, 4, 5);
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register rm = BITS(inst2, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ uint32_t v;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, rm, &v) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ base += v << shift;
|
|
Petr Machata |
4b23d2c |
+ } else {
|
|
Petr Machata |
4b23d2c |
+ /* Reserved. */
|
|
Petr Machata |
4b23d2c |
+ load_pc = 0;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ if (load_pc) {
|
|
Petr Machata |
4b23d2c |
+ /* xxx double casts */
|
|
Petr Machata |
4b23d2c |
+ uint32_t next;
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_32(proc,
|
|
Petr Machata |
4b23d2c |
+ (arch_addr_t)base, &next) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = (arch_addr_t)next;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xfff0) == 0xe8d0
|
|
Petr Machata |
4b23d2c |
+ && (inst2 & 0xfff0) == 0xf000) {
|
|
Petr Machata |
4b23d2c |
+ /* TBB. */
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register tbl_reg = BITS(inst1, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register off_reg = BITS(inst2, 0, 3);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t table;
|
|
Petr Machata |
4b23d2c |
+ if (tbl_reg == ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ /* Regcache copy of PC isn't right yet. */
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ table = (uint32_t)pc + 4;
|
|
Petr Machata |
4b23d2c |
+ else if (arm_get_register(proc, tbl_reg, &table) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t offset;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, off_reg, &offset) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ table += offset;
|
|
Petr Machata |
4b23d2c |
+ uint8_t length;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_8(proc, (arch_addr_t)table, &length) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + 2 * length;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ } else if ((inst1 & 0xfff0) == 0xe8d0
|
|
Petr Machata |
4b23d2c |
+ && (inst2 & 0xfff0) == 0xf010) {
|
|
Petr Machata |
4b23d2c |
+ /* TBH. */
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register tbl_reg = BITS(inst1, 0, 3);
|
|
Petr Machata |
4b23d2c |
+ const enum arm_register off_reg = BITS(inst2, 0, 3);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t table;
|
|
Petr Machata |
4b23d2c |
+ if (tbl_reg == ARM_REG_PC)
|
|
Petr Machata |
4b23d2c |
+ /* Regcache copy of PC isn't right yet. */
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ table = (uint32_t)pc + 4;
|
|
Petr Machata |
4b23d2c |
+ else if (arm_get_register(proc, tbl_reg, &table) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t offset;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, off_reg, &offset) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ table += 2 * offset;
|
|
Petr Machata |
4b23d2c |
+ uint16_t length;
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast */
|
|
Petr Machata |
4b23d2c |
+ if (proc_read_16(proc, (arch_addr_t)table, &length) < 0)
|
|
Petr Machata |
4b23d2c |
+ return -1;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + 2 * length;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
- } else {
|
|
Petr Machata |
cb74839 |
- fprintf(stderr, "gimme_arg called with wrong arguments\n");
|
|
Petr Machata |
cb74839 |
- exit(1);
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ /* Otherwise take the next instruction. */
|
|
Petr Machata |
4b23d2c |
+ if (nr == 0)
|
|
Petr Machata |
4b23d2c |
+ next_pcs[nr++] = pc + thumb_insn_size(inst1);
|
|
Petr Machata |
cb74839 |
return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+enum sw_singlestep_status
|
|
Petr Machata |
4b23d2c |
+arch_sw_singlestep(struct process *proc, struct breakpoint *sbp,
|
|
Petr Machata |
4b23d2c |
+ int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
|
|
Petr Machata |
4b23d2c |
+ struct sw_singlestep_data *add_cb_data)
|
|
Petr Machata |
4b23d2c |
+{
|
|
Petr Machata |
4b23d2c |
+ const arch_addr_t pc = get_instruction_pointer(proc);
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ uint32_t cpsr;
|
|
Petr Machata |
4b23d2c |
+ if (arm_get_register(proc, ARM_REG_CPSR, &cpsr) < 0)
|
|
Petr Machata |
4b23d2c |
+ return SWS_FAIL;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ const unsigned thumb_p = BIT(cpsr, 5);
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t next_pcs[2] = {};
|
|
Petr Machata |
4b23d2c |
+ if ((thumb_p ? &thumb_get_next_pcs
|
|
Petr Machata |
4b23d2c |
+ : &arm_get_next_pcs)(proc, pc, next_pcs) < 0)
|
|
Petr Machata |
4b23d2c |
+ return SWS_FAIL;
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int i;
|
|
Petr Machata |
4b23d2c |
+ for (i = 0; i < 2; ++i) {
|
|
Petr Machata |
4b23d2c |
+ /* XXX double cast. */
|
|
Petr Machata |
4b23d2c |
+ arch_addr_t target
|
|
Petr Machata |
4b23d2c |
+ = (arch_addr_t)(((uintptr_t)next_pcs[i]) | thumb_p);
|
|
Petr Machata |
4b23d2c |
+ if (next_pcs[i] != 0 && add_cb(target, add_cb_data) < 0)
|
|
Petr Machata |
4b23d2c |
+ return SWS_FAIL;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ debug(1, "PTRACE_CONT");
|
|
Petr Machata |
4b23d2c |
+ ptrace(PTRACE_CONT, proc->pid, 0, 0);
|
|
Petr Machata |
4b23d2c |
+ return SWS_OK;
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+size_t
|
|
Petr Machata |
cb74839 |
+arch_type_sizeof(struct process *proc, struct arg_type_info *info)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ if (proc == NULL)
|
|
Petr Machata |
cb74839 |
+ return (size_t)-2;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ switch (info->type) {
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_VOID:
|
|
Petr Machata |
cb74839 |
+ return 0;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_CHAR:
|
|
Petr Machata |
cb74839 |
+ return 1;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_SHORT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_USHORT:
|
|
Petr Machata |
cb74839 |
+ return 2;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_INT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_UINT:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_LONG:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_ULONG:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_POINTER:
|
|
Petr Machata |
cb74839 |
+ return 4;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_FLOAT:
|
|
Petr Machata |
cb74839 |
+ return 4;
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_DOUBLE:
|
|
Petr Machata |
cb74839 |
+ return 8;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_ARRAY:
|
|
Petr Machata |
cb74839 |
+ case ARGTYPE_STRUCT:
|
|
Petr Machata |
cb74839 |
+ /* Use default value. */
|
|
Petr Machata |
cb74839 |
+ return (size_t)-2;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ default:
|
|
Petr Machata |
cb74839 |
+ assert(info->type != info->type);
|
|
Petr Machata |
cb74839 |
+ abort();
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+size_t
|
|
Petr Machata |
cb74839 |
+arch_type_alignof(struct process *proc, struct arg_type_info *info)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ return arch_type_sizeof(proc, info);
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
diff --git a/sysdeps/linux-gnu/ia64/fetch.c b/sysdeps/linux-gnu/ia64/fetch.c
|
|
Petr Machata |
cb74839 |
index e90dbed..171c7a2 100644
|
|
Petr Machata |
cb74839 |
--- a/sysdeps/linux-gnu/ia64/fetch.c
|
|
Petr Machata |
cb74839 |
+++ b/sysdeps/linux-gnu/ia64/fetch.c
|
|
Petr Machata |
cb74839 |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
cb74839 |
/*
|
|
Petr Machata |
cb74839 |
* This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2008,2009 Juan Cespedes
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2006 Steve Fink
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
cb74839 |
@@ -249,37 +249,6 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
|
|
Petr Machata |
cb74839 |
return 0;
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-static enum arg_type
|
|
Petr Machata |
cb74839 |
-get_hfa_type(struct arg_type_info *info, size_t *countp)
|
|
Petr Machata |
cb74839 |
-{
|
|
Petr Machata |
cb74839 |
- size_t n = type_aggregate_size(info);
|
|
Petr Machata |
cb74839 |
- if (n == (size_t)-1)
|
|
Petr Machata |
cb74839 |
- return ARGTYPE_VOID;
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
- enum arg_type type = ARGTYPE_VOID;
|
|
Petr Machata |
cb74839 |
- *countp = 0;
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
- while (n-- > 0) {
|
|
Petr Machata |
cb74839 |
- struct arg_type_info *emt = type_element(info, n);
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
- enum arg_type emt_type = emt->type;
|
|
Petr Machata |
cb74839 |
- size_t emt_count = 1;
|
|
Petr Machata |
cb74839 |
- if (emt_type == ARGTYPE_STRUCT || emt_type == ARGTYPE_ARRAY)
|
|
Petr Machata |
cb74839 |
- emt_type = get_hfa_type(emt, &emt_count);
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
- if (type == ARGTYPE_VOID) {
|
|
Petr Machata |
cb74839 |
- if (emt_type != ARGTYPE_FLOAT
|
|
Petr Machata |
cb74839 |
- && emt_type != ARGTYPE_DOUBLE)
|
|
Petr Machata |
cb74839 |
- return ARGTYPE_VOID;
|
|
Petr Machata |
cb74839 |
- type = emt_type;
|
|
Petr Machata |
cb74839 |
- }
|
|
Petr Machata |
cb74839 |
- if (emt_type != type)
|
|
Petr Machata |
cb74839 |
- return ARGTYPE_VOID;
|
|
Petr Machata |
cb74839 |
- *countp += emt_count;
|
|
Petr Machata |
cb74839 |
- }
|
|
Petr Machata |
cb74839 |
- return type;
|
|
Petr Machata |
cb74839 |
-}
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
static int
|
|
Petr Machata |
cb74839 |
allocate_hfa(struct fetch_context *ctx, struct process *proc,
|
|
Petr Machata |
cb74839 |
struct arg_type_info *info, struct value *valuep,
|
|
Petr Machata |
cb74839 |
@@ -380,10 +349,11 @@ allocate_ret(struct fetch_context *ctx, struct process *proc,
|
|
Petr Machata |
cb74839 |
* floating-point registers, beginning with f8. */
|
|
Petr Machata |
cb74839 |
if (info->type == ARGTYPE_STRUCT || info->type == ARGTYPE_ARRAY) {
|
|
Petr Machata |
cb74839 |
size_t hfa_size;
|
|
Petr Machata |
cb74839 |
- enum arg_type hfa_type = get_hfa_type(info, &hfa_size);
|
|
Petr Machata |
cb74839 |
- if (hfa_type != ARGTYPE_VOID && hfa_size <= 8)
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *hfa_info
|
|
Petr Machata |
cb74839 |
+ = type_get_hfa_type(info, &hfa_size);
|
|
Petr Machata |
cb74839 |
+ if (hfa_info != NULL && hfa_size <= 8)
|
|
Petr Machata |
cb74839 |
return allocate_hfa(ctx, proc, info, valuep,
|
|
Petr Machata |
cb74839 |
- hfa_type, hfa_size);
|
|
Petr Machata |
cb74839 |
+ hfa_info->type, hfa_size);
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
/* Integers and pointers are passed in r8. 128-bit integers
|
|
Petr Machata |
cb74839 |
@@ -409,7 +379,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
Petr Machata |
cb74839 |
struct arg_type_info *info, struct value *valuep)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
switch (info->type) {
|
|
Petr Machata |
cb74839 |
- enum arg_type hfa_type;
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *hfa_info;
|
|
Petr Machata |
cb74839 |
size_t hfa_size;
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
case ARGTYPE_VOID:
|
|
Petr Machata |
cb74839 |
@@ -421,10 +391,10 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
|
|
Petr Machata |
cb74839 |
return allocate_float(ctx, proc, info, valuep, 1);
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
case ARGTYPE_STRUCT:
|
|
Petr Machata |
cb74839 |
- hfa_type = get_hfa_type(info, &hfa_size);
|
|
Petr Machata |
cb74839 |
- if (hfa_type != ARGTYPE_VOID)
|
|
Petr Machata |
cb74839 |
+ hfa_info = type_get_hfa_type(info, &hfa_size);
|
|
Petr Machata |
cb74839 |
+ if (hfa_info != NULL)
|
|
Petr Machata |
cb74839 |
return allocate_hfa(ctx, proc, info, valuep,
|
|
Petr Machata |
cb74839 |
- hfa_type, hfa_size);
|
|
Petr Machata |
cb74839 |
+ hfa_info->type, hfa_size);
|
|
Petr Machata |
cb74839 |
/* Fall through. */
|
|
Petr Machata |
cb74839 |
case ARGTYPE_CHAR:
|
|
Petr Machata |
cb74839 |
case ARGTYPE_SHORT:
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
|
|
Petr Machata |
4b23d2c |
index fb79e8a..67873ce 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/ia64/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/ia64/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
@@ -77,9 +77,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
return NULL;
|
|
Petr Machata |
4b23d2c |
return (void *)l;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, PT_B0, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
|
|
Petr Machata |
4b23d2c |
index c2fafe1..e25aefb 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/m68k/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/m68k/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
@@ -58,9 +59,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c
|
|
Petr Machata |
4b23d2c |
index 19f97cb..d6a7a50 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/mipsel/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/mipsel/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc.
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
@@ -94,9 +95,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
cb74839 |
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
|
|
Petr Machata |
cb74839 |
index 439b8e8..fe1602a 100644
|
|
Petr Machata |
cb74839 |
--- a/sysdeps/linux-gnu/ppc/plt.c
|
|
Petr Machata |
cb74839 |
+++ b/sysdeps/linux-gnu/ppc/plt.c
|
|
Petr Machata |
cb74839 |
@@ -262,7 +262,8 @@ load_opd_data(struct ltelf *lte, struct library *lib)
|
|
Petr Machata |
cb74839 |
{
|
|
Petr Machata |
cb74839 |
Elf_Scn *sec;
|
|
Petr Machata |
cb74839 |
GElf_Shdr shdr;
|
|
Petr Machata |
cb74839 |
- if (elf_get_section_named(lte, ".opd", &sec, &shdr) < 0) {
|
|
Petr Machata |
cb74839 |
+ if (elf_get_section_named(lte, ".opd", &sec, &shdr) < 0
|
|
Petr Machata |
cb74839 |
+ || sec == NULL) {
|
|
Petr Machata |
cb74839 |
fail:
|
|
Petr Machata |
cb74839 |
fprintf(stderr, "couldn't find .opd data\n");
|
|
Petr Machata |
cb74839 |
return -1;
|
|
Petr Machata |
cb74839 |
@@ -290,8 +291,9 @@ get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data)
|
|
Petr Machata |
cb74839 |
Elf_Scn *ppcgot_sec = NULL;
|
|
Petr Machata |
cb74839 |
GElf_Shdr ppcgot_shdr;
|
|
Petr Machata |
cb74839 |
if (ppcgot != 0
|
|
Petr Machata |
cb74839 |
- && elf_get_section_covering(lte, ppcgot,
|
|
Petr Machata |
cb74839 |
- &ppcgot_sec, &ppcgot_shdr) < 0)
|
|
Petr Machata |
cb74839 |
+ && (elf_get_section_covering(lte, ppcgot,
|
|
Petr Machata |
cb74839 |
+ &ppcgot_sec, &ppcgot_shdr) < 0
|
|
Petr Machata |
cb74839 |
+ || ppcgot_sec == NULL))
|
|
Petr Machata |
cb74839 |
fprintf(stderr,
|
|
Petr Machata |
cb74839 |
"DT_PPC_GOT=%#"PRIx64", but no such section found\n",
|
|
Petr Machata |
cb74839 |
ppcgot);
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
|
|
Petr Machata |
4b23d2c |
index ed9b398..40d7e7a 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/ppc/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/ppc/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2002,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2008 Luis Machado, IBM Corporation
|
|
Petr Machata |
4b23d2c |
@@ -63,9 +64,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0);
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_LNK, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
|
|
Petr Machata |
4b23d2c |
index 44e8f67..bb16c61 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/s390/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/s390/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2002,2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
@@ -87,13 +88,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
#endif
|
|
Petr Machata |
4b23d2c |
return (void *)ret;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
-#ifdef __s390x__
|
|
Petr Machata |
4b23d2c |
- if (proc->mask_32bit)
|
|
Petr Machata |
4b23d2c |
- addr = (void *)((long)addr & PSW_MASK31);
|
|
Petr Machata |
4b23d2c |
-#endif
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKEUSER, proc->pid, PT_GPR14, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c
|
|
Petr Machata |
4b23d2c |
index 8431c9b..c474c83 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/sparc/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/sparc/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,5 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
@@ -65,12 +66,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
|
|
Petr Machata |
4b23d2c |
return (void *)a->regs.u_regs[UREG_I6] + 12;
|
|
Petr Machata |
4b23d2c |
return (void *)a->regs.u_regs[UREG_I6] + 8;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
|
|
Petr Machata |
4b23d2c |
- if (!a->valid)
|
|
Petr Machata |
4b23d2c |
- return;
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKETEXT, proc->pid, a->regs.u_regs[UREG_I6] + 8, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
|
|
Petr Machata |
4b23d2c |
index e57a5ed..3aea082 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/trace.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/trace.c
|
|
Petr Machata |
4b23d2c |
@@ -561,12 +561,12 @@ remove_sw_breakpoints(struct process *proc)
|
|
Petr Machata |
4b23d2c |
assert(self != NULL);
|
|
Petr Machata |
4b23d2c |
assert(self->super.on_event == process_stopping_on_event);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- int ct = sizeof(self->sws_bp_addrs) / sizeof(*self->sws_bp_addrs);
|
|
Petr Machata |
4b23d2c |
+ int ct = sizeof(self->sws_bps) / sizeof(*self->sws_bps);
|
|
Petr Machata |
4b23d2c |
int i;
|
|
Petr Machata |
4b23d2c |
for (i = 0; i < ct; ++i)
|
|
Petr Machata |
4b23d2c |
- if (self->sws_bp_addrs[i] != 0) {
|
|
Petr Machata |
4b23d2c |
- delete_breakpoint(proc, self->sws_bp_addrs[i]);
|
|
Petr Machata |
4b23d2c |
- self->sws_bp_addrs[i] = 0;
|
|
Petr Machata |
4b23d2c |
+ if (self->sws_bps[i] != NULL) {
|
|
Petr Machata |
4b23d2c |
+ delete_breakpoint(proc, self->sws_bps[i]->addr);
|
|
Petr Machata |
4b23d2c |
+ self->sws_bps[i] = NULL;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
@@ -586,18 +586,17 @@ sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
|
|
Petr Machata |
4b23d2c |
struct process_stopping_handler *self = data->self;
|
|
Petr Machata |
4b23d2c |
struct process *proc = self->task_enabling_breakpoint;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- int ct = sizeof(self->sws_bp_addrs)
|
|
Petr Machata |
4b23d2c |
- / sizeof(*self->sws_bp_addrs);
|
|
Petr Machata |
4b23d2c |
+ int ct = sizeof(self->sws_bps) / sizeof(*self->sws_bps);
|
|
Petr Machata |
4b23d2c |
int i;
|
|
Petr Machata |
4b23d2c |
for (i = 0; i < ct; ++i)
|
|
Petr Machata |
4b23d2c |
- if (self->sws_bp_addrs[i] == 0) {
|
|
Petr Machata |
4b23d2c |
- self->sws_bp_addrs[i] = addr;
|
|
Petr Machata |
4b23d2c |
+ if (self->sws_bps[i] == NULL) {
|
|
Petr Machata |
4b23d2c |
static struct bp_callbacks cbs = {
|
|
Petr Machata |
4b23d2c |
.on_hit = sw_singlestep_bp_on_hit,
|
|
Petr Machata |
4b23d2c |
};
|
|
Petr Machata |
4b23d2c |
struct breakpoint *bp
|
|
Petr Machata |
4b23d2c |
= insert_breakpoint(proc, addr, NULL);
|
|
Petr Machata |
4b23d2c |
breakpoint_set_callbacks(bp, &cbs);
|
|
Petr Machata |
4b23d2c |
+ self->sws_bps[i] = bp;
|
|
Petr Machata |
4b23d2c |
return 0;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
@@ -608,7 +607,9 @@ sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
|
|
Petr Machata |
4b23d2c |
static int
|
|
Petr Machata |
4b23d2c |
singlestep(struct process_stopping_handler *self)
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
- struct process *proc = self->task_enabling_breakpoint;
|
|
Petr Machata |
4b23d2c |
+ size_t i;
|
|
Petr Machata |
4b23d2c |
+ for (i = 0; i < sizeof(self->sws_bps) / sizeof(*self->sws_bps); ++i)
|
|
Petr Machata |
4b23d2c |
+ self->sws_bps[i] = NULL;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
struct sw_singlestep_data data = { self };
|
|
Petr Machata |
4b23d2c |
switch (arch_sw_singlestep(self->task_enabling_breakpoint,
|
|
Petr Machata |
4b23d2c |
@@ -617,7 +618,8 @@ singlestep(struct process_stopping_handler *self)
|
|
Petr Machata |
4b23d2c |
case SWS_HW:
|
|
Petr Machata |
4b23d2c |
/* Otherwise do the default action: singlestep. */
|
|
Petr Machata |
4b23d2c |
debug(1, "PTRACE_SINGLESTEP");
|
|
Petr Machata |
4b23d2c |
- if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
|
|
Petr Machata |
4b23d2c |
+ if (ptrace(PTRACE_SINGLESTEP,
|
|
Petr Machata |
4b23d2c |
+ self->task_enabling_breakpoint->pid, 0, 0)) {
|
|
Petr Machata |
4b23d2c |
perror("PTRACE_SINGLESTEP");
|
|
Petr Machata |
4b23d2c |
return -1;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
@@ -1038,7 +1040,7 @@ ltrace_exiting_install_handler(struct process *proc)
|
|
Petr Machata |
4b23d2c |
struct process_vfork_handler
|
|
Petr Machata |
4b23d2c |
{
|
|
Petr Machata |
4b23d2c |
struct event_handler super;
|
|
Petr Machata |
4b23d2c |
- void *bp_addr;
|
|
Petr Machata |
4b23d2c |
+ int vfork_bp_refd:1;
|
|
Petr Machata |
4b23d2c |
};
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
static Event *
|
|
Petr Machata |
4b23d2c |
@@ -1049,38 +1051,33 @@ process_vfork_on_event(struct event_handler *super, Event *event)
|
|
Petr Machata |
4b23d2c |
event->proc->pid, event->type);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
struct process_vfork_handler *self = (void *)super;
|
|
Petr Machata |
4b23d2c |
- struct breakpoint *sbp;
|
|
Petr Machata |
4b23d2c |
+ struct process *proc = event->proc;
|
|
Petr Machata |
4b23d2c |
assert(self != NULL);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
switch (event->type) {
|
|
Petr Machata |
4b23d2c |
case EVENT_BREAKPOINT:
|
|
Petr Machata |
4b23d2c |
- /* Remember the vfork return breakpoint. */
|
|
Petr Machata |
4b23d2c |
- if (self->bp_addr == 0)
|
|
Petr Machata |
4b23d2c |
- self->bp_addr = event->e_un.brk_addr;
|
|
Petr Machata |
4b23d2c |
+ /* We turn on the vfork return breakpoint (which
|
|
Petr Machata |
4b23d2c |
+ * should be the one that we have tripped over just
|
|
Petr Machata |
4b23d2c |
+ * now) one extra time, so that the vfork parent hits
|
|
Petr Machata |
4b23d2c |
+ * it as well. */
|
|
Petr Machata |
4b23d2c |
+ if (!self->vfork_bp_refd) {
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *const sbp =
|
|
Petr Machata |
4b23d2c |
+ dict_find_entry(proc->leader->breakpoints,
|
|
Petr Machata |
4b23d2c |
+ event->e_un.brk_addr);
|
|
Petr Machata |
4b23d2c |
+ assert(sbp != NULL);
|
|
Petr Machata |
4b23d2c |
+ breakpoint_turn_on(sbp, proc->leader);
|
|
Petr Machata |
4b23d2c |
+ self->vfork_bp_refd = 1;
|
|
Petr Machata |
4b23d2c |
+ }
|
|
Petr Machata |
4b23d2c |
break;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
case EVENT_EXIT:
|
|
Petr Machata |
4b23d2c |
case EVENT_EXIT_SIGNAL:
|
|
Petr Machata |
4b23d2c |
case EVENT_EXEC:
|
|
Petr Machata |
4b23d2c |
- /* Smuggle back in the vfork return breakpoint, so
|
|
Petr Machata |
4b23d2c |
- * that our parent can trip over it once again. */
|
|
Petr Machata |
4b23d2c |
- if (self->bp_addr != 0) {
|
|
Petr Machata |
4b23d2c |
- sbp = dict_find_entry(event->proc->leader->breakpoints,
|
|
Petr Machata |
4b23d2c |
- self->bp_addr);
|
|
Petr Machata |
4b23d2c |
- if (sbp != NULL)
|
|
Petr Machata |
4b23d2c |
- assert(sbp->libsym == NULL);
|
|
Petr Machata |
4b23d2c |
- /* We don't mind failing that, it's not a big
|
|
Petr Machata |
4b23d2c |
- * deal to not display one extra vfork return. */
|
|
Petr Machata |
4b23d2c |
- insert_breakpoint(event->proc->parent,
|
|
Petr Machata |
4b23d2c |
- self->bp_addr, NULL);
|
|
Petr Machata |
4b23d2c |
- }
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
- continue_process(event->proc->parent->pid);
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
/* Remove the leader that we artificially set up
|
|
Petr Machata |
4b23d2c |
* earlier. */
|
|
Petr Machata |
4b23d2c |
- change_process_leader(event->proc, event->proc);
|
|
Petr Machata |
4b23d2c |
- destroy_event_handler(event->proc);
|
|
Petr Machata |
4b23d2c |
+ change_process_leader(proc, proc);
|
|
Petr Machata |
4b23d2c |
+ destroy_event_handler(proc);
|
|
Petr Machata |
4b23d2c |
+ continue_process(proc->parent->pid);
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
default:
|
|
Petr Machata |
4b23d2c |
;
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/trace.h b/sysdeps/linux-gnu/trace.h
|
|
Petr Machata |
4b23d2c |
index e988f70..5bb8380 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/trace.h
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/trace.h
|
|
Petr Machata |
4b23d2c |
@@ -64,8 +64,8 @@ struct process_stopping_handler
|
|
Petr Machata |
4b23d2c |
/* The pointer being re-enabled. */
|
|
Petr Machata |
4b23d2c |
struct breakpoint *breakpoint_being_enabled;
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
- /* Artificial atomic skip breakpoint, if any needed. */
|
|
Petr Machata |
4b23d2c |
- arch_addr_t sws_bp_addrs[2];
|
|
Petr Machata |
4b23d2c |
+ /* Software singlestep breakpoints, if any needed. */
|
|
Petr Machata |
4b23d2c |
+ struct breakpoint *sws_bps[2];
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
/* When all tasks are stopped, this callback gets called. */
|
|
Petr Machata |
4b23d2c |
void (*on_all_stopped)(struct process_stopping_handler *);
|
|
Petr Machata |
4b23d2c |
diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c
|
|
Petr Machata |
4b23d2c |
index 3886e84..0a42c6e 100644
|
|
Petr Machata |
4b23d2c |
--- a/sysdeps/linux-gnu/x86/regs.c
|
|
Petr Machata |
4b23d2c |
+++ b/sysdeps/linux-gnu/x86/regs.c
|
|
Petr Machata |
4b23d2c |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
4b23d2c |
/*
|
|
Petr Machata |
4b23d2c |
* This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
|
|
Petr Machata |
4b23d2c |
* Copyright (C) 2006 Ian Wienand
|
|
Petr Machata |
4b23d2c |
*
|
|
Petr Machata |
4b23d2c |
@@ -107,11 +107,3 @@ get_return_addr(struct process *proc, void *sp)
|
|
Petr Machata |
4b23d2c |
ret = conv_32(ret);
|
|
Petr Machata |
4b23d2c |
return ret;
|
|
Petr Machata |
4b23d2c |
}
|
|
Petr Machata |
4b23d2c |
-
|
|
Petr Machata |
4b23d2c |
-void
|
|
Petr Machata |
4b23d2c |
-set_return_addr(struct process *proc, void *addr)
|
|
Petr Machata |
4b23d2c |
-{
|
|
Petr Machata |
4b23d2c |
- if (proc->e_machine == EM_386)
|
|
Petr Machata |
4b23d2c |
- addr = (void *)((long int)addr & 0xffffffff);
|
|
Petr Machata |
4b23d2c |
- ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
|
|
Petr Machata |
4b23d2c |
-}
|
|
Petr Machata |
cb74839 |
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
|
|
Petr Machata |
cb74839 |
index e54086f..b585bc9 100644
|
|
Petr Machata |
cb74839 |
--- a/testsuite/ltrace.main/parameters.exp
|
|
Petr Machata |
cb74839 |
+++ b/testsuite/ltrace.main/parameters.exp
|
|
Petr Machata |
cb74839 |
@@ -35,9 +35,6 @@ if [regexp {ELF from incompatible architecture} $exec_output] {
|
|
Petr Machata |
cb74839 |
return
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
-set xfail_spec {"arm*-*" }
|
|
Petr Machata |
cb74839 |
-set xfail_spec_arm {"arm*-*"}
|
|
Petr Machata |
cb74839 |
-
|
|
Petr Machata |
cb74839 |
# Verify the output
|
|
Petr Machata |
cb74839 |
set pattern "func_intptr(17)"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
@@ -63,7 +60,6 @@ set pattern "func_ushort(33, 34)"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
set pattern "func_float(3.40*, -3.40*).*= 3.40*"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
-eval "setup_xfail $xfail_spec"
|
|
Petr Machata |
cb74839 |
set pattern "func_double(3.40*, -3.40*).*= -3.40*"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
set pattern "func_typedef(BLUE)"
|
|
Petr Machata |
cb74839 |
@@ -86,7 +82,6 @@ set pattern "func_work(\\\"x\\\")"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
set pattern "func_struct_2(17, { \\\"ABCDE\\\\\\\\0\\\", 0.250* }, 0.50*).*= { 0.250*, 'B', 'C' }"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
-eval "setup_xfail $xfail_spec_arm"
|
|
Petr Machata |
cb74839 |
set pattern "<... func_call resumed> \\\"x\\\", \\\"y\\\")"
|
|
Petr Machata |
cb74839 |
ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
4b23d2c |
diff --git a/testsuite/ltrace.torture/Makefile.am b/testsuite/ltrace.torture/Makefile.am
|
|
Petr Machata |
4b23d2c |
index daa772f..5a45265 100644
|
|
Petr Machata |
4b23d2c |
--- a/testsuite/ltrace.torture/Makefile.am
|
|
Petr Machata |
4b23d2c |
+++ b/testsuite/ltrace.torture/Makefile.am
|
|
Petr Machata |
4b23d2c |
@@ -15,15 +15,9 @@
|
|
Petr Machata |
4b23d2c |
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
Petr Machata |
4b23d2c |
#
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
-EXTRA_DIST = \
|
|
Petr Machata |
4b23d2c |
- ia64-sigill.exp \
|
|
Petr Machata |
4b23d2c |
- ia64-sigill.s \
|
|
Petr Machata |
4b23d2c |
- ppc-lwarx.c \
|
|
Petr Machata |
4b23d2c |
- ppc-lwarx.exp \
|
|
Petr Machata |
4b23d2c |
- signals.c \
|
|
Petr Machata |
4b23d2c |
- signals.exp \
|
|
Petr Machata |
4b23d2c |
- vfork-thread.c \
|
|
Petr Machata |
4b23d2c |
- vfork-thread.exp
|
|
Petr Machata |
4b23d2c |
+EXTRA_DIST = arm-singlestep.exp ia64-sigill.exp ia64-sigill.s \
|
|
Petr Machata |
4b23d2c |
+ ppc-lwarx.c ppc-lwarx.exp signals.c signals.exp \
|
|
Petr Machata |
4b23d2c |
+ vfork-thread.c vfork-thread.exp
|
|
Petr Machata |
4b23d2c |
|
|
Petr Machata |
4b23d2c |
CLEANFILES = *.o *.so *.log *.sum *.ltrace setval.tmp \
|
|
Petr Machata |
4b23d2c |
signals
|
|
Petr Machata |
4b23d2c |
diff --git a/testsuite/ltrace.torture/arm-singlestep.exp b/testsuite/ltrace.torture/arm-singlestep.exp
|
|
Petr Machata |
4b23d2c |
new file mode 100644
|
|
Petr Machata |
4b23d2c |
index 0000000..0d633d9
|
|
Petr Machata |
4b23d2c |
--- /dev/null
|
|
Petr Machata |
4b23d2c |
+++ b/testsuite/ltrace.torture/arm-singlestep.exp
|
|
Petr Machata |
4b23d2c |
@@ -0,0 +1,44 @@
|
|
Petr Machata |
4b23d2c |
+# This file is part of ltrace.
|
|
Petr Machata |
4b23d2c |
+# Copyright (C) 2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
4b23d2c |
+#
|
|
Petr Machata |
4b23d2c |
+# This program is free software; you can redistribute it and/or
|
|
Petr Machata |
4b23d2c |
+# modify it under the terms of the GNU General Public License as
|
|
Petr Machata |
4b23d2c |
+# published by the Free Software Foundation; either version 2 of the
|
|
Petr Machata |
4b23d2c |
+# License, or (at your option) any later version.
|
|
Petr Machata |
4b23d2c |
+#
|
|
Petr Machata |
4b23d2c |
+# This program is distributed in the hope that it will be useful, but
|
|
Petr Machata |
4b23d2c |
+# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Petr Machata |
4b23d2c |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Petr Machata |
4b23d2c |
+# General Public License for more details.
|
|
Petr Machata |
4b23d2c |
+#
|
|
Petr Machata |
4b23d2c |
+# You should have received a copy of the GNU General Public License
|
|
Petr Machata |
4b23d2c |
+# along with this program; if not, write to the Free Software
|
|
Petr Machata |
4b23d2c |
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Petr Machata |
4b23d2c |
+# 02110-1301 USA
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+if {![istarget arm*-*]} {
|
|
Petr Machata |
4b23d2c |
+ unsupported "arm-specific test"
|
|
Petr Machata |
4b23d2c |
+ return
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+set exe [ltraceCompile {} [ltraceSource c {
|
|
Petr Machata |
4b23d2c |
+ int puc(void) { return 0; }
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int bar(void);
|
|
Petr Machata |
4b23d2c |
+ int baz(void);
|
|
Petr Machata |
4b23d2c |
+ __asm__ (" .type bar, %function\n"
|
|
Petr Machata |
4b23d2c |
+ "bar: \n"
|
|
Petr Machata |
4b23d2c |
+ " b puc \n"
|
|
Petr Machata |
4b23d2c |
+ " .type baz, %function\n"
|
|
Petr Machata |
4b23d2c |
+ "baz: \n"
|
|
Petr Machata |
4b23d2c |
+ " b puc \n");
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ int main(void) { return bar() + baz(); }
|
|
Petr Machata |
4b23d2c |
+}]]
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ltraceMatch [ltraceRun -L -xbar+baz $exe] {
|
|
Petr Machata |
4b23d2c |
+ {{bar} == 1}
|
|
Petr Machata |
4b23d2c |
+ {{baz} == 1}
|
|
Petr Machata |
4b23d2c |
+}
|
|
Petr Machata |
4b23d2c |
+
|
|
Petr Machata |
4b23d2c |
+ltraceDone
|
|
Petr Machata |
cb74839 |
diff --git a/type.c b/type.c
|
|
Petr Machata |
cb74839 |
index d80550b..e06a9c2 100644
|
|
Petr Machata |
cb74839 |
--- a/type.c
|
|
Petr Machata |
cb74839 |
+++ b/type.c
|
|
Petr Machata |
cb74839 |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
cb74839 |
/*
|
|
Petr Machata |
cb74839 |
* This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
* Copyright (C) 2007,2008 Juan Cespedes
|
|
Petr Machata |
cb74839 |
*
|
|
Petr Machata |
cb74839 |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
cb74839 |
@@ -568,3 +568,39 @@ type_get_fp_equivalent(struct arg_type_info *info)
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
abort();
|
|
Petr Machata |
cb74839 |
}
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+struct arg_type_info *
|
|
Petr Machata |
cb74839 |
+type_get_hfa_type(struct arg_type_info *info, size_t *countp)
|
|
Petr Machata |
cb74839 |
+{
|
|
Petr Machata |
cb74839 |
+ assert(info != NULL);
|
|
Petr Machata |
cb74839 |
+ if (info->type != ARGTYPE_STRUCT
|
|
Petr Machata |
cb74839 |
+ && info->type != ARGTYPE_ARRAY)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ size_t n = type_aggregate_size(info);
|
|
Petr Machata |
cb74839 |
+ if (n == (size_t)-1)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *ret = NULL;
|
|
Petr Machata |
cb74839 |
+ *countp = 0;
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ while (n-- > 0) {
|
|
Petr Machata |
cb74839 |
+ struct arg_type_info *emt = type_element(info, n);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+ size_t emt_count = 1;
|
|
Petr Machata |
cb74839 |
+ if (emt->type == ARGTYPE_STRUCT || emt->type == ARGTYPE_ARRAY)
|
|
Petr Machata |
cb74839 |
+ emt = type_get_hfa_type(emt, &emt_count);
|
|
Petr Machata |
cb74839 |
+ if (emt == NULL)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+ if (ret == NULL) {
|
|
Petr Machata |
cb74839 |
+ if (emt->type != ARGTYPE_FLOAT
|
|
Petr Machata |
cb74839 |
+ && emt->type != ARGTYPE_DOUBLE)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+ ret = emt;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ if (emt->type != ret->type)
|
|
Petr Machata |
cb74839 |
+ return NULL;
|
|
Petr Machata |
cb74839 |
+ *countp += emt_count;
|
|
Petr Machata |
cb74839 |
+ }
|
|
Petr Machata |
cb74839 |
+ return ret;
|
|
Petr Machata |
cb74839 |
+}
|
|
Petr Machata |
cb74839 |
diff --git a/type.h b/type.h
|
|
Petr Machata |
cb74839 |
index b92c1af..3210677 100644
|
|
Petr Machata |
cb74839 |
--- a/type.h
|
|
Petr Machata |
cb74839 |
+++ b/type.h
|
|
Petr Machata |
cb74839 |
@@ -1,6 +1,6 @@
|
|
Petr Machata |
cb74839 |
/*
|
|
Petr Machata |
cb74839 |
* This file is part of ltrace.
|
|
Petr Machata |
cb74839 |
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
+ * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
|
|
Petr Machata |
cb74839 |
* Copyright (C) 1997-2009 Juan Cespedes
|
|
Petr Machata |
cb74839 |
*
|
|
Petr Machata |
cb74839 |
* This program is free software; you can redistribute it and/or
|
|
Petr Machata |
cb74839 |
@@ -142,4 +142,13 @@ int type_is_signed(enum arg_type type);
|
|
Petr Machata |
cb74839 |
* type. */
|
|
Petr Machata |
cb74839 |
struct arg_type_info *type_get_fp_equivalent(struct arg_type_info *info);
|
|
Petr Machata |
cb74839 |
|
|
Petr Machata |
cb74839 |
+/* If INFO is homogeneous floating-point aggregate, return the
|
|
Petr Machata |
cb74839 |
+ * corresponding floating point type, and set *COUNTP to number of
|
|
Petr Machata |
cb74839 |
+ * fields of the structure. Otherwise return NULL. INFO is a HFA if
|
|
Petr Machata |
cb74839 |
+ * it's an aggregate whose each field is either a HFA, or a
|
|
Petr Machata |
cb74839 |
+ * floating-point type. */
|
|
Petr Machata |
cb74839 |
+struct arg_type_info *type_get_hfa_type(struct arg_type_info *info,
|
|
Petr Machata |
cb74839 |
+ size_t *countp);
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
+
|
|
Petr Machata |
cb74839 |
#endif /* TYPE_H */
|