libexplain  1.4.D001
libexplain/buffer/errno/ptrace.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010-2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 #include <libexplain/ac/stdint.h>
00021 #include <libexplain/ac/signal.h>
00022 #include <libexplain/ac/sys/ptrace.h>
00023 #include <libexplain/ac/sys/user.h>
00024 
00025 #include <libexplain/buffer/ebusy.h>
00026 #include <libexplain/buffer/efault.h>
00027 #include <libexplain/buffer/einval.h>
00028 #include <libexplain/buffer/eio.h>
00029 #include <libexplain/buffer/eperm.h>
00030 #include <libexplain/buffer/errno/generic.h>
00031 #include <libexplain/buffer/errno/ptrace.h>
00032 #include <libexplain/buffer/esrch.h>
00033 #include <libexplain/buffer/gettext.h>
00034 #include <libexplain/buffer/long.h>
00035 #include <libexplain/buffer/pid_t_star.h>
00036 #include <libexplain/buffer/pointer.h>
00037 #include <libexplain/buffer/ptrace_options.h>
00038 #include <libexplain/buffer/ptrace_request.h>
00039 #include <libexplain/buffer/ptrace_vm_entry.h>
00040 #include <libexplain/buffer/signal.h>
00041 #include <libexplain/explanation.h>
00042 #include <libexplain/is_efault.h>
00043 #include <libexplain/process_exists.h>
00044 
00045 
00046 static void
00047 explain_buffer_errno_ptrace_system_call(explain_string_buffer_t *sb, int errnum,
00048     int request, pid_t pid, void *addr, void *data)
00049 {
00050     (void)errnum;
00051     explain_string_buffer_puts(sb, "ptrace(request = ");
00052     explain_buffer_ptrace_request(sb, request);
00053     explain_string_buffer_puts(sb, ", pid = ");
00054     explain_buffer_pid_t(sb, pid);
00055     explain_string_buffer_puts(sb, ", addr = ");
00056     explain_buffer_pointer(sb, addr);
00057     explain_string_buffer_puts(sb, ", data = ");
00058     switch (request)
00059     {
00060 #ifdef PT_CONTINUE
00061     case PT_CONTINUE:
00062 #endif
00063 #ifdef PT_SYSCALL
00064     case PT_SYSCALL:
00065 #endif
00066 #ifdef PT_STEP
00067     case PT_STEP:
00068 #endif
00069 #ifdef PT_SYSEMU
00070     case PT_SYSEMU:
00071 #endif
00072 #ifdef PT_SYSEMU_SINGLESTEP
00073     case PT_SYSEMU_SINGLESTEP:
00074 #endif
00075 #ifdef PT_DETACH
00076     case PT_DETACH:
00077 #endif
00078         explain_buffer_signal(sb, (intptr_t)data);
00079         break;
00080 
00081 #ifdef PT_SETOPTIONS
00082     case PT_SETOPTIONS:
00083 #endif
00084 #ifdef PT_OLDSETOPTIONS
00085     case PT_OLDSETOPTIONS:
00086 #endif
00087         explain_buffer_ptrace_options(sb, (intptr_t)data);
00088         break;
00089 
00090 #ifdef PT_WRITE_I
00091     case PT_WRITE_I:
00092 #endif
00093 #ifdef PT_WRITE_D
00094     case PT_WRITE_D:
00095 #endif
00096 #ifdef PT_WRITE_U
00097     case PT_WRITE_U:
00098 #endif
00099         explain_buffer_long(sb, (intptr_t)data);
00100         break;
00101 
00102 #ifdef PT_VM_ENTRY
00103     case PT_VM_ENTRY:
00104         explain_buffer_ptrace_vm_entry(sb, data);
00105         break;
00106 #endif
00107 
00108     /* FIXME: FreeBSD's PT_IO uses struct ptrace_io_desc */
00109 
00110     default:
00111         explain_buffer_pointer(sb, data);
00112         break;
00113     }
00114     explain_string_buffer_putc(sb, ')');
00115 }
00116 
00117 
00118 static int
00119 request_is_known(int request)
00120 {
00121     switch (request)
00122     {
00123 #ifdef PT_TRACE_ME
00124     case PT_TRACE_ME:
00125 #endif
00126 #ifdef PT_READ_I
00127     case PT_READ_I:
00128 #endif
00129 #ifdef PT_READ_D
00130     case PT_READ_D:
00131 #endif
00132 #ifdef PT_READ_U
00133     case PT_READ_U:
00134 #endif
00135 #ifdef PT_WRITE_I
00136     case PT_WRITE_I:
00137 #endif
00138 #ifdef PT_WRITE_D
00139     case PT_WRITE_D:
00140 #endif
00141 #ifdef PT_WRITE_U
00142     case PT_WRITE_U:
00143 #endif
00144 #ifdef PT_CONTINUE
00145     case PT_CONTINUE:
00146 #endif
00147 #ifdef PT_KILL
00148     case PT_KILL:
00149 #endif
00150 #ifdef PT_SINGLESTEP
00151     case PT_SINGLESTEP:
00152 #endif
00153 #ifdef PT_GETREGS
00154     case PT_GETREGS:
00155 #endif
00156 #ifdef PT_SETREGS
00157     case PT_SETREGS:
00158 #endif
00159 #ifdef PT_GETFPREGS
00160     case PT_GETFPREGS:
00161 #endif
00162 #ifdef PT_SETFPREGS
00163     case PT_SETFPREGS:
00164 #endif
00165 #ifdef PT_ATTACH
00166     case PT_ATTACH:
00167 #endif
00168 #ifdef PT_DETACH
00169     case PT_DETACH:
00170 #endif
00171 #ifdef PT_GETFPXREGS
00172     case PT_GETFPXREGS:
00173 #endif
00174 #ifdef PT_SETFPXREGS
00175     case PT_SETFPXREGS:
00176 #endif
00177 #ifdef PT_SYSCALL
00178     case PT_SYSCALL:
00179 #endif
00180 #ifdef PT_SETOPTIONS
00181     case PT_SETOPTIONS:
00182 #endif
00183 #ifdef PT_OLDSETOPTIONS
00184     case PT_OLDSETOPTIONS:
00185 #endif
00186 #ifdef PT_GETEVENTMSG
00187     case PT_GETEVENTMSG:
00188 #endif
00189 #ifdef PT_GETSIGINFO
00190     case PT_GETSIGINFO:
00191 #endif
00192 #ifdef PT_SETSIGINFO
00193     case PT_SETSIGINFO:
00194 #endif
00195 #ifdef PT_SYSEMU
00196     case PT_SYSEMU:
00197 #endif
00198 #ifdef PT_SYSEMU_SINGLESTEP
00199     case PT_SYSEMU_SINGLESTEP:
00200 #endif
00201 #ifdef PT_IO
00202     case PT_IO:
00203 #endif
00204 #ifdef PT_LWPINFO
00205     case PT_LWPINFO:
00206 #endif
00207 #ifdef PT_GETNUMLWPS
00208     case PT_GETNUMLWPS:
00209 #endif
00210 #ifdef PT_GETLWPLIST
00211     case PT_GETLWPLIST:
00212 #endif
00213 #ifdef PT_CLEARSTEP
00214     case PT_CLEARSTEP:
00215 #endif
00216 #ifdef PT_SETSTEP
00217     case PT_SETSTEP:
00218 #endif
00219 #ifdef PT_SUSPEND
00220     case PT_SUSPEND:
00221 #endif
00222 #ifdef PT_RESUME
00223     case PT_RESUME:
00224 #endif
00225 #ifdef PT_TO_SCE
00226     case PT_TO_SCE:
00227 #endif
00228 #ifdef PT_TO_SCX
00229     case PT_TO_SCX :
00230 #endif
00231 #ifdef PT_GETDBREGS
00232     case PT_GETDBREGS:
00233 #endif
00234 #ifdef PT_SETDBREGS
00235     case PT_SETDBREGS:
00236 #endif
00237 #ifdef PT_VM_TIMESTAMP
00238     case PT_VM_TIMESTAMP:
00239 #endif
00240 #ifdef PT_VM_ENTRY
00241     case PT_VM_ENTRY:
00242 #endif
00243         return 1;
00244 
00245     default:
00246         break;
00247     }
00248     return 0;
00249 }
00250 
00251 
00252 static int
00253 calculate_addr_size(int request)
00254 {
00255     switch (request)
00256     {
00257 #ifdef PT_READ_U
00258     case PT_READ_U:
00259 #endif
00260 #ifdef PT_WRITE_I
00261     case PT_WRITE_I:
00262 #endif
00263 #ifdef PT_WRITE_D
00264     case PT_WRITE_D:
00265 #endif
00266 #ifdef PT_WRITE_U
00267     case PT_WRITE_U:
00268 #endif
00269         return sizeof(int);
00270 
00271     default:
00272         break;
00273     }
00274     return 0;
00275 }
00276 
00277 
00278 static int
00279 calculate_data_size(int request)
00280 {
00281     /*
00282      * The following structs are all defined in <sys/user.h> (on Linux,
00283      * anyway), so if your system doesn't have them, we can't give
00284      * useful answers.
00285      */
00286     switch (request)
00287     {
00288 #ifdef SYS_PTRACE_USER_REGS_STRUCT
00289 #ifdef PT_GETREGS
00290     case PT_GETREGS:
00291         return sizeof(struct user_regs_struct);
00292 #endif
00293 #ifdef PT_SETREGS
00294     case PT_SETREGS:
00295         return sizeof(struct user_regs_struct);
00296 #endif
00297 #endif /* SYS_PTRACE_USER_REGS_STRUCT */
00298 
00299 #ifdef SYS_PTRACE_USER_FPREGS_STRUCT
00300 #ifdef PT_GETFPREGS
00301     case PT_GETFPREGS:
00302         return sizeof(struct user_fpregs_struct);
00303 #endif
00304 #ifdef PT_SETFPREGS
00305     case PT_SETFPREGS:
00306         return sizeof(struct user_fpregs_struct);
00307 #endif
00308 #endif /* SYS_PTRACE_USER_FPREGS_STRUCT */
00309 
00310 #ifdef SYS_PTRACE_USER_FPXREGS_STRUCT
00311 #ifdef PT_GETFPXREGS
00312     case PT_GETFPXREGS:
00313         return sizeof(struct user_fpxregs_struct);
00314 #endif
00315 #ifdef PT_SETFPXREGS
00316     case PT_SETFPXREGS:
00317         return sizeof(struct user_fpxregs_struct);
00318 #endif
00319 #endif /* SYS_PTRACE_USER_FPREGS_STRUCT */
00320 
00321 #ifdef PT_GETEVENTMSG
00322     case PT_GETEVENTMSG:
00323         return sizeof(unsigned long);
00324 #endif
00325 #ifdef PT_GETSIGINFO
00326     case PT_GETSIGINFO:
00327         return sizeof(siginfo_t);
00328 #endif
00329 #ifdef PT_SETSIGINFO
00330     case PT_SETSIGINFO:
00331         return sizeof(siginfo_t);
00332 #endif
00333 
00334 #ifdef PT_VM_ENTRY
00335     case PT_VM_ENTRY:
00336         /* FreeBSD, not Linux */
00337         return sizeof(struct ptrace_vm_entry);
00338 #endif
00339 
00340     default:
00341         break;
00342     }
00343     return 0;
00344 }
00345 
00346 #if defined(PT_SETOPTIONS) || defined(PT_OLDSETOPTIONS)
00347 
00348 static void
00349 setting_an_invalid_option(explain_string_buffer_t *sb)
00350 {
00351     explain_buffer_gettext
00352     (
00353         sb,
00354         /*
00355          * xgettext: This error message is issued to explain an EINVAL
00356          * error reported by the ptrace(2) system call, in the case
00357          * where an attempt was made to set an invalid option.
00358          */
00359         i18n("an attempt was made to set an invalid option")
00360     );
00361 }
00362 
00363 #endif
00364 
00365 void
00366 explain_buffer_errno_ptrace_explanation(explain_string_buffer_t *sb, int errnum,
00367     const char *syscall_name, int request, pid_t pid, void *addr, void *data)
00368 {
00369     size_t addr_size = calculate_addr_size(request);
00370     size_t data_size = calculate_data_size(request);
00371 
00372     /*
00373      * http://www.opengroup.org/onlinepubs/009695399/functions/ptrace.html
00374      */
00375     switch (errnum)
00376     {
00377     case EBUSY:
00378         explain_buffer_gettext
00379         (
00380             sb,
00381             /*
00382              * xgettext: This error message is issued to explain an EBUSY error
00383              * reported by the ptrace(2) system call, in the case where there
00384              * was an error with allocating or freeing a debug register.
00385              */
00386             i18n("there was an error with allocating or freeing a debug "
00387                 "register")
00388         );
00389         break;
00390 
00391     case EFAULT:
00392         if (addr_size && explain_is_efault_pointer(addr, addr_size))
00393         {
00394             explain_buffer_efault(sb, "addr");
00395             break;
00396         }
00397         if (data_size && explain_is_efault_pointer(data, data_size))
00398         {
00399             explain_buffer_efault(sb, "data");
00400             break;
00401         }
00402         explain_buffer_gettext
00403         (
00404             sb,
00405             /*
00406              * xgettext: This error message is issued to explain an EFAULT error
00407              * reported by the ptrace(2) system call, in the cases where there
00408              * was an attempt to read from or write to an invalid area in the
00409              * parent's or child's memory, probably because the area wasn't
00410              * mapped or accessible.
00411              */
00412             i18n("there was an attempt to read from or write to an invalid "
00413                 "area in the parent's or child's memory, probably because the "
00414                 "area wasn't mapped or accessible")
00415         );
00416         /*
00417          * Unfortunately, under Linux, different variations of this
00418          * fault will return EIO or EFAULT more or less arbitrarily.
00419          */
00420         break;
00421 
00422     case EINVAL:
00423         if (!request_is_known(request))
00424         {
00425             explain_buffer_einval_vague(sb, "request");
00426             return;
00427         }
00428 #ifdef PT_SETOPTIONS
00429         if (request == PT_SETOPTIONS)
00430         {
00431             setting_an_invalid_option(sb);
00432             break;
00433         }
00434 #endif
00435 #ifdef PT_OLDSETOPTIONS
00436         if (request == PT_OLDSETOPTIONS)
00437         {
00438             setting_an_invalid_option(sb);
00439             break;
00440         }
00441 #endif
00442         goto generic;
00443 
00444     case EIO:
00445         if (!request_is_known(request))
00446         {
00447             explain_buffer_einval_vague(sb, "request");
00448             return;
00449         }
00450         if (addr_size && explain_is_efault_pointer(addr, addr_size))
00451         {
00452             explain_buffer_efault(sb, "addr");
00453             break;
00454         }
00455         if (data_size && explain_is_efault_pointer(data, data_size))
00456         {
00457             explain_buffer_efault(sb, "data");
00458             break;
00459         }
00460         switch (request)
00461         {
00462 #ifdef PT_CONTINUE
00463         case PT_CONTINUE:
00464 #endif
00465 #ifdef PT_SYSCALL
00466         case PT_SYSCALL:
00467 #endif
00468 #ifdef PT_STEP
00469         case PT_STEP:
00470 #endif
00471 #ifdef PT_SYSEMU
00472         case PT_SYSEMU:
00473 #endif
00474 #ifdef PT_SYSEMU_SINGLESTEP
00475         case PT_SYSEMU_SINGLESTEP:
00476 #endif
00477 #ifdef PT_DETACH
00478         case PT_DETACH:
00479 #endif
00480             explain_buffer_gettext
00481             (
00482                 sb,
00483                 /*
00484                  * xgettext: This error message is issued to explain an EIO
00485                  * error reported by the ptrace(2) system call, in the case
00486                  * where an invalid signal was specified during a restart
00487                  * request.
00488                  */
00489                 i18n("an invalid signal was specified during a restart request")
00490             );
00491             return;
00492 
00493         default:
00494             break;
00495         }
00496         explain_buffer_gettext
00497         (
00498             sb,
00499             /*
00500              * xgettext: This error message is issued to explain an EIO error
00501              * reported by the ptrace(2) system call, in the case where there
00502              * was a word-alignment violation.
00503              */
00504             i18n("there was a word-alignment violation")
00505         );
00506         break;
00507 
00508     case EPERM:
00509         if (!explain_process_exists(pid))
00510         {
00511             explain_buffer_eperm_kill(sb);
00512             break;
00513         }
00514 
00515         /*
00516          * Unprivileged processes cannot trace processes that are
00517          * running set-user-ID or set-group-ID programs.
00518          *
00519          * The process may already be being traced.
00520          * FIXME: can prctl tell us this?
00521          *
00522          * The process may be init(8), i.e. pid == 1
00523          */
00524         explain_buffer_gettext
00525         (
00526             sb,
00527             /*
00528              * xgettext: This error message is issued to explain an EPERM error
00529              * reported by the ptrace(2) system call, in the case where the
00530              * specified process cannot be traced.
00531              */
00532             i18n("the specified process cannot be traced")
00533         );
00534         break;
00535 
00536     case ESRCH:
00537         if (pid <= 0 || kill(pid, 0) < 0)
00538         {
00539             explain_buffer_eperm_kill(sb);
00540             break;
00541         }
00542 
00543         /* FIXME: figure out which case applies */
00544         /* FIXME: i18n */
00545         explain_string_buffer_puts
00546         (
00547             sb,
00548             "the specified process is not currently being traced by the "
00549             "caller, or is not stopped (for requests that require that)"
00550         );
00551         break;
00552 
00553     default:
00554         generic:
00555         explain_buffer_errno_generic(sb, errnum, syscall_name);
00556         break;
00557     }
00558 }
00559 
00560 
00561 void
00562 explain_buffer_errno_ptrace(explain_string_buffer_t *sb, int errnum, int
00563     request, pid_t pid, void *addr, void *data)
00564 {
00565     explain_explanation_t exp;
00566 
00567     explain_explanation_init(&exp, errnum);
00568     explain_buffer_errno_ptrace_system_call(&exp.system_call_sb, errnum,
00569         request, pid, addr, data);
00570     explain_buffer_errno_ptrace_explanation(&exp.explanation_sb, errnum,
00571         "ptrace", request, pid, addr, data);
00572     explain_explanation_assemble(&exp, sb);
00573 }
00574 
00575 
00576 /* vim: set ts=8 sw=4 et : */