Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl> |
| 3 | * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl> |
| 4 | * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com> |
Wichert Akkerman | 4dc8a2a | 1999-12-23 14:20:14 +0000 | [diff] [blame] | 5 | * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl> |
| 6 | * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation |
| 7 | * Linux for s390 port by D.J. Barrow |
| 8 | * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com> |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 9 | * Copyright (c) 1999-2018 The strace developers. |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 10 | * All rights reserved. |
| 11 | * |
| 12 | * Redistribution and use in source and binary forms, with or without |
| 13 | * modification, are permitted provided that the following conditions |
| 14 | * are met: |
| 15 | * 1. Redistributions of source code must retain the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer. |
| 17 | * 2. Redistributions in binary form must reproduce the above copyright |
| 18 | * notice, this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * 3. The name of the author may not be used to endorse or promote products |
| 21 | * derived from this software without specific prior written permission. |
| 22 | * |
| 23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 26 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 28 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 32 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 33 | */ |
| 34 | |
| 35 | #include "defs.h" |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 36 | #include "mmap_notify.h" |
Dmitry V. Levin | e2fb0bb | 2015-09-15 21:51:15 +0000 | [diff] [blame] | 37 | #include "native_defs.h" |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 38 | #include "ptrace.h" |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 39 | #include "nsig.h" |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 40 | #include "number_set.h" |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 41 | #include "delay.h" |
| 42 | #include "retval.h" |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 43 | #include <limits.h> |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 44 | |
Dmitry V. Levin | 5503dd2 | 2015-02-13 02:12:14 +0000 | [diff] [blame] | 45 | /* for struct iovec */ |
| 46 | #include <sys/uio.h> |
Maarten ter Huurne | 40c174b | 2014-10-20 01:02:48 +0200 | [diff] [blame] | 47 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 48 | /* for __X32_SYSCALL_BIT */ |
| 49 | #include <asm/unistd.h> |
| 50 | |
Dmitry V. Levin | 7211dbc | 2015-02-28 12:20:21 +0000 | [diff] [blame] | 51 | #include "regs.h" |
Wichert Akkerman | 15dea97 | 1999-10-06 13:06:34 +0000 | [diff] [blame] | 52 | |
Denys Vlasenko | 8470374 | 2012-02-25 02:38:52 +0100 | [diff] [blame] | 53 | #if defined(SPARC64) |
Roland McGrath | 6d1a65c | 2004-07-12 07:44:08 +0000 | [diff] [blame] | 54 | # undef PTRACE_GETREGS |
| 55 | # define PTRACE_GETREGS PTRACE_GETREGS64 |
| 56 | # undef PTRACE_SETREGS |
| 57 | # define PTRACE_SETREGS PTRACE_SETREGS64 |
Denys Vlasenko | 8470374 | 2012-02-25 02:38:52 +0100 | [diff] [blame] | 58 | #endif |
Roland McGrath | 6d1a65c | 2004-07-12 07:44:08 +0000 | [diff] [blame] | 59 | |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 60 | #include "syscall.h" |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 61 | #include "xstring.h" |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 62 | |
| 63 | /* Define these shorthand notations to simplify the syscallent files. */ |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 64 | #include "sysent_shorthand_defs.h" |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 65 | |
Szabolcs Nagy | 34683e3 | 2015-12-15 18:32:17 +0000 | [diff] [blame] | 66 | #define SEN(syscall_name) SEN_ ## syscall_name, SYS_FUNC_NAME(sys_ ## syscall_name) |
Elvira Khabirova | 140ecf8 | 2015-07-10 22:24:48 +0300 | [diff] [blame] | 67 | |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 68 | const struct_sysent sysent0[] = { |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 69 | #include "syscallent.h" |
| 70 | }; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 71 | |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 72 | #if SUPPORTED_PERSONALITIES > 1 |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 73 | # include PERSONALITY1_INCLUDE_FUNCS |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 74 | static const struct_sysent sysent1[] = { |
Denys Vlasenko | 523635f | 2012-02-25 02:44:25 +0100 | [diff] [blame] | 75 | # include "syscallent1.h" |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 76 | }; |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 77 | #endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 78 | |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 79 | #if SUPPORTED_PERSONALITIES > 2 |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 80 | # include PERSONALITY2_INCLUDE_FUNCS |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 81 | static const struct_sysent sysent2[] = { |
Denys Vlasenko | 523635f | 2012-02-25 02:44:25 +0100 | [diff] [blame] | 82 | # include "syscallent2.h" |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 83 | }; |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 84 | #endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 85 | |
| 86 | /* Now undef them since short defines cause wicked namespace pollution. */ |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 87 | #include "sysent_shorthand_undefs.h" |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 88 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 89 | const char *const errnoent[] = { |
| 90 | #include "errnoent.h" |
| 91 | }; |
| 92 | const char *const signalent[] = { |
| 93 | #include "signalent.h" |
| 94 | |
| 95 | }; |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 96 | /* |
Dmitry V. Levin | df7aa2b | 2015-01-19 17:02:16 +0000 | [diff] [blame] | 97 | * `ioctlent[012].h' files are automatically generated by the auxiliary |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 98 | * program `ioctlsort', such that the list is sorted by the `code' field. |
| 99 | * This has the side-effect of resolving the _IO.. macros into |
| 100 | * plain integers, eliminating the need to include here everything |
| 101 | * in "/usr/include". |
| 102 | */ |
| 103 | |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 104 | const struct_ioctlent ioctlent0[] = { |
Dmitry V. Levin | df7aa2b | 2015-01-19 17:02:16 +0000 | [diff] [blame] | 105 | #include "ioctlent0.h" |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 106 | }; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 107 | |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 108 | #if SUPPORTED_PERSONALITIES > 1 |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 109 | static const struct_ioctlent ioctlent1[] = { |
Denys Vlasenko | 523635f | 2012-02-25 02:44:25 +0100 | [diff] [blame] | 110 | # include "ioctlent1.h" |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 111 | }; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 112 | # include PERSONALITY0_INCLUDE_PRINTERS_DECLS |
| 113 | static const struct_printers printers0 = { |
| 114 | # include PERSONALITY0_INCLUDE_PRINTERS_DEFS |
| 115 | }; |
| 116 | # include PERSONALITY1_INCLUDE_PRINTERS_DECLS |
| 117 | static const struct_printers printers1 = { |
| 118 | # include PERSONALITY1_INCLUDE_PRINTERS_DEFS |
| 119 | }; |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 120 | #endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 121 | |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 122 | #if SUPPORTED_PERSONALITIES > 2 |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 123 | static const struct_ioctlent ioctlent2[] = { |
Denys Vlasenko | 523635f | 2012-02-25 02:44:25 +0100 | [diff] [blame] | 124 | # include "ioctlent2.h" |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 125 | }; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 126 | # include PERSONALITY2_INCLUDE_PRINTERS_DECLS |
| 127 | static const struct_printers printers2 = { |
| 128 | # include PERSONALITY2_INCLUDE_PRINTERS_DEFS |
| 129 | }; |
Denys Vlasenko | 39fca62 | 2011-08-20 02:12:33 +0200 | [diff] [blame] | 130 | #endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 131 | |
Dmitry V. Levin | e6f5524 | 2013-02-26 22:02:30 +0000 | [diff] [blame] | 132 | enum { |
| 133 | nsyscalls0 = ARRAY_SIZE(sysent0) |
| 134 | #if SUPPORTED_PERSONALITIES > 1 |
| 135 | , nsyscalls1 = ARRAY_SIZE(sysent1) |
| 136 | # if SUPPORTED_PERSONALITIES > 2 |
| 137 | , nsyscalls2 = ARRAY_SIZE(sysent2) |
| 138 | # endif |
| 139 | #endif |
| 140 | }; |
| 141 | |
| 142 | enum { |
Dmitry V. Levin | e6f5524 | 2013-02-26 22:02:30 +0000 | [diff] [blame] | 143 | nioctlents0 = ARRAY_SIZE(ioctlent0) |
| 144 | #if SUPPORTED_PERSONALITIES > 1 |
| 145 | , nioctlents1 = ARRAY_SIZE(ioctlent1) |
| 146 | # if SUPPORTED_PERSONALITIES > 2 |
| 147 | , nioctlents2 = ARRAY_SIZE(ioctlent2) |
| 148 | # endif |
| 149 | #endif |
| 150 | }; |
| 151 | |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 152 | #if SUPPORTED_PERSONALITIES > 1 |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 153 | const struct_sysent *sysent = sysent0; |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 154 | const struct_ioctlent *ioctlent = ioctlent0; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 155 | const struct_printers *printers = &printers0; |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 156 | #endif |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 157 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 158 | const unsigned int nerrnos = ARRAY_SIZE(errnoent); |
| 159 | const unsigned int nsignals = ARRAY_SIZE(signalent); |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 160 | unsigned nsyscalls = nsyscalls0; |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 161 | unsigned nioctlents = nioctlents0; |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 162 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 163 | const unsigned int nsyscall_vec[SUPPORTED_PERSONALITIES] = { |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 164 | nsyscalls0, |
| 165 | #if SUPPORTED_PERSONALITIES > 1 |
| 166 | nsyscalls1, |
| 167 | #endif |
| 168 | #if SUPPORTED_PERSONALITIES > 2 |
| 169 | nsyscalls2, |
| 170 | #endif |
| 171 | }; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 172 | const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES] = { |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 173 | sysent0, |
| 174 | #if SUPPORTED_PERSONALITIES > 1 |
| 175 | sysent1, |
| 176 | #endif |
| 177 | #if SUPPORTED_PERSONALITIES > 2 |
| 178 | sysent2, |
| 179 | #endif |
| 180 | }; |
| 181 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 182 | const char *const personality_names[] = |
| 183 | # if defined X86_64 |
| 184 | {"64 bit", "32 bit", "x32"} |
| 185 | # elif defined X32 |
| 186 | {"x32", "32 bit"} |
| 187 | # elif SUPPORTED_PERSONALITIES == 2 |
| 188 | {"64 bit", "32 bit"} |
| 189 | # else |
| 190 | {STRINGIFY_VAL(__WORDSIZE) " bit"} |
| 191 | # endif |
| 192 | ; |
| 193 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 194 | const char *const personality_designators[] = |
| 195 | # if defined X86_64 |
| 196 | { "64", "32", "x32" } |
| 197 | # elif defined X32 |
| 198 | { "x32", "32" } |
| 199 | # elif SUPPORTED_PERSONALITIES == 2 |
| 200 | { "64", "32" } |
| 201 | # else |
| 202 | { STRINGIFY_VAL(__WORDSIZE) } |
| 203 | # endif |
| 204 | ; |
| 205 | |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 206 | #if SUPPORTED_PERSONALITIES > 1 |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 207 | |
Denys Vlasenko | ae8643e | 2013-02-15 14:55:14 +0100 | [diff] [blame] | 208 | unsigned current_personality; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 209 | |
Denys Vlasenko | ae8643e | 2013-02-15 14:55:14 +0100 | [diff] [blame] | 210 | # ifndef current_wordsize |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 211 | unsigned current_wordsize = PERSONALITY0_WORDSIZE; |
Denys Vlasenko | ae8643e | 2013-02-15 14:55:14 +0100 | [diff] [blame] | 212 | static const int personality_wordsize[SUPPORTED_PERSONALITIES] = { |
Roland McGrath | 4b2dcca | 2006-01-12 10:18:53 +0000 | [diff] [blame] | 213 | PERSONALITY0_WORDSIZE, |
Roland McGrath | 4b2dcca | 2006-01-12 10:18:53 +0000 | [diff] [blame] | 214 | PERSONALITY1_WORDSIZE, |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 215 | # if SUPPORTED_PERSONALITIES > 2 |
Roland McGrath | 4b2dcca | 2006-01-12 10:18:53 +0000 | [diff] [blame] | 216 | PERSONALITY2_WORDSIZE, |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 217 | # endif |
Denys Vlasenko | 5c774b2 | 2011-08-20 01:50:09 +0200 | [diff] [blame] | 218 | }; |
Denys Vlasenko | ae8643e | 2013-02-15 14:55:14 +0100 | [diff] [blame] | 219 | # endif |
Roland McGrath | 4b2dcca | 2006-01-12 10:18:53 +0000 | [diff] [blame] | 220 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 221 | # ifndef current_klongsize |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 222 | unsigned current_klongsize = PERSONALITY0_KLONGSIZE; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 223 | static const int personality_klongsize[SUPPORTED_PERSONALITIES] = { |
| 224 | PERSONALITY0_KLONGSIZE, |
| 225 | PERSONALITY1_KLONGSIZE, |
| 226 | # if SUPPORTED_PERSONALITIES > 2 |
| 227 | PERSONALITY2_KLONGSIZE, |
| 228 | # endif |
| 229 | }; |
| 230 | # endif |
| 231 | |
Denys Vlasenko | 5c774b2 | 2011-08-20 01:50:09 +0200 | [diff] [blame] | 232 | void |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 233 | set_personality(unsigned int personality) |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 234 | { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 235 | if (personality == current_personality) |
| 236 | return; |
| 237 | |
| 238 | if (personality >= SUPPORTED_PERSONALITIES) |
| 239 | error_msg_and_die("Requested switch to unsupported personality " |
| 240 | "%u", personality); |
| 241 | |
Denys Vlasenko | 9cbc15b | 2013-02-22 13:37:36 +0100 | [diff] [blame] | 242 | nsyscalls = nsyscall_vec[personality]; |
| 243 | sysent = sysent_vec[personality]; |
| 244 | |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 245 | switch (personality) { |
| 246 | case 0: |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 247 | ioctlent = ioctlent0; |
| 248 | nioctlents = nioctlents0; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 249 | printers = &printers0; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 250 | break; |
| 251 | |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 252 | case 1: |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 253 | ioctlent = ioctlent1; |
| 254 | nioctlents = nioctlents1; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 255 | printers = &printers1; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 256 | break; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 257 | |
Denys Vlasenko | a9fe13c | 2013-02-22 13:26:10 +0100 | [diff] [blame] | 258 | # if SUPPORTED_PERSONALITIES > 2 |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 259 | case 2: |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 260 | ioctlent = ioctlent2; |
| 261 | nioctlents = nioctlents2; |
Elvira Khabirova | 0929422 | 2015-08-04 01:47:02 +0300 | [diff] [blame] | 262 | printers = &printers2; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 263 | break; |
Denys Vlasenko | 9fd4f96 | 2012-03-19 09:36:42 +0100 | [diff] [blame] | 264 | # endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 265 | } |
| 266 | |
| 267 | current_personality = personality; |
Denys Vlasenko | ae8643e | 2013-02-15 14:55:14 +0100 | [diff] [blame] | 268 | # ifndef current_wordsize |
| 269 | current_wordsize = personality_wordsize[personality]; |
| 270 | # endif |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 271 | # ifndef current_klongsize |
| 272 | current_klongsize = personality_klongsize[personality]; |
| 273 | # endif |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 274 | } |
| 275 | |
Dmitry V. Levin | a5a839a | 2011-12-23 00:50:49 +0000 | [diff] [blame] | 276 | static void |
Dmitry V. Levin | 3ed5d02 | 2014-09-10 13:46:04 +0000 | [diff] [blame] | 277 | update_personality(struct tcb *tcp, unsigned int personality) |
Dmitry V. Levin | a5a839a | 2011-12-23 00:50:49 +0000 | [diff] [blame] | 278 | { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 279 | static bool need_mpers_warning[] = |
| 280 | { false, !HAVE_PERSONALITY_1_MPERS, !HAVE_PERSONALITY_2_MPERS }; |
| 281 | |
Dmitry V. Levin | a5a839a | 2011-12-23 00:50:49 +0000 | [diff] [blame] | 282 | set_personality(personality); |
| 283 | |
| 284 | if (personality == tcp->currpers) |
| 285 | return; |
| 286 | tcp->currpers = personality; |
| 287 | |
Dmitry V. Levin | a5a839a | 2011-12-23 00:50:49 +0000 | [diff] [blame] | 288 | if (!qflag) { |
Dmitry V. Levin | 6c8ef05 | 2015-05-25 22:51:19 +0000 | [diff] [blame] | 289 | error_msg("[ Process PID=%d runs in %s mode. ]", |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 290 | tcp->pid, personality_names[personality]); |
Chris Metcalf | 0b99a8a | 2013-02-05 17:48:33 +0100 | [diff] [blame] | 291 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 292 | |
| 293 | if (need_mpers_warning[personality]) { |
| 294 | error_msg("WARNING: Proper structure decoding for this " |
| 295 | "personality is not supported, please consider " |
| 296 | "building strace with mpers support enabled."); |
| 297 | need_mpers_warning[personality] = false; |
| 298 | } |
Dmitry V. Levin | a5a839a | 2011-12-23 00:50:49 +0000 | [diff] [blame] | 299 | } |
| 300 | #endif |
Roland McGrath | e10e62a | 2004-09-04 04:20:43 +0000 | [diff] [blame] | 301 | |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 302 | #ifdef SYS_socket_subcall |
Roland McGrath | a4d4853 | 2005-06-08 20:45:28 +0000 | [diff] [blame] | 303 | static void |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 304 | decode_socket_subcall(struct tcb *tcp) |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 305 | { |
Dmitry V. Levin | e0a0d89 | 2016-07-20 01:49:25 +0000 | [diff] [blame] | 306 | const int call = tcp->u_arg[0]; |
Wichert Akkerman | bf79f2e | 2000-09-01 21:03:06 +0000 | [diff] [blame] | 307 | |
Dmitry V. Levin | e0a0d89 | 2016-07-20 01:49:25 +0000 | [diff] [blame] | 308 | if (call < 1 || call >= SYS_socket_nsubcalls) |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 309 | return; |
| 310 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 311 | const kernel_ulong_t scno = SYS_socket_subcall + call; |
Dmitry V. Levin | e0a0d89 | 2016-07-20 01:49:25 +0000 | [diff] [blame] | 312 | const unsigned int nargs = sysent[scno].nargs; |
| 313 | uint64_t buf[nargs]; |
Dmitry V. Levin | c215569 | 2015-03-22 15:52:40 +0000 | [diff] [blame] | 314 | |
Dmitry V. Levin | e0a0d89 | 2016-07-20 01:49:25 +0000 | [diff] [blame] | 315 | if (umoven(tcp, tcp->u_arg[1], nargs * current_wordsize, buf) < 0) |
| 316 | return; |
| 317 | |
| 318 | tcp->scno = scno; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 319 | tcp->qual_flg = qual_flags(scno); |
Dmitry V. Levin | e0a0d89 | 2016-07-20 01:49:25 +0000 | [diff] [blame] | 320 | tcp->s_ent = &sysent[scno]; |
| 321 | |
| 322 | unsigned int i; |
| 323 | for (i = 0; i < nargs; ++i) |
| 324 | tcp->u_arg[i] = (sizeof(uint32_t) == current_wordsize) |
Dmitry V. Levin | de5b009 | 2016-07-26 15:59:28 +0000 | [diff] [blame] | 325 | ? ((uint32_t *) (void *) buf)[i] : buf[i]; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 326 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 327 | #endif /* SYS_socket_subcall */ |
Mike Frysinger | 3362e89 | 2012-03-15 01:09:19 -0400 | [diff] [blame] | 328 | |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 329 | #ifdef SYS_ipc_subcall |
| 330 | static void |
| 331 | decode_ipc_subcall(struct tcb *tcp) |
| 332 | { |
Dmitry V. Levin | b412d75 | 2016-07-22 01:17:25 +0000 | [diff] [blame] | 333 | unsigned int call = tcp->u_arg[0]; |
| 334 | const unsigned int version = call >> 16; |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 335 | |
Dmitry V. Levin | b412d75 | 2016-07-22 01:17:25 +0000 | [diff] [blame] | 336 | if (version) { |
| 337 | # if defined S390 || defined S390X |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 338 | return; |
Dmitry V. Levin | b412d75 | 2016-07-22 01:17:25 +0000 | [diff] [blame] | 339 | # else |
| 340 | # ifdef SPARC64 |
| 341 | if (current_wordsize == 8) |
| 342 | return; |
| 343 | # endif |
| 344 | set_tcb_priv_ulong(tcp, version); |
| 345 | call &= 0xffff; |
| 346 | # endif |
| 347 | } |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 348 | |
Dmitry V. Levin | b412d75 | 2016-07-22 01:17:25 +0000 | [diff] [blame] | 349 | switch (call) { |
| 350 | case 1: case 2: case 3: case 4: |
| 351 | case 11: case 12: case 13: case 14: |
| 352 | case 21: case 22: case 23: case 24: |
| 353 | break; |
| 354 | default: |
| 355 | return; |
| 356 | } |
| 357 | |
| 358 | tcp->scno = SYS_ipc_subcall + call; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 359 | tcp->qual_flg = qual_flags(tcp->scno); |
Denys Vlasenko | 74ec14f | 2013-02-21 16:13:47 +0100 | [diff] [blame] | 360 | tcp->s_ent = &sysent[tcp->scno]; |
Dmitry V. Levin | b412d75 | 2016-07-22 01:17:25 +0000 | [diff] [blame] | 361 | |
| 362 | const unsigned int n = tcp->s_ent->nargs; |
| 363 | unsigned int i; |
Denys Vlasenko | 74ec14f | 2013-02-21 16:13:47 +0100 | [diff] [blame] | 364 | for (i = 0; i < n; i++) |
Dmitry V. Levin | 648c22c | 2012-03-15 22:08:55 +0000 | [diff] [blame] | 365 | tcp->u_arg[i] = tcp->u_arg[i + 1]; |
| 366 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 367 | #endif /* SYS_ipc_subcall */ |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 368 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 369 | #ifdef SYS_syscall_subcall |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 370 | static void |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 371 | decode_syscall_subcall(struct tcb *tcp) |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 372 | { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 373 | if (!scno_is_valid(tcp->u_arg[0])) |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 374 | return; |
| 375 | tcp->scno = tcp->u_arg[0]; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 376 | tcp->qual_flg = qual_flags(tcp->scno); |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 377 | tcp->s_ent = &sysent[tcp->scno]; |
| 378 | memmove(&tcp->u_arg[0], &tcp->u_arg[1], |
| 379 | sizeof(tcp->u_arg) - sizeof(tcp->u_arg[0])); |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 380 | # ifdef LINUX_MIPSO32 |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 381 | /* |
| 382 | * Fetching the last arg of 7-arg syscalls (fadvise64_64 |
Dmitry V. Levin | 54a4a1a | 2016-09-28 01:57:59 +0000 | [diff] [blame] | 383 | * and sync_file_range) requires additional code, |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 384 | * see linux/mips/get_syscall_args.c |
| 385 | */ |
Dmitry V. Levin | 54a4a1a | 2016-09-28 01:57:59 +0000 | [diff] [blame] | 386 | if (tcp->s_ent->nargs == MAX_ARGS) { |
| 387 | if (umoven(tcp, |
| 388 | mips_REG_SP + MAX_ARGS * sizeof(tcp->u_arg[0]), |
| 389 | sizeof(tcp->u_arg[0]), |
| 390 | &tcp->u_arg[MAX_ARGS - 1]) < 0) |
| 391 | tcp->u_arg[MAX_ARGS - 1] = 0; |
| 392 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 393 | # endif /* LINUX_MIPSO32 */ |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 394 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 395 | #endif /* SYS_syscall_subcall */ |
Dmitry V. Levin | f34b97f | 2015-04-17 09:14:19 +0000 | [diff] [blame] | 396 | |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 397 | static void |
| 398 | dumpio(struct tcb *tcp) |
| 399 | { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 400 | int fd = tcp->u_arg[0]; |
| 401 | if (fd < 0) |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 402 | return; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 403 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 404 | if (is_number_in_set(fd, write_set)) { |
| 405 | switch (tcp->s_ent->sen) { |
| 406 | case SEN_write: |
| 407 | case SEN_pwrite: |
| 408 | case SEN_send: |
| 409 | case SEN_sendto: |
| 410 | case SEN_mq_timedsend: |
| 411 | dumpstr(tcp, tcp->u_arg[1], tcp->u_arg[2]); |
| 412 | break; |
| 413 | case SEN_writev: |
| 414 | case SEN_pwritev: |
| 415 | case SEN_pwritev2: |
| 416 | case SEN_vmsplice: |
| 417 | dumpiov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], -1); |
| 418 | break; |
| 419 | case SEN_sendmsg: |
| 420 | dumpiov_in_msghdr(tcp, tcp->u_arg[1], -1); |
| 421 | break; |
| 422 | case SEN_sendmmsg: |
| 423 | dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]); |
| 424 | break; |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | if (syserror(tcp)) |
| 429 | return; |
| 430 | |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 431 | if (is_number_in_set(fd, read_set)) { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 432 | switch (tcp->s_ent->sen) { |
Elvira Khabirova | 483c15f | 2015-07-10 22:24:58 +0300 | [diff] [blame] | 433 | case SEN_read: |
| 434 | case SEN_pread: |
| 435 | case SEN_recv: |
| 436 | case SEN_recvfrom: |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 437 | case SEN_mq_timedreceive: |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 438 | dumpstr(tcp, tcp->u_arg[1], tcp->u_rval); |
| 439 | return; |
Elvira Khabirova | 483c15f | 2015-07-10 22:24:58 +0300 | [diff] [blame] | 440 | case SEN_readv: |
Dmitry V. Levin | 3f6ebce | 2016-03-31 00:01:58 +0000 | [diff] [blame] | 441 | case SEN_preadv: |
Dmitry V. Levin | a6dd094 | 2016-05-11 00:42:10 +0000 | [diff] [blame] | 442 | case SEN_preadv2: |
Dmitry V. Levin | 05a0af6 | 2016-01-20 00:17:02 +0000 | [diff] [blame] | 443 | dumpiov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], |
| 444 | tcp->u_rval); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 445 | return; |
Elvira Khabirova | 483c15f | 2015-07-10 22:24:58 +0300 | [diff] [blame] | 446 | case SEN_recvmsg: |
Dmitry V. Levin | 93c9d1c | 2016-01-20 03:26:37 +0000 | [diff] [blame] | 447 | dumpiov_in_msghdr(tcp, tcp->u_arg[1], tcp->u_rval); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 448 | return; |
Elvira Khabirova | 483c15f | 2015-07-10 22:24:58 +0300 | [diff] [blame] | 449 | case SEN_recvmmsg: |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 450 | dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]); |
| 451 | return; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 452 | } |
| 453 | } |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 454 | } |
| 455 | |
Eugene Syromyatnikov | 6fdb104 | 2016-09-29 15:56:27 +0300 | [diff] [blame] | 456 | const char * |
| 457 | err_name(unsigned long err) |
| 458 | { |
| 459 | if ((err < nerrnos) && errnoent[err]) |
| 460 | return errnoent[err]; |
| 461 | |
| 462 | return NULL; |
| 463 | } |
| 464 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 465 | static void |
| 466 | print_err_ret(kernel_ulong_t ret, unsigned long u_error) |
| 467 | { |
| 468 | const char *u_error_str = err_name(u_error); |
| 469 | |
| 470 | if (u_error_str) |
| 471 | tprintf("= %" PRI_kld " %s (%s)", |
| 472 | ret, u_error_str, strerror(u_error)); |
| 473 | else |
| 474 | tprintf("= %" PRI_kld " (errno %lu)", ret, u_error); |
| 475 | } |
| 476 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 477 | static long get_regs(struct tcb *); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 478 | static int get_syscall_args(struct tcb *); |
| 479 | static int get_syscall_result(struct tcb *); |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 480 | static int arch_get_scno(struct tcb *tcp); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 481 | static int arch_set_scno(struct tcb *, kernel_ulong_t); |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 482 | static void get_error(struct tcb *, const bool); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 483 | static int arch_set_error(struct tcb *); |
| 484 | static int arch_set_success(struct tcb *); |
| 485 | |
| 486 | struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; |
| 487 | |
| 488 | static struct inject_opts * |
| 489 | tcb_inject_opts(struct tcb *tcp) |
| 490 | { |
| 491 | return (scno_in_range(tcp->scno) && tcp->inject_vec[current_personality]) |
| 492 | ? &tcp->inject_vec[current_personality][tcp->scno] : NULL; |
| 493 | } |
| 494 | |
| 495 | |
| 496 | static long |
| 497 | tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo) |
| 498 | { |
| 499 | if (!tcp->inject_vec[current_personality]) { |
| 500 | tcp->inject_vec[current_personality] = |
| 501 | xcalloc(nsyscalls, sizeof(**inject_vec)); |
| 502 | memcpy(tcp->inject_vec[current_personality], |
| 503 | inject_vec[current_personality], |
| 504 | nsyscalls * sizeof(**inject_vec)); |
| 505 | } |
| 506 | |
| 507 | struct inject_opts *opts = tcb_inject_opts(tcp); |
| 508 | |
| 509 | if (!opts || opts->first == 0) |
| 510 | return 0; |
| 511 | |
| 512 | --opts->first; |
| 513 | |
| 514 | if (opts->first != 0) |
| 515 | return 0; |
| 516 | |
| 517 | opts->first = opts->step; |
| 518 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 519 | if (!recovering(tcp)) { |
| 520 | if (opts->data.flags & INJECT_F_SIGNAL) |
| 521 | *signo = opts->data.signo; |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 522 | if (opts->data.flags & (INJECT_F_ERROR | INJECT_F_RETVAL)) { |
| 523 | kernel_long_t scno = |
| 524 | (opts->data.flags & INJECT_F_SYSCALL) |
| 525 | ? (kernel_long_t) shuffle_scno(opts->data.scno) |
| 526 | : -1; |
| 527 | |
| 528 | if (!arch_set_scno(tcp, scno)) { |
| 529 | tcp->flags |= TCB_TAMPERED; |
| 530 | if (scno != -1) |
| 531 | tcp->flags |= TCB_TAMPERED_NO_FAIL; |
| 532 | } |
| 533 | } |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 534 | if (opts->data.flags & INJECT_F_DELAY_ENTER) |
| 535 | delay_tcb(tcp, opts->data.delay_idx, true); |
| 536 | if (opts->data.flags & INJECT_F_DELAY_EXIT) |
| 537 | tcp->flags |= TCB_INJECT_DELAY_EXIT; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 538 | } |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 539 | |
| 540 | return 0; |
| 541 | } |
| 542 | |
| 543 | static long |
| 544 | tamper_with_syscall_exiting(struct tcb *tcp) |
| 545 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 546 | struct inject_opts *opts = tcb_inject_opts(tcp); |
| 547 | if (!opts) |
| 548 | return 0; |
| 549 | |
| 550 | if (inject_delay_exit(tcp)) |
| 551 | delay_tcb(tcp, opts->data.delay_idx, false); |
| 552 | |
| 553 | if (!syscall_tampered(tcp)) |
| 554 | return 0; |
| 555 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 556 | if (!syserror(tcp) ^ !!syscall_tampered_nofail(tcp)) { |
| 557 | error_msg("Failed to tamper with process %d: unexpectedly got" |
| 558 | " %serror (return value %#" PRI_klx ", error %lu)", |
| 559 | tcp->pid, syscall_tampered_nofail(tcp) ? "" : "no ", |
| 560 | tcp->u_rval, tcp->u_error); |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 561 | |
| 562 | return 1; |
| 563 | } |
| 564 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 565 | bool update_tcb = false; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 566 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 567 | if (opts->data.flags & INJECT_F_RETVAL) { |
| 568 | kernel_long_t inject_rval = |
| 569 | retval_get(opts->data.rval_idx); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 570 | kernel_long_t u_rval = tcp->u_rval; |
| 571 | |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 572 | tcp->u_rval = inject_rval; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 573 | if (arch_set_success(tcp)) { |
| 574 | tcp->u_rval = u_rval; |
| 575 | } else { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 576 | update_tcb = true; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 577 | tcp->u_error = 0; |
| 578 | } |
| 579 | } else { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 580 | unsigned long new_error = retval_get(opts->data.rval_idx); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 581 | |
| 582 | if (new_error != tcp->u_error && new_error <= MAX_ERRNO_VALUE) { |
| 583 | unsigned long u_error = tcp->u_error; |
| 584 | |
| 585 | tcp->u_error = new_error; |
| 586 | if (arch_set_error(tcp)) { |
| 587 | tcp->u_error = u_error; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 588 | } else { |
| 589 | update_tcb = true; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 590 | } |
| 591 | } |
| 592 | } |
| 593 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 594 | if (update_tcb) { |
| 595 | tcp->u_error = 0; |
| 596 | get_error(tcp, !(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS)); |
| 597 | } |
| 598 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 599 | return 0; |
| 600 | } |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 601 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 602 | /* |
| 603 | * Returns: |
| 604 | * 0: "ignore this ptrace stop", bail out silently. |
| 605 | * 1: ok, decoded; call |
| 606 | * syscall_entering_finish(tcp, syscall_entering_trace(tcp, ...)). |
| 607 | * other: error; call syscall_entering_finish(tcp, res), where res is the value |
| 608 | * returned. |
| 609 | */ |
| 610 | int |
| 611 | syscall_entering_decode(struct tcb *tcp) |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 612 | { |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 613 | int res = get_scno(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 614 | if (res == 0) |
| 615 | return res; |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 616 | int scno_good = res; |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 617 | if (res != 1 || (res = get_syscall_args(tcp)) != 1) { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 618 | printleader(tcp); |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 619 | tprintf("%s(", scno_good == 1 ? tcp->s_ent->sys_name : "????"); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 620 | /* |
| 621 | * " <unavailable>" will be added later by the code which |
| 622 | * detects ptrace errors. |
| 623 | */ |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 624 | return res; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 625 | } |
| 626 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 627 | #if defined SYS_ipc_subcall \ |
| 628 | || defined SYS_socket_subcall \ |
| 629 | || defined SYS_syscall_subcall |
| 630 | for (;;) { |
| 631 | switch (tcp->s_ent->sen) { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 632 | # ifdef SYS_ipc_subcall |
Elvira Khabirova | 483c15f | 2015-07-10 22:24:58 +0300 | [diff] [blame] | 633 | case SEN_ipc: |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 634 | decode_ipc_subcall(tcp); |
| 635 | break; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 636 | # endif |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 637 | # ifdef SYS_socket_subcall |
| 638 | case SEN_socketcall: |
| 639 | decode_socket_subcall(tcp); |
| 640 | break; |
| 641 | # endif |
| 642 | # ifdef SYS_syscall_subcall |
| 643 | case SEN_syscall: |
| 644 | decode_syscall_subcall(tcp); |
| 645 | if (tcp->s_ent->sen != SEN_syscall) |
| 646 | continue; |
| 647 | break; |
| 648 | # endif |
| 649 | } |
| 650 | break; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 651 | } |
| 652 | #endif |
| 653 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 654 | return 1; |
| 655 | } |
| 656 | |
| 657 | int |
| 658 | syscall_entering_trace(struct tcb *tcp, unsigned int *sig) |
| 659 | { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 660 | /* Restrain from fault injection while the trace executes strace code. */ |
| 661 | if (hide_log(tcp)) { |
| 662 | tcp->qual_flg &= ~QUAL_INJECT; |
| 663 | } |
| 664 | |
| 665 | switch (tcp->s_ent->sen) { |
| 666 | case SEN_execve: |
| 667 | case SEN_execveat: |
| 668 | #if defined SPARC || defined SPARC64 |
| 669 | case SEN_execv: |
| 670 | #endif |
| 671 | tcp->flags &= ~TCB_HIDE_LOG; |
| 672 | break; |
| 673 | } |
| 674 | |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 675 | if (!traced(tcp) || (tracing_paths && !pathtrace_match(tcp))) { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 676 | tcp->flags |= TCB_FILTERED; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 677 | return 0; |
| 678 | } |
| 679 | |
| 680 | tcp->flags &= ~TCB_FILTERED; |
| 681 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 682 | if (hide_log(tcp)) { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 683 | return 0; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 684 | } |
| 685 | |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 686 | if (inject(tcp)) |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 687 | tamper_with_syscall_entering(tcp, sig); |
| 688 | |
| 689 | if (cflag == CFLAG_ONLY_STATS) { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 690 | return 0; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 691 | } |
| 692 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 693 | #ifdef ENABLE_STACKTRACE |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 694 | if (stack_trace_enabled) { |
| 695 | if (tcp->s_ent->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 696 | unwind_tcb_capture(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 697 | } |
| 698 | #endif |
| 699 | |
| 700 | printleader(tcp); |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 701 | tprintf("%s(", tcp->s_ent->sys_name); |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 702 | int res = raw(tcp) ? printargs(tcp) : tcp->s_ent->sys_func(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 703 | fflush(tcp->outf); |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 704 | return res; |
| 705 | } |
| 706 | |
| 707 | void |
| 708 | syscall_entering_finish(struct tcb *tcp, int res) |
| 709 | { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 710 | tcp->flags |= TCB_INSYSCALL; |
Dmitry V. Levin | 204c2bc | 2015-07-08 14:10:56 +0000 | [diff] [blame] | 711 | tcp->sys_func_rval = res; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 712 | /* Measure the entrance time as late as possible to avoid errors. */ |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 713 | if ((Tflag || cflag) && !filtered(tcp)) |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 714 | clock_gettime(CLOCK_MONOTONIC, &tcp->etime); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 715 | } |
| 716 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 717 | /* Returns: |
| 718 | * 0: "bail out". |
| 719 | * 1: ok. |
| 720 | * -1: error in one of ptrace ops. |
| 721 | * |
| 722 | * If not 0, call syscall_exiting_trace(tcp, res), where res is the return |
| 723 | * value. Anyway, call syscall_exiting_finish(tcp) then. |
| 724 | */ |
| 725 | int |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 726 | syscall_exiting_decode(struct tcb *tcp, struct timespec *pts) |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 727 | { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 728 | /* Measure the exit time as early as possible to avoid errors. */ |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 729 | if ((Tflag || cflag) && !(filtered(tcp) || hide_log(tcp))) |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 730 | clock_gettime(CLOCK_MONOTONIC, pts); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 731 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 732 | if (tcp->s_ent->sys_flags & MEMORY_MAPPING_CHANGE) |
| 733 | mmap_notify_report(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 734 | |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 735 | if (filtered(tcp) || hide_log(tcp)) |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 736 | return 0; |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 737 | |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 738 | #if SUPPORTED_PERSONALITIES > 1 |
| 739 | update_personality(tcp, tcp->currpers); |
| 740 | #endif |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 741 | |
| 742 | return get_syscall_result(tcp); |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 743 | } |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 744 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 745 | int |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 746 | syscall_exiting_trace(struct tcb *tcp, struct timespec *ts, int res) |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 747 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 748 | if (syscall_tampered(tcp) || inject_delay_exit(tcp)) |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 749 | tamper_with_syscall_exiting(tcp); |
| 750 | |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 751 | if (cflag) { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 752 | count_syscall(tcp, ts); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 753 | if (cflag == CFLAG_ONLY_STATS) { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 754 | return 0; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 755 | } |
| 756 | } |
| 757 | |
| 758 | /* If not in -ff mode, and printing_tcp != tcp, |
| 759 | * then the log currently does not end with output |
| 760 | * of _our syscall entry_, but with something else. |
| 761 | * We need to say which syscall's return is this. |
| 762 | * |
| 763 | * Forced reprinting via TCB_REPRINT is used only by |
| 764 | * "strace -ff -oLOG test/threaded_execve" corner case. |
| 765 | * It's the only case when -ff mode needs reprinting. |
| 766 | */ |
| 767 | if ((followfork < 2 && printing_tcp != tcp) || (tcp->flags & TCB_REPRINT)) { |
| 768 | tcp->flags &= ~TCB_REPRINT; |
| 769 | printleader(tcp); |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 770 | tprintf("<... %s resumed> ", tcp->s_ent->sys_name); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 771 | } |
| 772 | printing_tcp = tcp; |
| 773 | |
| 774 | tcp->s_prev_ent = NULL; |
| 775 | if (res != 1) { |
| 776 | /* There was error in one of prior ptrace ops */ |
| 777 | tprints(") "); |
| 778 | tabto(); |
| 779 | tprints("= ? <unavailable>\n"); |
| 780 | line_ended(); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 781 | return res; |
| 782 | } |
| 783 | tcp->s_prev_ent = tcp->s_ent; |
| 784 | |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 785 | int sys_res = 0; |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 786 | if (raw(tcp)) { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 787 | /* sys_res = printargs(tcp); - but it's nop on sysexit */ |
| 788 | } else { |
| 789 | /* FIXME: not_failing_only (IOW, option -z) is broken: |
| 790 | * failure of syscall is known only after syscall return. |
| 791 | * Thus we end up with something like this on, say, ENOENT: |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 792 | * open("does_not_exist", O_RDONLY <unfinished ...> |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 793 | * {next syscall decode} |
| 794 | * whereas the intended result is that open(...) line |
| 795 | * is not shown at all. |
| 796 | */ |
| 797 | if (not_failing_only && tcp->u_error) |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 798 | return 0; /* ignore failed syscalls */ |
Dmitry V. Levin | 204c2bc | 2015-07-08 14:10:56 +0000 | [diff] [blame] | 799 | if (tcp->sys_func_rval & RVAL_DECODED) |
| 800 | sys_res = tcp->sys_func_rval; |
| 801 | else |
| 802 | sys_res = tcp->s_ent->sys_func(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 803 | } |
| 804 | |
| 805 | tprints(") "); |
| 806 | tabto(); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 807 | |
Elliott Hughes | 77c3ff8 | 2017-09-08 17:11:00 -0700 | [diff] [blame] | 808 | if (raw(tcp)) { |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 809 | if (tcp->u_error) |
| 810 | print_err_ret(tcp->u_rval, tcp->u_error); |
| 811 | else |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 812 | tprintf("= %#" PRI_klx, tcp->u_rval); |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 813 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 814 | if (syscall_tampered(tcp)) |
| 815 | tprints(" (INJECTED)"); |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 816 | } else if (!(sys_res & RVAL_NONE) && tcp->u_error) { |
| 817 | switch (tcp->u_error) { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 818 | /* Blocked signals do not interrupt any syscalls. |
| 819 | * In this case syscalls don't return ERESTARTfoo codes. |
| 820 | * |
| 821 | * Deadly signals set to SIG_DFL interrupt syscalls |
| 822 | * and kill the process regardless of which of the codes below |
| 823 | * is returned by the interrupted syscall. |
| 824 | * In some cases, kernel forces a kernel-generated deadly |
| 825 | * signal to be unblocked and set to SIG_DFL (and thus cause |
| 826 | * death) if it is blocked or SIG_IGNed: for example, SIGSEGV |
| 827 | * or SIGILL. (The alternative is to leave process spinning |
| 828 | * forever on the faulty instruction - not useful). |
| 829 | * |
| 830 | * SIG_IGNed signals and non-deadly signals set to SIG_DFL |
| 831 | * (for example, SIGCHLD, SIGWINCH) interrupt syscalls, |
| 832 | * but kernel will always restart them. |
| 833 | */ |
| 834 | case ERESTARTSYS: |
| 835 | /* Most common type of signal-interrupted syscall exit code. |
| 836 | * The system call will be restarted with the same arguments |
| 837 | * if SA_RESTART is set; otherwise, it will fail with EINTR. |
| 838 | */ |
| 839 | tprints("= ? ERESTARTSYS (To be restarted if SA_RESTART is set)"); |
| 840 | break; |
| 841 | case ERESTARTNOINTR: |
| 842 | /* Rare. For example, fork() returns this if interrupted. |
| 843 | * SA_RESTART is ignored (assumed set): the restart is unconditional. |
| 844 | */ |
| 845 | tprints("= ? ERESTARTNOINTR (To be restarted)"); |
| 846 | break; |
| 847 | case ERESTARTNOHAND: |
| 848 | /* pause(), rt_sigsuspend() etc use this code. |
| 849 | * SA_RESTART is ignored (assumed not set): |
| 850 | * syscall won't restart (will return EINTR instead) |
| 851 | * even after signal with SA_RESTART set. However, |
| 852 | * after SIG_IGN or SIG_DFL signal it will restart |
| 853 | * (thus the name "restart only if has no handler"). |
| 854 | */ |
| 855 | tprints("= ? ERESTARTNOHAND (To be restarted if no handler)"); |
| 856 | break; |
| 857 | case ERESTART_RESTARTBLOCK: |
| 858 | /* Syscalls like nanosleep(), poll() which can't be |
| 859 | * restarted with their original arguments use this |
| 860 | * code. Kernel will execute restart_syscall() instead, |
| 861 | * which changes arguments before restarting syscall. |
| 862 | * SA_RESTART is ignored (assumed not set) similarly |
| 863 | * to ERESTARTNOHAND. (Kernel can't honor SA_RESTART |
| 864 | * since restart data is saved in "restart block" |
| 865 | * in task struct, and if signal handler uses a syscall |
| 866 | * which in turn saves another such restart block, |
| 867 | * old data is lost and restart becomes impossible) |
| 868 | */ |
| 869 | tprints("= ? ERESTART_RESTARTBLOCK (Interrupted by signal)"); |
| 870 | break; |
| 871 | default: |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 872 | print_err_ret(tcp->u_rval, tcp->u_error); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 873 | break; |
| 874 | } |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 875 | if (syscall_tampered(tcp)) |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 876 | tprints(" (INJECTED)"); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 877 | if ((sys_res & RVAL_STR) && tcp->auxstr) |
| 878 | tprintf(" (%s)", tcp->auxstr); |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 879 | } else { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 880 | if (sys_res & RVAL_NONE) |
| 881 | tprints("= ?"); |
| 882 | else { |
| 883 | switch (sys_res & RVAL_MASK) { |
| 884 | case RVAL_HEX: |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 885 | #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 886 | if (current_klongsize < sizeof(tcp->u_rval)) { |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 887 | tprintf("= %#x", |
| 888 | (unsigned int) tcp->u_rval); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 889 | } else |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 890 | #endif |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 891 | { |
| 892 | tprintf("= %#" PRI_klx, tcp->u_rval); |
| 893 | } |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 894 | break; |
| 895 | case RVAL_OCTAL: |
Dmitry V. Levin | 8d37438 | 2016-08-03 14:05:39 +0000 | [diff] [blame] | 896 | tprints("= "); |
| 897 | print_numeric_long_umask(tcp->u_rval); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 898 | break; |
| 899 | case RVAL_UDECIMAL: |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 900 | #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 901 | if (current_klongsize < sizeof(tcp->u_rval)) { |
Dmitry V. Levin | be1cb92 | 2016-01-07 14:20:17 +0000 | [diff] [blame] | 902 | tprintf("= %u", |
| 903 | (unsigned int) tcp->u_rval); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 904 | } else |
Dmitry V. Levin | be1cb92 | 2016-01-07 14:20:17 +0000 | [diff] [blame] | 905 | #endif |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 906 | { |
| 907 | tprintf("= %" PRI_klu, tcp->u_rval); |
| 908 | } |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 909 | break; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 910 | case RVAL_FD: |
| 911 | if (show_fd_path) { |
| 912 | tprints("= "); |
| 913 | printfd(tcp, tcp->u_rval); |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 914 | } else |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 915 | tprintf("= %" PRI_kld, tcp->u_rval); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 916 | break; |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 917 | default: |
Dmitry V. Levin | 6c8ef05 | 2015-05-25 22:51:19 +0000 | [diff] [blame] | 918 | error_msg("invalid rval format"); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 919 | break; |
| 920 | } |
| 921 | } |
| 922 | if ((sys_res & RVAL_STR) && tcp->auxstr) |
| 923 | tprintf(" (%s)", tcp->auxstr); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 924 | if (syscall_tampered(tcp)) |
| 925 | tprints(" (INJECTED)"); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 926 | } |
| 927 | if (Tflag) { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 928 | ts_sub(ts, ts, &tcp->etime); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 929 | tprintf(" <%ld.%06ld>", |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 930 | (long) ts->tv_sec, (long) ts->tv_nsec / 1000); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 931 | } |
| 932 | tprints("\n"); |
| 933 | dumpio(tcp); |
| 934 | line_ended(); |
| 935 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 936 | #ifdef ENABLE_STACKTRACE |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 937 | if (stack_trace_enabled) |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 938 | unwind_tcb_print(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 939 | #endif |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 940 | return 0; |
| 941 | } |
| 942 | |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 943 | void |
| 944 | syscall_exiting_finish(struct tcb *tcp) |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 945 | { |
Elliott Hughes | 28e98bc | 2018-06-14 16:59:04 -0700 | [diff] [blame] | 946 | tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED | TCB_INJECT_DELAY_EXIT); |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 947 | tcp->sys_func_rval = 0; |
| 948 | free_tcb_priv_data(tcp); |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 949 | } |
| 950 | |
Dmitry V. Levin | 9af94a2 | 2015-09-18 01:54:59 +0000 | [diff] [blame] | 951 | bool |
| 952 | is_erestart(struct tcb *tcp) |
| 953 | { |
| 954 | switch (tcp->u_error) { |
| 955 | case ERESTARTSYS: |
| 956 | case ERESTARTNOINTR: |
| 957 | case ERESTARTNOHAND: |
| 958 | case ERESTART_RESTARTBLOCK: |
| 959 | return true; |
| 960 | default: |
| 961 | return false; |
| 962 | } |
| 963 | } |
| 964 | |
Dmitry V. Levin | ba63d8a | 2016-10-03 11:48:55 +0000 | [diff] [blame] | 965 | static unsigned long saved_u_error; |
Dmitry V. Levin | 3858b93 | 2015-09-18 01:54:59 +0000 | [diff] [blame] | 966 | |
| 967 | void |
| 968 | temporarily_clear_syserror(struct tcb *tcp) |
| 969 | { |
| 970 | saved_u_error = tcp->u_error; |
| 971 | tcp->u_error = 0; |
| 972 | } |
| 973 | |
| 974 | void |
| 975 | restore_cleared_syserror(struct tcb *tcp) |
| 976 | { |
| 977 | tcp->u_error = saved_u_error; |
| 978 | } |
| 979 | |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 980 | #define XLAT_MACROS_ONLY |
| 981 | # include "xlat/nt_descriptor_types.h" |
| 982 | #undef XLAT_MACROS_ONLY |
| 983 | |
Dmitry V. Levin | d70d1c4 | 2015-03-22 22:13:55 +0000 | [diff] [blame] | 984 | #include "arch_regs.c" |
Wichert Akkerman | c792698 | 2000-04-10 22:22:31 +0000 | [diff] [blame] | 985 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 986 | #if HAVE_ARCH_GETRVAL2 |
Dmitry V. Levin | d70d1c4 | 2015-03-22 22:13:55 +0000 | [diff] [blame] | 987 | # include "arch_getrval2.c" |
Dmitry V. Levin | 48f0890 | 2015-03-05 23:30:02 +0000 | [diff] [blame] | 988 | #endif |
| 989 | |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 990 | void |
Denys Vlasenko | 5a2483b | 2013-07-01 12:49:14 +0200 | [diff] [blame] | 991 | print_pc(struct tcb *tcp) |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 992 | { |
Dmitry V. Levin | 5105d4a | 2015-11-30 03:30:51 +0000 | [diff] [blame] | 993 | #if defined ARCH_PC_REG |
| 994 | # define ARCH_GET_PC 0 |
| 995 | #elif defined ARCH_PC_PEEK_ADDR |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 996 | kernel_ulong_t pc; |
Dmitry V. Levin | 5105d4a | 2015-11-30 03:30:51 +0000 | [diff] [blame] | 997 | # define ARCH_PC_REG pc |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 998 | # define ARCH_GET_PC upeek(tcp, ARCH_PC_PEEK_ADDR, &pc) |
Dmitry V. Levin | b2d9ff2 | 2015-02-23 13:43:20 +0000 | [diff] [blame] | 999 | #else |
Dmitry V. Levin | 5105d4a | 2015-11-30 03:30:51 +0000 | [diff] [blame] | 1000 | # error Neither ARCH_PC_REG nor ARCH_PC_PEEK_ADDR is defined |
Dmitry V. Levin | e96cb62 | 2015-02-15 15:52:02 +0000 | [diff] [blame] | 1001 | #endif |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1002 | if (get_regs(tcp) < 0 || ARCH_GET_PC) |
Dmitry V. Levin | 5105d4a | 2015-11-30 03:30:51 +0000 | [diff] [blame] | 1003 | tprints(current_wordsize == 4 ? "[????????] " |
| 1004 | : "[????????????????] "); |
| 1005 | else |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1006 | tprintf(current_wordsize == 4 |
| 1007 | ? "[%08" PRI_klx "] " : "[%016" PRI_klx "] ", |
| 1008 | (kernel_ulong_t) ARCH_PC_REG); |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 1009 | } |
| 1010 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1011 | #include "getregs_old.h" |
| 1012 | |
| 1013 | #undef ptrace_getregset_or_getregs |
| 1014 | #undef ptrace_setregset_or_setregs |
| 1015 | #ifdef ARCH_REGS_FOR_GETREGSET |
| 1016 | |
| 1017 | # define ptrace_getregset_or_getregs ptrace_getregset |
Dmitry V. Levin | d6db1db | 2015-02-13 23:41:04 +0000 | [diff] [blame] | 1018 | static long |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1019 | ptrace_getregset(pid_t pid) |
Dmitry V. Levin | faa177e | 2013-03-17 23:48:45 +0000 | [diff] [blame] | 1020 | { |
Dmitry V. Levin | d6db1db | 2015-02-13 23:41:04 +0000 | [diff] [blame] | 1021 | # ifdef ARCH_IOVEC_FOR_GETREGSET |
| 1022 | /* variable iovec */ |
| 1023 | ARCH_IOVEC_FOR_GETREGSET.iov_len = sizeof(ARCH_REGS_FOR_GETREGSET); |
| 1024 | return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, |
| 1025 | &ARCH_IOVEC_FOR_GETREGSET); |
| 1026 | # else |
| 1027 | /* constant iovec */ |
Dmitry V. Levin | b787b10 | 2013-03-18 10:17:14 +0000 | [diff] [blame] | 1028 | static struct iovec io = { |
| 1029 | .iov_base = &ARCH_REGS_FOR_GETREGSET, |
| 1030 | .iov_len = sizeof(ARCH_REGS_FOR_GETREGSET) |
Dmitry V. Levin | faa177e | 2013-03-17 23:48:45 +0000 | [diff] [blame] | 1031 | }; |
Dmitry V. Levin | d6db1db | 2015-02-13 23:41:04 +0000 | [diff] [blame] | 1032 | return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &io); |
Dmitry V. Levin | b787b10 | 2013-03-18 10:17:14 +0000 | [diff] [blame] | 1033 | |
Dmitry V. Levin | faa177e | 2013-03-17 23:48:45 +0000 | [diff] [blame] | 1034 | # endif |
Dmitry V. Levin | b787b10 | 2013-03-18 10:17:14 +0000 | [diff] [blame] | 1035 | } |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1036 | |
| 1037 | # ifndef HAVE_GETREGS_OLD |
| 1038 | # define ptrace_setregset_or_setregs ptrace_setregset |
| 1039 | static int |
| 1040 | ptrace_setregset(pid_t pid) |
| 1041 | { |
| 1042 | # ifdef ARCH_IOVEC_FOR_GETREGSET |
| 1043 | /* variable iovec */ |
| 1044 | return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, |
| 1045 | &ARCH_IOVEC_FOR_GETREGSET); |
| 1046 | # else |
| 1047 | /* constant iovec */ |
| 1048 | static struct iovec io = { |
| 1049 | .iov_base = &ARCH_REGS_FOR_GETREGSET, |
| 1050 | .iov_len = sizeof(ARCH_REGS_FOR_GETREGSET) |
| 1051 | }; |
| 1052 | return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &io); |
| 1053 | # endif |
| 1054 | } |
| 1055 | # endif /* !HAVE_GETREGS_OLD */ |
| 1056 | |
| 1057 | #elif defined ARCH_REGS_FOR_GETREGS |
| 1058 | |
| 1059 | # define ptrace_getregset_or_getregs ptrace_getregs |
| 1060 | static long |
| 1061 | ptrace_getregs(pid_t pid) |
| 1062 | { |
| 1063 | # if defined SPARC || defined SPARC64 |
| 1064 | /* SPARC systems have the meaning of data and addr reversed */ |
| 1065 | return ptrace(PTRACE_GETREGS, pid, (void *) &ARCH_REGS_FOR_GETREGS, 0); |
| 1066 | # else |
| 1067 | return ptrace(PTRACE_GETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); |
| 1068 | # endif |
| 1069 | } |
| 1070 | |
| 1071 | # ifndef HAVE_GETREGS_OLD |
| 1072 | # define ptrace_setregset_or_setregs ptrace_setregs |
| 1073 | static int |
| 1074 | ptrace_setregs(pid_t pid) |
| 1075 | { |
| 1076 | # if defined SPARC || defined SPARC64 |
| 1077 | /* SPARC systems have the meaning of data and addr reversed */ |
| 1078 | return ptrace(PTRACE_SETREGS, pid, (void *) &ARCH_REGS_FOR_GETREGS, 0); |
| 1079 | # else |
| 1080 | return ptrace(PTRACE_SETREGS, pid, NULL, &ARCH_REGS_FOR_GETREGS); |
| 1081 | # endif |
| 1082 | } |
| 1083 | # endif /* !HAVE_GETREGS_OLD */ |
| 1084 | |
| 1085 | #endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */ |
Dmitry V. Levin | b787b10 | 2013-03-18 10:17:14 +0000 | [diff] [blame] | 1086 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1087 | #ifdef ptrace_getregset_or_getregs |
| 1088 | static long get_regs_error; |
| 1089 | #endif |
| 1090 | |
| 1091 | void |
| 1092 | clear_regs(struct tcb *tcp) |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 1093 | { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1094 | #ifdef ptrace_getregset_or_getregs |
| 1095 | get_regs_error = -1; |
| 1096 | #endif |
| 1097 | } |
| 1098 | |
| 1099 | static long |
| 1100 | get_regs(struct tcb *const tcp) |
| 1101 | { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1102 | #ifdef ptrace_getregset_or_getregs |
Dmitry V. Levin | 27e3ae9 | 2013-03-17 23:18:35 +0000 | [diff] [blame] | 1103 | |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 1104 | if (get_regs_error != -1) |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1105 | return get_regs_error; |
Elliott Hughes | 39bac05 | 2017-05-25 16:56:11 -0700 | [diff] [blame] | 1106 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1107 | # ifdef HAVE_GETREGS_OLD |
| 1108 | /* |
| 1109 | * Try PTRACE_GETREGSET/PTRACE_GETREGS first, |
| 1110 | * fallback to getregs_old. |
| 1111 | */ |
| 1112 | static int use_getregs_old; |
| 1113 | if (use_getregs_old < 0) { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1114 | return get_regs_error = ptrace_getregset_or_getregs(tcp->pid); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1115 | } else if (use_getregs_old == 0) { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1116 | get_regs_error = ptrace_getregset_or_getregs(tcp->pid); |
Dmitry V. Levin | 27e3ae9 | 2013-03-17 23:18:35 +0000 | [diff] [blame] | 1117 | if (get_regs_error >= 0) { |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1118 | use_getregs_old = -1; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1119 | return get_regs_error; |
Denys Vlasenko | eec8d5d | 2013-02-14 03:29:48 +0100 | [diff] [blame] | 1120 | } |
Dmitry V. Levin | 27e3ae9 | 2013-03-17 23:18:35 +0000 | [diff] [blame] | 1121 | if (errno == EPERM || errno == ESRCH) |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1122 | return get_regs_error; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1123 | use_getregs_old = 1; |
Dmitry V. Levin | 27e3ae9 | 2013-03-17 23:18:35 +0000 | [diff] [blame] | 1124 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1125 | return get_regs_error = getregs_old(tcp); |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1126 | # else /* !HAVE_GETREGS_OLD */ |
| 1127 | /* Assume that PTRACE_GETREGSET/PTRACE_GETREGS works. */ |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1128 | get_regs_error = ptrace_getregset_or_getregs(tcp->pid); |
| 1129 | |
| 1130 | # if defined ARCH_PERSONALITY_0_IOV_SIZE |
| 1131 | if (get_regs_error) |
| 1132 | return get_regs_error; |
| 1133 | |
| 1134 | switch (ARCH_IOVEC_FOR_GETREGSET.iov_len) { |
| 1135 | case ARCH_PERSONALITY_0_IOV_SIZE: |
| 1136 | update_personality(tcp, 0); |
| 1137 | break; |
| 1138 | case ARCH_PERSONALITY_1_IOV_SIZE: |
| 1139 | update_personality(tcp, 1); |
| 1140 | break; |
| 1141 | default: { |
| 1142 | static bool printed = false; |
| 1143 | |
| 1144 | if (!printed) { |
| 1145 | error_msg("Unsupported regset size returned by " |
| 1146 | "PTRACE_GETREGSET: %zu", |
| 1147 | ARCH_IOVEC_FOR_GETREGSET.iov_len); |
| 1148 | |
| 1149 | printed = true; |
| 1150 | } |
| 1151 | |
| 1152 | update_personality(tcp, 0); |
| 1153 | } |
| 1154 | } |
| 1155 | # endif /* ARCH_PERSONALITY_0_IOV_SIZE */ |
| 1156 | |
| 1157 | return get_regs_error; |
| 1158 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1159 | # endif /* !HAVE_GETREGS_OLD */ |
Dmitry V. Levin | 7abf2e8 | 2015-02-13 23:56:54 +0000 | [diff] [blame] | 1160 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1161 | #else /* !ptrace_getregset_or_getregs */ |
| 1162 | |
Dmitry V. Levin | f51aec6 | 2015-11-30 00:01:01 +0000 | [diff] [blame] | 1163 | # warning get_regs is not implemented for this architecture yet |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1164 | return 0; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1165 | |
| 1166 | #endif /* !ptrace_getregset_or_getregs */ |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 1167 | } |
Denys Vlasenko | ce7d953 | 2013-02-05 16:36:13 +0100 | [diff] [blame] | 1168 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1169 | #ifdef ptrace_setregset_or_setregs |
| 1170 | static int |
| 1171 | set_regs(pid_t pid) |
| 1172 | { |
| 1173 | return ptrace_setregset_or_setregs(pid); |
| 1174 | } |
| 1175 | #endif /* ptrace_setregset_or_setregs */ |
| 1176 | |
Dmitry V. Levin | e3dfc59 | 2016-08-09 10:28:22 +0000 | [diff] [blame] | 1177 | struct sysent_buf { |
| 1178 | struct tcb *tcp; |
| 1179 | struct_sysent ent; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1180 | char buf[sizeof("syscall_0x") + sizeof(kernel_ulong_t) * 2]; |
Dmitry V. Levin | e3dfc59 | 2016-08-09 10:28:22 +0000 | [diff] [blame] | 1181 | }; |
| 1182 | |
| 1183 | static void |
| 1184 | free_sysent_buf(void *ptr) |
| 1185 | { |
| 1186 | struct sysent_buf *s = ptr; |
| 1187 | s->tcp->s_prev_ent = s->tcp->s_ent = NULL; |
| 1188 | free(ptr); |
| 1189 | } |
| 1190 | |
Dmitry V. Levin | 1651051 | 2015-11-30 01:46:52 +0000 | [diff] [blame] | 1191 | /* |
| 1192 | * Returns: |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 1193 | * 0: "ignore this ptrace stop", syscall_entering_decode() should return a "bail |
| 1194 | * out silently" code. |
| 1195 | * 1: ok, continue in syscall_entering_decode(). |
| 1196 | * other: error, syscall_entering_decode() should print error indicator |
| 1197 | * ("????" etc) and return an appropriate code. |
Denys Vlasenko | b88f961 | 2011-08-21 18:03:23 +0200 | [diff] [blame] | 1198 | */ |
Denys Vlasenko | 8497b62 | 2015-03-21 17:51:52 +0100 | [diff] [blame] | 1199 | int |
Denys Vlasenko | 06602d9 | 2011-08-24 17:53:52 +0200 | [diff] [blame] | 1200 | get_scno(struct tcb *tcp) |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 1201 | { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1202 | if (get_regs(tcp) < 0) |
Dmitry V. Levin | 144cda2 | 2015-03-23 18:48:32 +0000 | [diff] [blame] | 1203 | return -1; |
| 1204 | |
Dmitry V. Levin | 1651051 | 2015-11-30 01:46:52 +0000 | [diff] [blame] | 1205 | int rc = arch_get_scno(tcp); |
| 1206 | if (rc != 1) |
| 1207 | return rc; |
Wichert Akkerman | 76baf7c | 1999-02-19 00:21:36 +0000 | [diff] [blame] | 1208 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1209 | tcp->scno = shuffle_scno(tcp->scno); |
| 1210 | |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1211 | if (scno_is_valid(tcp->scno)) { |
Dmitry V. Levin | 1651051 | 2015-11-30 01:46:52 +0000 | [diff] [blame] | 1212 | tcp->s_ent = &sysent[tcp->scno]; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1213 | tcp->qual_flg = qual_flags(tcp->scno); |
Denys Vlasenko | 74ec14f | 2013-02-21 16:13:47 +0100 | [diff] [blame] | 1214 | } else { |
Dmitry V. Levin | e3dfc59 | 2016-08-09 10:28:22 +0000 | [diff] [blame] | 1215 | struct sysent_buf *s = xcalloc(1, sizeof(*s)); |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 1216 | |
Dmitry V. Levin | e3dfc59 | 2016-08-09 10:28:22 +0000 | [diff] [blame] | 1217 | s->tcp = tcp; |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 1218 | s->ent.nargs = MAX_ARGS; |
| 1219 | s->ent.sen = SEN_printargs; |
| 1220 | s->ent.sys_func = printargs; |
| 1221 | s->ent.sys_name = s->buf; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1222 | xsprintf(s->buf, "syscall_%#" PRI_klx, shuffle_scno(tcp->scno)); |
Dmitry V. Levin | 60d7ec8 | 2016-08-09 00:07:53 +0000 | [diff] [blame] | 1223 | |
| 1224 | tcp->s_ent = &s->ent; |
Elvira Khabirova | ed37c8d | 2016-06-12 19:11:43 +0300 | [diff] [blame] | 1225 | tcp->qual_flg = QUAL_RAW | DEFAULT_QUAL_FLAGS; |
Dmitry V. Levin | e3dfc59 | 2016-08-09 10:28:22 +0000 | [diff] [blame] | 1226 | |
| 1227 | set_tcb_priv_data(tcp, s, free_sysent_buf); |
| 1228 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1229 | debug_msg("pid %d invalid syscall %#" PRI_klx, |
| 1230 | tcp->pid, shuffle_scno(tcp->scno)); |
Denys Vlasenko | 74ec14f | 2013-02-21 16:13:47 +0100 | [diff] [blame] | 1231 | } |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1232 | |
| 1233 | /* |
| 1234 | * We refrain from argument decoding during recovering |
| 1235 | * as tracee memory mappings has changed and the registers |
| 1236 | * are very likely pointing to garbage already. |
| 1237 | */ |
| 1238 | if (recovering(tcp)) |
| 1239 | tcp->qual_flg |= QUAL_RAW; |
| 1240 | |
Pavel Machek | 4dc3b14 | 2000-02-01 17:58:41 +0000 | [diff] [blame] | 1241 | return 1; |
| 1242 | } |
| 1243 | |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1244 | #ifdef ptrace_getregset_or_getregs |
| 1245 | # define get_syscall_result_regs get_regs |
| 1246 | #else |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 1247 | static int get_syscall_result_regs(struct tcb *); |
Dmitry V. Levin | f51aec6 | 2015-11-30 00:01:01 +0000 | [diff] [blame] | 1248 | #endif |
Denys Vlasenko | a614692 | 2011-08-24 18:07:22 +0200 | [diff] [blame] | 1249 | |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 1250 | /* Returns: |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 1251 | * 1: ok, continue in syscall_exiting_trace(). |
| 1252 | * -1: error, syscall_exiting_trace() should print error indicator |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 1253 | * ("????" etc) and bail out. |
| 1254 | */ |
Denys Vlasenko | ed4f4f0 | 2011-08-22 11:54:06 +0200 | [diff] [blame] | 1255 | static int |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 1256 | get_syscall_result(struct tcb *tcp) |
Pavel Machek | 4dc3b14 | 2000-02-01 17:58:41 +0000 | [diff] [blame] | 1257 | { |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1258 | if (get_syscall_result_regs(tcp) < 0) |
Dmitry V. Levin | f51aec6 | 2015-11-30 00:01:01 +0000 | [diff] [blame] | 1259 | return -1; |
Dmitry V. Levin | 0c8c5c9 | 2015-11-29 00:06:45 +0000 | [diff] [blame] | 1260 | tcp->u_error = 0; |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1261 | get_error(tcp, |
Elliott Hughes | 03a418e | 2018-06-15 13:11:40 -0700 | [diff] [blame] | 1262 | (!(tcp->s_ent->sys_flags & SYSCALL_NEVER_FAILS) |
| 1263 | || syscall_tampered(tcp)) |
| 1264 | && !syscall_tampered_nofail(tcp)); |
Dmitry V. Levin | 0c8c5c9 | 2015-11-29 00:06:45 +0000 | [diff] [blame] | 1265 | |
Dmitry V. Levin | 1b78607 | 2015-03-22 18:09:55 +0000 | [diff] [blame] | 1266 | return 1; |
Dmitry V. Levin | 7d7c963 | 2010-03-29 17:51:02 +0000 | [diff] [blame] | 1267 | } |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 1268 | |
| 1269 | #include "get_scno.c" |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1270 | #include "set_scno.c" |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 1271 | #include "get_syscall_args.c" |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1272 | #ifndef ptrace_getregset_or_getregs |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 1273 | # include "get_syscall_result.c" |
| 1274 | #endif |
| 1275 | #include "get_error.c" |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1276 | #include "set_error.c" |
| 1277 | #ifdef HAVE_GETREGS_OLD |
Dmitry V. Levin | 7386ca7 | 2015-11-30 13:57:51 +0000 | [diff] [blame] | 1278 | # include "getregs_old.c" |
| 1279 | #endif |
Elliott Hughes | b755614 | 2018-02-20 17:03:16 -0800 | [diff] [blame] | 1280 | #include "shuffle_scno.c" |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1281 | |
| 1282 | const char * |
| 1283 | syscall_name(kernel_ulong_t scno) |
| 1284 | { |
Elliott Hughes | dc75b01 | 2017-07-05 13:54:44 -0700 | [diff] [blame] | 1285 | return scno_is_valid(scno) ? sysent[scno].sys_name : NULL; |
Elliott Hughes | d35df49 | 2017-02-15 15:19:05 -0800 | [diff] [blame] | 1286 | } |