]> granicus.if.org Git - strace/blobdiff - ldt.c
nlattr: add unsigned int decoders that print in hex form
[strace] / ldt.c
diff --git a/ldt.c b/ldt.c
index 6880cc9fbfc50ec79208e3b4e4d350ec5e8fdc01..104abc315da6cb2b20db26221c8e8bcc0ec5bc8a 100644 (file)
--- a/ldt.c
+++ b/ldt.c
@@ -6,6 +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-2018 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 # include <asm/ldt.h>
 
+# include "print_fields.h"
+# include "xstring.h"
+
 void
-print_user_desc(struct tcb *tcp, const long 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;
 
-       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);
+       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));
+
+                       *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("%ld, ", 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(", %lu", 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 0;
 }
 
 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;
 
@@ -90,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;
                }
@@ -100,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;
 }