aboutsummaryrefslogtreecommitdiff
path: root/ldt.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldt.c')
-rw-r--r--ldt.c148
1 files changed, 114 insertions, 34 deletions
diff --git a/ldt.c b/ldt.c
index 81bc8ae3..682847ed 100644
--- a/ldt.c
+++ b/ldt.c
@@ -6,7 +6,7 @@
* Copyright (c) 2002-2004 Roland McGrath <roland@redhat.com>
* Copyright (c) 2010 Andreas Schwab <schwab@linux-m68k.org>
* Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
- * Copyright (c) 2014-2017 The strace developers.
+ * Copyright (c) 2014-2018 The strace developers.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,50 +38,130 @@
# include <asm/ldt.h>
+# include "print_fields.h"
+# include "xstring.h"
+
void
-print_user_desc(struct tcb *const tcp, const kernel_ulong_t addr)
+print_user_desc(struct tcb *const tcp, const kernel_ulong_t addr,
+ enum user_desc_print_filter filter)
{
struct user_desc desc;
+ unsigned *entry_number = get_tcb_priv_data(tcp);
+
+ switch (filter) {
+ case USER_DESC_ENTERING:
+ if (umove_or_printaddr(tcp, addr, &desc.entry_number))
+ return;
+
+ break;
+
+ case USER_DESC_EXITING:
+ if (!addr || !verbose(tcp))
+ return;
+ if (syserror(tcp) || umove(tcp, addr, &desc)) {
+ if (entry_number)
+ tprints(", ...}");
+
+ return;
+ }
+
+ break;
+
+ case USER_DESC_BOTH:
+ if (umove_or_printaddr(tcp, addr, &desc))
+ return;
+
+ break;
+ }
+
+ if (filter & USER_DESC_ENTERING) {
+ PRINT_FIELD_ID("{", desc, entry_number);
+
+ /*
+ * If we don't print the whole structure now, let's save it for
+ * later.
+ */
+ if (filter == USER_DESC_ENTERING) {
+ entry_number = xmalloc(sizeof(*entry_number));
- if (umove_or_printaddr(tcp, addr, &desc))
- return;
-
- tprintf("{entry_number:%d, "
- "base_addr:%#08x, "
- "limit:%d, "
- "seg_32bit:%d, "
- "contents:%d, "
- "read_exec_only:%d, "
- "limit_in_pages:%d, "
- "seg_not_present:%d, "
- "useable:%d}",
- desc.entry_number,
- desc.base_addr,
- desc.limit,
- desc.seg_32bit,
- desc.contents,
- desc.read_exec_only,
- desc.limit_in_pages,
- desc.seg_not_present,
- desc.useable);
+ *entry_number = desc.entry_number;
+ set_tcb_priv_data(tcp, entry_number, free);
+ }
+ }
+
+ if (filter & USER_DESC_EXITING) {
+ /*
+ * It should be the same in case of get_thread_area, but we can
+ * never be sure...
+ */
+ if (filter == USER_DESC_EXITING) {
+ if (entry_number) {
+ if (*entry_number != desc.entry_number) {
+ if ((int) desc.entry_number == -1)
+ tprints(" => -1");
+ else
+ tprintf(" => %u",
+ desc.entry_number);
+ }
+ } else {
+ /*
+ * This is really strange. If we are here, it
+ * means that we failed on entering but somehow
+ * succeeded on exiting.
+ */
+ PRINT_FIELD_ID(" => {", desc, entry_number);
+ }
+ }
+
+ PRINT_FIELD_0X(", ", desc, base_addr);
+ PRINT_FIELD_0X(", ", desc, limit);
+ PRINT_FIELD_U_CAST(", ", desc, seg_32bit, unsigned int);
+ PRINT_FIELD_U_CAST(", ", desc, contents, unsigned int);
+ PRINT_FIELD_U_CAST(", ", desc, read_exec_only, unsigned int);
+ PRINT_FIELD_U_CAST(", ", desc, limit_in_pages, unsigned int);
+ PRINT_FIELD_U_CAST(", ", desc, seg_not_present, unsigned int);
+ PRINT_FIELD_U_CAST(", ", desc, useable, unsigned int);
+
+# ifdef HAVE_STRUCT_USER_DESC_LM
+ /* lm is totally ignored for 32-bit processes */
+ if (current_klongsize == 8)
+ PRINT_FIELD_U_CAST(", ", desc, lm, unsigned int);
+# endif /* HAVE_STRUCT_USER_DESC_LM */
+
+ tprints("}");
+ }
}
SYS_FUNC(modify_ldt)
{
- tprintf("%" PRI_kld ", ", tcp->u_arg[0]);
- if (tcp->u_arg[2] != sizeof(struct user_desc))
- printaddr(tcp->u_arg[1]);
- else
- print_user_desc(tcp, tcp->u_arg[1]);
- tprintf(", %" PRI_klu, tcp->u_arg[2]);
+ if (entering(tcp)) {
+ tprintf("%d, ", (int) tcp->u_arg[0]);
+ if (tcp->u_arg[2] != sizeof(struct user_desc))
+ printaddr(tcp->u_arg[1]);
+ else
+ print_user_desc(tcp, tcp->u_arg[1], USER_DESC_BOTH);
+ tprintf(", %" PRI_klu, tcp->u_arg[2]);
+
+ return 0;
+ }
- return RVAL_DECODED;
+ /*
+ * For some reason ("tht ABI for sys_modify_ldt() expects
+ * 'int'"), modify_ldt clips higher bits on x86_64.
+ */
+
+ if (syserror(tcp) || (kernel_ulong_t) tcp->u_rval < 0xfffff000)
+ return 0;
+
+ tcp->u_error = -(unsigned int) tcp->u_rval;
+
+ return RVAL_PRINT_ERR_VAL;
}
SYS_FUNC(set_thread_area)
{
if (entering(tcp)) {
- print_user_desc(tcp, tcp->u_arg[0]);
+ print_user_desc(tcp, tcp->u_arg[0], USER_DESC_BOTH);
} else {
struct user_desc desc;
@@ -91,7 +171,7 @@ SYS_FUNC(set_thread_area)
} else {
static char outstr[32];
- sprintf(outstr, "entry_number:%d", desc.entry_number);
+ xsprintf(outstr, "entry_number=%u", desc.entry_number);
tcp->auxstr = outstr;
return RVAL_STR;
}
@@ -101,8 +181,8 @@ SYS_FUNC(set_thread_area)
SYS_FUNC(get_thread_area)
{
- if (exiting(tcp))
- print_user_desc(tcp, tcp->u_arg[0]);
+ print_user_desc(tcp, tcp->u_arg[0],
+ entering(tcp) ? USER_DESC_ENTERING : USER_DESC_EXITING);
return 0;
}