summaryrefslogtreecommitdiff
path: root/src/ldt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ldt.c')
-rw-r--r--src/ldt.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/ldt.c b/src/ldt.c
new file mode 100644
index 000000000..de93cf896
--- /dev/null
+++ b/src/ldt.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
+ * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
+ * Copyright (c) 1993-1996 Rick Sladkey <jrs@world.std.com>
+ * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
+ * 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@strace.io>
+ * Copyright (c) 2014-2018 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#ifdef HAVE_STRUCT_USER_DESC
+
+# include <asm/ldt.h>
+
+# include "xstring.h"
+
+void
+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) {
+ tprint_struct_next();
+ tprint_more_data_follows();
+ tprint_struct_end();
+ }
+
+ return;
+ }
+
+ break;
+
+ case USER_DESC_BOTH:
+ if (umove_or_printaddr(tcp, addr, &desc))
+ return;
+
+ break;
+ }
+
+ if (filter & USER_DESC_ENTERING) {
+ tprint_struct_begin();
+ 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));
+
+ *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) {
+ tprint_value_changed();
+ 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.
+ */
+ tprint_value_changed();
+ tprint_struct_begin();
+ PRINT_FIELD_ID(desc, entry_number);
+ }
+ }
+
+ tprint_struct_next();
+ PRINT_FIELD_0X(desc, base_addr);
+ tprint_struct_next();
+ PRINT_FIELD_0X(desc, limit);
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, seg_32bit, unsigned int);
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, contents, unsigned int);
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, read_exec_only, unsigned int);
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, limit_in_pages, unsigned int);
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, seg_not_present, unsigned int);
+ tprint_struct_next();
+ 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) {
+ tprint_struct_next();
+ PRINT_FIELD_U_CAST(desc, lm, unsigned int);
+ }
+# endif /* HAVE_STRUCT_USER_DESC_LM */
+
+ tprint_struct_end();
+ }
+}
+
+SYS_FUNC(modify_ldt)
+{
+ 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;
+ }
+
+ /*
+ * 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 0;
+}
+
+SYS_FUNC(set_thread_area)
+{
+ if (entering(tcp)) {
+ print_user_desc(tcp, tcp->u_arg[0], USER_DESC_BOTH);
+ } else {
+ struct user_desc desc;
+
+ if (!verbose(tcp) || syserror(tcp) ||
+ umove(tcp, tcp->u_arg[0], &desc) < 0) {
+ /* returned entry_number is not available */
+ } else {
+ static char outstr[32];
+
+ xsprintf(outstr, "entry_number=%u", desc.entry_number);
+ tcp->auxstr = outstr;
+ return RVAL_STR;
+ }
+ }
+ return 0;
+}
+
+SYS_FUNC(get_thread_area)
+{
+ print_user_desc(tcp, tcp->u_arg[0],
+ entering(tcp) ? USER_DESC_ENTERING : USER_DESC_EXITING);
+ return 0;
+}
+
+#endif /* HAVE_STRUCT_USER_DESC */
+
+#if defined(M68K) || defined(MIPS)
+SYS_FUNC(set_thread_area)
+{
+ printaddr(tcp->u_arg[0]);
+
+ return RVAL_DECODED;
+
+}
+#endif
+
+#if defined(M68K)
+SYS_FUNC(get_thread_area)
+{
+ return RVAL_DECODED | RVAL_HEX;
+}
+#endif