OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / procps / pmap.c
1 /*
2  * Copyright 2002 by Albert Cahalan; all rights reserved.
3  * This file may be used subject to the terms and conditions of the
4  * GNU Library General Public License Version 2, or any later version
5  * at your option, as published by the Free Software Foundation.
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU Library General Public License for more details.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #include <sys/ipc.h>
22 #include <sys/shm.h>
23
24 #include "proc/readproc.h"
25 #include "proc/version.h"
26 #include "proc/escape.h"
27
28 static void usage(void) NORETURN;
29 static void usage(void){
30   fprintf(stderr,
31     "Usage: pmap [-x | -d] [-q] pid...\n"
32     "-x  show details\n"
33     "-d  show offset and device number\n"
34     "-q  quiet; less header/footer info\n"
35     "-V  show the version number\n"
36   );
37   exit(1);
38 }
39
40
41 static int V_option;
42 static int r_option;  // ignored -- for SunOS compatibility
43 static int x_option;
44 static int d_option;
45 static int q_option;
46
47
48 static unsigned shm_minor = ~0u;
49
50 static void discover_shm_minor(void){
51   void *addr;
52   int shmid;
53   char mapbuf[256];
54
55   if(!freopen("/proc/self/maps", "r", stdin)) return;
56
57   // create
58   shmid = shmget(IPC_PRIVATE, 42, IPC_CREAT | 0666);
59   if(shmid==-1) return; // failed; oh well
60   // attach
61   addr = shmat(shmid, NULL, SHM_RDONLY);
62   if(addr==(void*)-1) goto out_destroy;
63
64   while(fgets(mapbuf, sizeof mapbuf, stdin)){
65     char flags[32];
66     char *tmp; // to clean up unprintables
67     unsigned KLONG start, end;
68     unsigned long long file_offset, inode;
69     unsigned dev_major, dev_minor;
70     sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
71     tmp = strchr(mapbuf,'\n');
72     if(tmp) *tmp='\0';
73     tmp = mapbuf;
74     while(*tmp){
75       if(!isprint(*tmp)) *tmp='?';
76       tmp++;
77     }
78     if(start > (unsigned long)addr) continue;
79     if(dev_major) continue;
80     if(flags[3] != 's') continue;
81     if(strstr(mapbuf,"/SYSV")){
82       shm_minor = dev_minor;
83       break;
84     }
85   }
86
87   if(shmdt(addr)) perror("shmdt");
88
89 out_destroy:
90   if(shmctl(shmid, IPC_RMID, NULL)) perror("IPC_RMID");
91
92   return;
93 }
94
95
96 static const char *mapping_name(proc_t *p, unsigned KLONG addr, unsigned KLONG len, const char *mapbuf, unsigned showpath, unsigned dev_major, unsigned dev_minor, unsigned long long inode){
97   const char *cp;
98
99   if(!dev_major && dev_minor==shm_minor && strstr(mapbuf,"/SYSV")){
100     static char shmbuf[64];
101     snprintf(shmbuf, sizeof shmbuf, "  [ shmid=0x%Lx ]", inode);
102     return shmbuf;
103   }
104
105   cp = strrchr(mapbuf,'/');
106   if(cp){
107     if(showpath) return strchr(mapbuf,'/');
108     return cp[1] ? cp+1 : cp;
109   }
110
111   cp = strchr(mapbuf,'/');
112   if(cp){
113     if(showpath) return cp;
114     return strrchr(cp,'/') + 1;  // it WILL succeed
115   }
116
117   cp = "  [ anon ]";
118   if( (p->start_stack >= addr) && (p->start_stack <= addr+len) )  cp = "  [ stack ]";
119   return cp;
120 }
121
122 static int one_proc(proc_t *p){
123   char buf[32];
124   char mapbuf[9600];
125   char cmdbuf[512];
126   unsigned long total_shared = 0ul;
127   unsigned long total_private_readonly = 0ul;
128   unsigned long total_private_writeable = 0ul;
129
130   // Overkill, but who knows what is proper? The "w" prog
131   // uses the tty width to determine this.
132   int maxcmd = 0xfffff;
133
134   sprintf(buf,"/proc/%u/maps",p->tgid);
135   if(!freopen(buf, "r", stdin)) return 1;
136
137   escape_command(cmdbuf, p, sizeof cmdbuf, &maxcmd, ESC_ARGS|ESC_BRACKETS);
138   printf("%u:   %s\n", p->tgid, cmdbuf);
139
140   if(!q_option && (x_option|d_option)){
141     if(x_option){
142       if(sizeof(KLONG)==4) printf("Address   Kbytes     RSS    Anon  Locked Mode   Mapping\n");
143       else         printf("Address           Kbytes     RSS    Anon  Locked Mode   Mapping\n");
144     }
145     if(d_option){
146       if(sizeof(KLONG)==4) printf("Address   Kbytes Mode  Offset           Device    Mapping\n");
147       else         printf("Address           Kbytes Mode  Offset           Device    Mapping\n");
148     }
149   }
150
151   while(fgets(mapbuf,sizeof mapbuf,stdin)){
152     char flags[32];
153     char *tmp; // to clean up unprintables
154     unsigned KLONG start, end, diff;
155     unsigned long long file_offset, inode;
156     unsigned dev_major, dev_minor;
157     sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
158     tmp = strchr(mapbuf,'\n');
159     if(tmp) *tmp='\0';
160     tmp = mapbuf;
161     while(*tmp){
162       if(!isprint(*tmp)) *tmp='?';
163       tmp++;
164     }
165     
166     diff = end-start;
167     if(flags[3]=='s') total_shared  += diff;
168     if(flags[3]=='p'){
169       flags[3] = '-';
170       if(flags[1]=='w') total_private_writeable += diff;
171       else              total_private_readonly  += diff;
172     }
173
174     // format used by Solaris 9 and procps-3.2.0+
175     // an 'R' if swap not reserved (MAP_NORESERVE, SysV ISM shared mem, etc.)
176     flags[4] = '-';
177     flags[5] = '\0';
178
179     if(x_option){
180       const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
181       printf(
182         (sizeof(KLONG)==8)
183           ? "%016"KLF"x %7lu       -       -       - %s  %s\n"
184           :      "%08lx %7lu       -       -       - %s  %s\n",
185         start,
186         (unsigned long)(diff>>10),
187         flags,
188         cp
189       );
190     }
191     if(d_option){
192       const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
193       printf(
194         (sizeof(KLONG)==8)
195           ? "%016"KLF"x %7lu %s %016Lx %03x:%05x %s\n"
196           :      "%08lx %7lu %s %016Lx %03x:%05x %s\n",
197         start,
198         (unsigned long)(diff>>10),
199         flags,
200         file_offset,
201         dev_major, dev_minor,
202         cp
203       );
204     }
205     if(!x_option && !d_option){
206       const char *cp = mapping_name(p, start, diff, mapbuf, 1, dev_major, dev_minor, inode);
207       printf(
208         (sizeof(KLONG)==8)
209           ? "%016"KLF"x %6luK %s  %s\n"
210           :      "%08lx %6luK %s  %s\n",
211         start,
212         (unsigned long)(diff>>10),
213         flags,
214         cp
215       );
216     }
217     
218   }
219
220   if(!q_option){
221     if(x_option){
222       if(sizeof(KLONG)==8){
223         printf("----------------  ------  ------  ------  ------\n");
224         printf(
225           "total kB %15ld       -       -       -\n",
226           (total_shared + total_private_writeable + total_private_readonly) >> 10
227         );
228       }else{
229         printf("-------- ------- ------- ------- -------\n");
230         printf(
231           "total kB %7ld       -       -       -\n",
232           (total_shared + total_private_writeable + total_private_readonly) >> 10
233         );
234       }
235     }
236     if(d_option){
237         printf(
238           "mapped: %ldK    writeable/private: %ldK    shared: %ldK\n",
239           (total_shared + total_private_writeable + total_private_readonly) >> 10,
240           total_private_writeable >> 10,
241           total_shared >> 10
242         );
243     }
244     if(!x_option && !d_option){
245       if(sizeof(KLONG)==8) printf(" total %16ldK\n", (total_shared + total_private_writeable + total_private_readonly) >> 10);
246       else                 printf(" total %8ldK\n",  (total_shared + total_private_writeable + total_private_readonly) >> 10);
247     }
248   }
249
250   return 0;
251 }
252
253
254 int main(int argc, char *argv[]){
255   unsigned *pidlist;
256   unsigned count = 0;
257   PROCTAB* PT;
258   proc_t p;
259   int ret = 0;
260
261   if(argc<2) usage();
262   pidlist = malloc(sizeof(unsigned)*argc);  // a bit more than needed perhaps
263
264   while(*++argv){
265     if(!strcmp("--version",*argv)){
266       V_option++;
267       continue;
268     }
269     if(**argv=='-'){
270       char *walk = *argv;
271       if(!walk[1]) usage();
272       while(*++walk){
273         switch(*walk){
274         case 'V':
275           V_option++;
276           break;
277         case 'x':
278           x_option++;
279           break;
280         case 'r':
281           r_option++;
282           break;
283         case 'd':
284           d_option++;
285           break;
286         case 'q':
287           q_option++;
288           break;
289         default:
290           usage();
291         }
292       }
293     }else{
294       char *walk = *argv;
295       char *endp;
296       unsigned long pid;
297       if(!strncmp("/proc/",walk,6)){
298         walk += 6;
299         // user allowed to do: pmap /proc/*
300         if(*walk<'0' || *walk>'9') continue;
301       }
302       if(*walk<'0' || *walk>'9') usage();
303       pid = strtoul(walk, &endp, 0);
304       if(pid<1ul || pid>0x7ffffffful || *endp) usage();
305       pidlist[count++] = pid;
306     }
307   }
308
309   if( (x_option|V_option|r_option|d_option|q_option) >> 1 ) usage(); // dupes
310   if(V_option){
311     if(count|x_option|r_option|d_option|q_option) usage();
312     fprintf(stdout, "pmap (%s)\n", procps_version);
313     return 0;
314   }
315   if(count<1) usage();   // no processes
316   if(d_option && x_option) usage();
317
318   discover_shm_minor();
319
320   pidlist[count] = 0;  // old libproc interface is zero-terminated
321   PT = openproc(PROC_FILLSTAT|PROC_FILLARG|PROC_PID, pidlist);
322   while(readproc(PT, &p)){
323     ret |= one_proc(&p);
324     if(p.cmdline) free((void*)*p.cmdline);
325     count--;
326   }
327   closeproc(PT);
328
329   if(count) ret |= 42;  // didn't find all processes asked for
330   return ret;
331 }