[PATCH 6/9] unwind: allow to specify unwinder back-end with -k option

Masatake YAMATO yamato at redhat.com
Tue Mar 13 17:28:11 UTC 2018


With this commit, -k option can take an optional argument
specifying unwinder like:

  $ strace -klibunwind ...

Here, "libunwind" is the name of unwinder. Currently only libunwind
is available as unwinder. Using libdw as unwinder is planed.

If no unwinder is given, strace choose one of available unwinders
linked in the build time.

The code introduced with this commit requires GNU extension.

* defs.h (unwind_init): add a parameter specifying unwinder.

* strace.c (init): store unwinder name to `unwinder_name' local variable
  if an unwinder is specified in -k option. The variable is passed
  to `unwind_init' function.

* unwind.c (unwinders): New array to store available unwinders.
  (unwind_init): Choose a one from the array.

Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
 defs.h   |  2 +-
 strace.c | 10 ++++++++--
 unwind.c | 25 ++++++++++++++++++++-----
 3 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/defs.h b/defs.h
index e7bb537c..450e966e 100644
--- a/defs.h
+++ b/defs.h
@@ -732,7 +732,7 @@ extern void tv_mul(struct timeval *, const struct timeval *, int);
 extern void tv_div(struct timeval *, const struct timeval *, int);
 
 #ifdef CAN_UNWIND
-extern void unwind_init(void);
+extern void unwind_init(const char *unwinder_name);
 extern void unwind_tcb_init(struct tcb *);
 extern void unwind_tcb_fin(struct tcb *);
 extern void unwind_tcb_print(struct tcb *);
diff --git a/strace.c b/strace.c
index 34e2ede7..c12b1a40 100644
--- a/strace.c
+++ b/strace.c
@@ -1583,6 +1583,9 @@ init(int argc, char *argv[])
 {
 	int c, i;
 	int optF = 0;
+#ifdef CAN_UNWIND
+	const char *unwinder_name;
+#endif
 
 	if (!program_invocation_name || !*program_invocation_name) {
 		static char name[] = "strace";
@@ -1606,7 +1609,9 @@ init(int argc, char *argv[])
 	qualify("signal=all");
 	while ((c = getopt(argc, argv, "+"
 #ifdef CAN_UNWIND
-	    "k"
+	    "k::"		/* Use GNU Extension to
+				 * take optional option argument
+				 */
 #endif
 	    "a:b:cCdDe:E:fFhiI:o:O:p:P:qrs:S:tTu:vVwxyz")) != EOF) {
 		switch (c) {
@@ -1666,6 +1671,7 @@ init(int argc, char *argv[])
 #ifdef CAN_UNWIND
 		case 'k':
 			stack_trace_enabled = true;
+			unwinder_name = optarg;
 			break;
 #endif
 		case 'o':
@@ -1797,7 +1803,7 @@ init(int argc, char *argv[])
 	if (stack_trace_enabled) {
 		unsigned int tcbi;
 
-		unwind_init();
+		unwind_init(unwinder_name);
 		for (tcbi = 0; tcbi < tcbtabsize; ++tcbi) {
 			unwind_tcb_init(tcbtab[tcbi]);
 		}
diff --git a/unwind.c b/unwind.c
index 83c5cff4..845e2d20 100644
--- a/unwind.c
+++ b/unwind.c
@@ -57,17 +57,32 @@ static const char asprintf_error_str[] = "???";
 #ifdef USE_LIBUNWIND
 extern const struct unwind_unwinder_t unwinder_libunwind;
 #endif
+
+static const struct unwind_unwinder_t *unwinders[] = {
+#ifdef USE_LIBUNWIND
+	&unwinder_libunwind,
+#endif
+};
+
 static const struct unwind_unwinder_t *unwinder;
 
 void
-unwind_init(void)
+unwind_init(const char *unwinder_name)
 {
-#ifdef USE_LIBUNWIND
-	unwinder = &unwinder_libunwind;
-#endif
+	if (!unwinder_name)
+		unwinder = unwinders[0];
+	else {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(unwinders) ; i++)
+			if (strcmp(unwinders[i]->name, unwinder_name) == 0) {
+				unwinder = unwinders[i];
+				break;
+			}
+	}
 
 	if (!unwinder)
-		error_msg_and_die("bug: no unwinder");
+		error_msg_and_die("no such unwinder: %s", unwinder_name);
 
 	if (unwinder->init)
 		unwinder->init();
-- 
2.14.3



More information about the Strace-devel mailing list