tizen beta release
[external/psmisc.git] / src / peekfd.c
1 /*
2  * peekfd.c - Intercept file descriptor read and writes
3  *
4  * Copyright (C) 2007 Trent Waddington <trent.waddington@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <sys/ptrace.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <sys/syscall.h>
30 #include <byteswap.h>
31 #include <endian.h>
32 #include <sys/user.h>
33 #include <stdlib.h>
34 #include <getopt.h>
35 #include <ctype.h>
36
37 #include "i18n.h"
38
39 #ifdef I386
40         #define REG_ORIG_ACCUM orig_eax
41         #define REG_ACCUM eax
42         #define REG_PARAM1 ebx
43         #define REG_PARAM2 ecx
44         #define REG_PARAM3 edx
45 #elif X86_64
46         #define REG_ORIG_ACCUM orig_rax
47         #define REG_ACCUM rax
48         #define REG_PARAM1 rdi
49         #define REG_PARAM2 rsi
50         #define REG_PARAM3 rdx
51 #elif PPC
52         #define REG_ORIG_ACCUM gpr[0]
53         #define REG_ACCUM gpr[3]
54         #define REG_PARAM1 orig_gpr3
55         #define REG_PARAM2 gpr[4]
56         #define REG_PARAM3 gpr[5]
57 #ifndef PT_ORIG_R3
58         #define PT_ORIG_R3 34
59 #endif
60 #endif
61
62 #define MAX_ATTACHED_PIDS 1024
63 int num_attached_pids = 0;
64 pid_t attached_pids[MAX_ATTACHED_PIDS];
65
66 void detach(void) {
67         int i;
68         for (i = 0; i < num_attached_pids; i++) 
69                 ptrace(PTRACE_DETACH, attached_pids[i], 0, 0);
70 }
71
72 void attach(pid_t pid) {
73         attached_pids[0] = pid;
74         if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
75                 fprintf(stderr, _("Error attaching to pid %i\n"), pid);
76                 return;
77         }
78         num_attached_pids++;
79 }
80
81 void print_version()
82 {
83   fprintf(stderr, _("peekfd (PSmisc) %s\n"), VERSION);
84   fprintf(stderr, _(
85     "Copyright (C) 2007 Trent Waddington\n\n"));
86   fprintf(stderr, _(
87     "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
88     "This is free software, and you are welcome to redistribute it under\n"
89     "the terms of the GNU General Public License.\n"
90     "For more information about these matters, see the files named COPYING.\n"));
91 }
92
93 void usage() {
94         fprintf(stderr, _(
95       "Usage: peekfd [-8] [-n] [-c] [-d] [-V] [-h] <pid> [<fd> ..]\n"
96           "    -8 output 8 bit clean streams.\n"
97           "    -n don't display read/write from fd headers.\n"
98           "    -c peek at any new child processes too.\n"
99           "    -d remove duplicate read/writes from the output.\n"
100           "    -V prints version info.\n"
101           "    -h prints this help.\n"
102           "\n"
103           "  Press CTRL-C to end output.\n"));
104 }
105
106 int bufdiff(int pid, unsigned char *lastbuf, unsigned int addr, unsigned int len) {
107         int i;
108         for (i = 0; i < len; i++)
109                 if (lastbuf[i] != (ptrace(PTRACE_PEEKTEXT, pid, addr + i, 0) & 0xff))
110                         return 1;
111         return 0;
112 }
113
114 int main(int argc, char **argv)
115 {
116         int eight_bit_clean = 0;
117         int no_headers = 0;
118         int follow_forks = 0;
119         int remove_duplicates = 0;
120         int optc;
121     int target_pid = 0;
122     int numfds = 0;
123     int *fds = NULL;
124     int i;
125
126     struct option options[] = {
127       {"eight-bit-clean", 0, NULL, '8'},
128       {"no-headers", 0, NULL, 'n'},
129       {"follow", 0, NULL, 'f'},
130       {"duplicates-removed", 0, NULL, 'd'},
131       {"help", 0, NULL, 'h'},
132       {"version", 0, NULL, 'V'},
133     };
134
135   /* Setup the i18n */
136 #ifdef ENABLE_NLS
137     setlocale(LC_ALL, "");
138     bindtextdomain(PACKAGE, LOCALEDIR);
139     textdomain(PACKAGE);
140 #endif
141
142         if (argc < 2) {
143                 usage();
144                 return 1;
145         }
146
147         while ((optc = getopt_long(argc, argv, "8ncdhV",options, NULL)) != -1) {
148                 switch(optc) {
149                         case '8':
150                                 eight_bit_clean = 1;
151                                 break;
152                         case 'n':
153                                 no_headers = 1;
154                                 break;
155                         case 'c':
156                                 follow_forks = 1;
157                                 break;
158                         case 'd':
159                                 remove_duplicates = 1;
160                                 break;
161                         case 'V':
162                                 print_version();
163                                 return 1;
164                         case 'h':
165                         case '?':
166                                 usage();
167                                 return 1;
168                 }
169         }
170     /* First arg off the options is the PID to see */
171     if (optind >= argc) {
172       usage();
173       return -1;
174     }
175     target_pid = atoi(argv[optind++]);
176
177     if (optind < argc) {
178       numfds = argc - optind;
179       fds = malloc(sizeof(int) * numfds);
180           for (i = 0; i < numfds; i++)
181                 fds[i] = atoi(argv[optind + 1 + i]);
182     }
183
184         attach(target_pid);
185         if (num_attached_pids == 0)
186                 return 1;
187
188         atexit(detach);
189
190         ptrace(PTRACE_SYSCALL, attached_pids[0], 0, 0);
191
192         /*int count = 0;*/
193         int lastfd = numfds > 0 ? fds[0] : 0;
194         int lastdir = 3;
195         unsigned char *lastbuf = NULL;
196         int last_buf_size=-1;
197
198         for(;;) {
199                 int status;
200                 int pid = wait(&status);
201                 if (WIFSTOPPED(status)) {
202 #ifdef PPC
203                         struct pt_regs regs;
204                         regs.gpr[0] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R0, 0);
205                         regs.gpr[3] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R3, 0);
206                         regs.gpr[4] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R4, 0);
207                         regs.gpr[5] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R5, 0);
208                         regs.orig_gpr3 = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_ORIG_R3, 0);
209 #else
210                         struct user_regs_struct regs;
211                         ptrace(PTRACE_GETREGS, pid, 0, &regs);
212 #endif          
213                         /*unsigned int b = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);*/
214                         if (follow_forks && (regs.REG_ORIG_ACCUM == SYS_fork || regs.REG_ORIG_ACCUM == SYS_clone)) {
215                                 if (regs.REG_ACCUM > 0)
216                                         attach(regs.REG_ACCUM);                                 
217                         }
218                         if ((regs.REG_ORIG_ACCUM == SYS_read || regs.REG_ORIG_ACCUM == SYS_write) && (regs.REG_PARAM3 == regs.REG_ACCUM)) {
219                                 for (i = 0; i < numfds; i++)
220                                         if (fds[i] == regs.REG_PARAM1)
221                                                 break;
222                                 if (i != numfds || numfds == 0) {
223                                         if (regs.REG_PARAM1 != lastfd || regs.REG_ORIG_ACCUM != lastdir) {
224                                                 lastfd = regs.REG_PARAM1;
225                                                 lastdir = regs.REG_ORIG_ACCUM;
226                                                 if (!no_headers)
227                                                         printf("\n%sing fd %i:\n", regs.REG_ORIG_ACCUM == SYS_read ? "read" : "writ", lastfd);
228                                         }
229                                         if (!remove_duplicates || lastbuf == NULL
230                                                         ||  last_buf_size != regs.REG_PARAM3 || 
231                                                         bufdiff(pid, lastbuf, regs.REG_PARAM2, regs.REG_PARAM3)) {
232
233                                                 if (remove_duplicates) {
234                                                         if (lastbuf)
235                                                                 free(lastbuf);
236                                                         lastbuf = malloc(regs.REG_PARAM3);
237                                                         last_buf_size = regs.REG_PARAM3;
238                                                 }
239
240                                                 for (i = 0; i < regs.REG_PARAM3; i++) {
241 #ifdef _BIG_ENDIAN
242                                                         unsigned int a = bswap_32(ptrace(PTRACE_PEEKTEXT, pid, regs.REG_PARAM2 + i, 0));
243 #else
244                                                         unsigned int a = ptrace(PTRACE_PEEKTEXT, pid, regs.REG_PARAM2 + i, 0);
245 #endif
246                                                         if (remove_duplicates)
247                                                                 lastbuf[i] = a & 0xff;
248
249                                                         if (eight_bit_clean)
250                                                                 putchar(a & 0xff);
251                                                         else {
252                                                                 if (isprint(a & 0xff) || (a & 0xff) == '\n')
253                                                                         printf("%c", a & 0xff);
254                                                                 else if ((a & 0xff) == 0x0d)
255                                                                         printf("\n");
256                                                                 else if ((a & 0xff) == 0x7f)
257                                                                         printf("\b");
258                                                                 else if (a & 0xff)
259                                                                         printf(" [%02x] ", a & 0xff);
260                                                         }
261                                                 }
262                                         }
263                                         fflush(stdout);
264                                 }
265                         }
266
267                         ptrace(PTRACE_SYSCALL, pid, 0, 0);
268                 }
269         }
270
271         return 0;
272 }