diff options
Diffstat (limited to 'ldt.c')
-rw-r--r-- | ldt.c | 148 |
1 files changed, 114 insertions, 34 deletions
@@ -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; } |