root/trunk/extensions/pmap.c

Revision 5, 24.6 kB (checked in by jesus, 7 years ago)

make this work with 8.2.x

Line 
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26
27 #pragma ident   "@(#)pmap.c     1.32    06/09/11 SMI"
28
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <ctype.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <limits.h>
38 #include <link.h>
39 #include <libelf.h>
40 #include <sys/types.h>
41 #include <signal.h>
42 #include <sys/stat.h>
43 #include <sys/mkdev.h>
44 #include <sys/mman.h>
45 #include <sys/lgrp_user.h>
46 #include "libproc.h"
47 #include "libzonecfg.h"
48
49 #include "postgres.h"
50 #include "fmgr.h"
51 #include "funcapi.h"
52
53 #ifdef PG_MODULE_MAGIC
54 PG_MODULE_MAGIC;
55 #endif
56
57 #define SOL_MAP_DATA_CNT 13
58 #define KILOBYTE        1024
59 #define MEGABYTE        (KILOBYTE * KILOBYTE)
60 #define GIGABYTE        (KILOBYTE * KILOBYTE * KILOBYTE)
61
62 /*
63  * Round up the value to the nearest kilobyte
64  */
65 #define ROUNDUP_KB(x)   (((x) + (KILOBYTE - 1)) / KILOBYTE)
66
67 /*
68  * The alignment should be a power of 2.
69  */
70 #define P2ALIGN(x, align)               ((x) & -(align))
71
72 #define INVALID_ADDRESS                 (uintptr_t)(-1)
73
74
75 /*
76  * -L option requires per-page information. The information is presented in an
77  * array of page_descr structures.
78  */
79 typedef struct page_descr {
80         uintptr_t       pd_start;       /* start address of a page */
81         size_t          pd_pagesize;    /* page size in bytes */
82         lgrp_id_t       pd_lgrp;        /* lgroup of memory backing the page */
83         int             pd_valid;       /* valid page description if non-zero */
84 } page_descr_t;
85
86 /*
87  * Per-page information for a memory chunk.
88  * The meminfo(2) system call accepts up to MAX_MEMINFO_CNT pages at once.
89  * When we need to scan larger ranges we divide them in MAX_MEMINFO_CNT sized
90  * chunks. The chunk information is stored in the memory_chunk structure.
91  */
92 typedef struct memory_chunk {
93         page_descr_t    page_info[MAX_MEMINFO_CNT];
94         uintptr_t       end_addr;
95         uintptr_t       chunk_start;    /* Starting address */
96         uintptr_t       chunk_end;      /* chunk_end is always <= end_addr */
97         size_t          page_size;
98         int             page_index;     /* Current page */
99         int             page_count;     /* Number of pages */
100 } memory_chunk_t;
101
102 typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int);
103
104 static  int     xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *,
105     int);
106
107 static  int     look_xmap_nopgsz(void *, const prxmap_t *, const char *,
108     int, int);
109
110 static int gather_xmap(void *, const prxmap_t *, const char *, int, int);
111 static int iter_map(proc_map_f *, void *);
112 static int iter_xmap(proc_xmap_f *, void *);
113
114 static  int     perr(char *);
115
116 static int      address_in_range(uintptr_t, uintptr_t, size_t);
117 static size_t   adjust_addr_range(uintptr_t, uintptr_t, size_t,
118     uintptr_t *, uintptr_t *);
119
120 /*
121  * The -A address range is represented as a pair of addresses
122  * <start_addr, end_addr>. Either one of these may be unspecified (set to
123  * INVALID_ADDRESS). If both are unspecified, no address range restrictions are
124  * in place.
125  */
126 static  uintptr_t start_addr = INVALID_ADDRESS;
127 static  uintptr_t end_addr = INVALID_ADDRESS;
128
129 static  int     addr_width, size_width;
130 static  char    *command;
131 static  char    *procname;
132 static  struct ps_prochandle *Pr;
133
134 typedef struct lwpstack {
135         lwpid_t lwps_lwpid;
136         stack_t lwps_stack;
137 } lwpstack_t;
138
139 typedef struct {
140         prxmap_t        md_xmap;
141         prmap_t         md_map;
142         char            *md_objname;
143         boolean_t       md_last;
144         int             md_doswap;
145 } mapdata_t;
146
147 static  mapdata_t       *maps;
148 static  int             map_count;
149 static  int             map_alloc;
150
151 static  lwpstack_t *stacks = NULL;
152 static  uint_t  nstacks = 0;
153
154 #define MAX_TRIES       5
155
156 static int
157 getstack(void *data, const lwpstatus_t *lsp)
158 {
159         int *np = (int *)data;
160
161         if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) {
162                 stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK;
163                 stacks[*np].lwps_lwpid = lsp->pr_lwpid;
164                 (*np)++;
165         }
166
167         if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) {
168                 stacks[*np].lwps_lwpid = lsp->pr_lwpid;
169                 (*np)++;
170         }
171
172         return (0);
173 }
174
175 /*
176  * We compare the high memory addresses since stacks are faulted in from
177  * high memory addresses to low memory addresses, and our prmap_t
178  * structures identify only the range of addresses that have been faulted
179  * in so far.
180  */
181 static int
182 cmpstacks(const void *ap, const void *bp)
183 {
184         const lwpstack_t *as = ap;
185         const lwpstack_t *bs = bp;
186         uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size;
187         uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size;
188
189         if (a < b)
190                 return (1);
191         if (a > b)
192                 return (-1);
193         return (0);
194 }
195
196 static char *
197 make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname,
198         char *buf, size_t bufsz)
199 {
200         const pstatus_t         *Psp = Pstatus(Pr);
201         const psinfo_t          *pi = Ppsinfo(Pr);
202         char                    fname[100];
203         struct stat             statb;
204         int                     len;
205         char                    zname[ZONENAME_MAX];
206         char                    zpath[PATH_MAX];
207         char                    objname[PATH_MAX];
208
209         if (strcmp(mapname, "a.out") == 0 &&
210             Pexecname(Pr, buf, bufsz) != NULL)
211                 return (buf);
212
213         if (Pobjname(Pr, addr, objname, sizeof (objname)) != NULL) {
214                 (void) strncpy(buf, objname, bufsz);
215
216                 if ((len = resolvepath(buf, buf, bufsz)) > 0) {
217                         buf[len] = '\0';
218                         return (buf);
219                 }
220
221                 /*
222                  * If the target is in a non-global zone, attempt to prepend
223                  * the zone path in order to give the global-zone caller the
224                  * real path to the file.
225                  */
226                 if (getzonenamebyid(pi->pr_zoneid, zname,
227                         sizeof (zname)) != -1 && strcmp(zname, "global") != 0 &&
228                     zone_get_zonepath(zname, zpath, sizeof (zpath)) == Z_OK) {
229                         (void) strncat(zpath, "/root",
230                             MAXPATHLEN - strlen(zpath));
231
232                         if (bufsz <= strlen(zpath))
233                                 return (NULL);
234
235                         (void) strncpy(buf, zpath, bufsz);
236                         (void) strncat(buf, objname, bufsz - strlen(zpath));
237                 }
238
239                 if ((len = resolvepath(buf, buf, bufsz)) > 0) {
240                         buf[len] = '\0';
241                         return (buf);
242                 }
243         }
244
245         if (Pstate(Pr) != PS_DEAD && *mapname != '\0') {
246                 (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s",
247                         (int)Psp->pr_pid, mapname);
248                 if (stat(fname, &statb) == 0) {
249                         dev_t dev = statb.st_dev;
250                         ino_t ino = statb.st_ino;
251                         (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu",
252                                 (ulong_t)major(dev), (ulong_t)minor(dev), ino);
253                         return (buf);
254                 }
255         }
256
257         return (NULL);
258 }
259
260 static char *
261 anon_name(char *name, const pstatus_t *Psp,
262     uintptr_t vaddr, size_t size, int mflags, int shmid)
263 {
264         if (mflags & MA_ISM) {
265                 if (shmid == -1)
266                         (void) snprintf(name, PATH_MAX, "  [ %s shmid=null ]",
267                             (mflags & MA_NORESERVE) ? "ism" : "dism");
268                 else
269                         (void) snprintf(name, PATH_MAX, "  [ %s shmid=0x%x ]",
270                             (mflags & MA_NORESERVE) ? "ism" : "dism", shmid);
271         } else if (mflags & MA_SHM) {
272                 if (shmid == -1)
273                         (void) sprintf(name, "  [ shmid=null ]");
274                 else
275                         (void) sprintf(name, "  [ shmid=0x%x ]", shmid);
276         } else if (vaddr + size > Psp->pr_stkbase &&
277             vaddr < Psp->pr_stkbase + Psp->pr_stksize) {
278                 (void) strcpy(name, "  [ stack ]");
279         } else if ((mflags & MA_ANON) &&
280             vaddr + size > Psp->pr_brkbase &&
281             vaddr < Psp->pr_brkbase + Psp->pr_brksize) {
282                 (void) strcpy(name, "  [ heap ]");
283         } else {
284                 lwpstack_t key, *stk;
285
286                 key.lwps_stack.ss_sp = (void *)vaddr;
287                 key.lwps_stack.ss_size = size;
288                 if (nstacks > 0 &&
289                     (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]),
290                     cmpstacks)) != NULL) {
291                         (void) snprintf(name, PATH_MAX, "  [ %s tid=%d ]",
292                             (stk->lwps_stack.ss_flags & SS_ONSTACK) ?
293                             "altstack" : "stack",
294                             stk->lwps_lwpid);
295                 } else if (Pstate(Pr) != PS_DEAD) {
296                         (void) strcpy(name, "  [ anon ]");
297                 } else {
298                         return (NULL);
299                 }
300         }
301
302         return (name);
303 }
304
305 static int
306 xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap)
307 {
308         char mapname[PATH_MAX];
309         int mapfd, nmap, i, rc;
310         struct stat st;
311         prxmap_t *prmapp, *pmp;
312         ssize_t n;
313
314         (void) snprintf(mapname, sizeof (mapname),
315             "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid);
316
317         if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) {
318                 if (mapfd >= 0)
319                         (void) close(mapfd);
320                 return (perr(mapname));
321         }
322
323         nmap = st.st_size / sizeof (prxmap_t);
324         nmap *= 2;
325 again:
326         prmapp = malloc((nmap + 1) * sizeof (prxmap_t));
327
328         if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) {
329                 (void) close(mapfd);
330                 free(prmapp);
331                 return (perr("read xmap"));
332         }
333
334         if (nmap < n / sizeof (prxmap_t)) {
335                 free(prmapp);
336                 nmap *= 2;
337                 goto again;
338         }
339
340         (void) close(mapfd);
341         nmap = n / sizeof (prxmap_t);
342
343         for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) {
344                 if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) {
345                         free(prmapp);
346                         return (rc);
347                 }
348         }
349
350         /*
351          * Mark the last element.
352          */
353         if (map_count > 0)
354                 maps[map_count - 1].md_last = B_TRUE;
355
356         free(prmapp);
357         return (0);
358 }
359
360 /*ARGSUSED*/
361 static int
362 look_xmap_nopgsz(void *data,
363         const prxmap_t *pmp,
364         const char *object_name,
365         int last, int doswap)
366 {
367         const pstatus_t *Psp = Pstatus(Pr);
368         char mname[PATH_MAX];
369         char *lname = NULL;
370         char *ln;
371         static uintptr_t prev_vaddr;
372         static size_t prev_size;
373         static offset_t prev_offset;
374         static int prev_mflags;
375         static char *prev_lname;
376         static char prev_mname[PATH_MAX];
377         static ulong_t prev_rss;
378         static ulong_t prev_anon;
379         static ulong_t prev_locked;
380         static ulong_t prev_swap;
381         int merged = 0;
382         static int first = 1;
383         ulong_t swap = 0;
384         int kperpage;
385         int vo = 0;
386         char **values = (char **)data;
387
388         /*
389          * Calculate swap reservations
390          */
391         if (pmp->pr_mflags & MA_SHARED) {
392                 if ((pmp->pr_mflags & MA_NORESERVE) == 0) {
393                         /* Swap reserved for entire non-ism SHM */
394                         swap = pmp->pr_size / pmp->pr_pagesize;
395                 }
396         } else if (pmp->pr_mflags & MA_NORESERVE) {
397                 /* Swap reserved on fault for each anon page */
398                 swap = pmp->pr_anon;
399         } else if (pmp->pr_mflags & MA_WRITE) {
400                 /* Swap reserve for entire writable segment */
401                 swap = pmp->pr_size / pmp->pr_pagesize;
402         }
403
404         /*
405          * If the mapping is not anon or not part of the heap, make a name
406          * for it.  We don't want to report the heap as a.out's data.
407          */
408         if (!(pmp->pr_mflags & MA_ANON) ||
409             pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase ||
410             pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) {
411                 lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname,
412                     mname, sizeof (mname));
413         }
414
415         if (lname != NULL) {
416                 if ((ln = strrchr(lname, '/')) != NULL)
417                         lname = ln + 1;
418         } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) {
419                 lname = anon_name(mname, Psp, pmp->pr_vaddr,
420                     pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid);
421         }
422
423         kperpage = pmp->pr_pagesize / KILOBYTE;
424
425         prev_vaddr = pmp->pr_vaddr;
426         prev_size = pmp->pr_size;
427         prev_offset = pmp->pr_offset;
428         prev_mflags = pmp->pr_mflags;
429         if (lname == NULL) {
430                 prev_lname = NULL;
431         } else {
432                 (void) strcpy(prev_mname, lname);
433                 prev_lname = prev_mname;
434         }
435         prev_rss = pmp->pr_rss * kperpage;
436         prev_anon = pmp->pr_anon * kperpage;
437         prev_locked = pmp->pr_locked * kperpage;
438         prev_swap = swap * kperpage;
439
440         values[vo] = palloc(32 * sizeof(char));
441         snprintf(values[vo], 32, "%lu", (ulong_t)prev_vaddr);
442         vo++;
443
444         values[vo] = palloc(32 * sizeof(char));
445         snprintf(values[vo], 32, "%ld", prev_size);
446         vo++;
447
448         values[vo] = palloc(32 * sizeof(char));
449         snprintf(values[vo], 32, "%ld", prev_rss);
450         vo++;
451         values[vo] = palloc(32 * sizeof(char));
452         snprintf(values[vo], 32, "%ld", prev_anon);
453         vo++;
454         values[vo] = palloc(32 * sizeof(char));
455         snprintf(values[vo], 32, "%ld", prev_locked);
456         vo++;
457
458         values[vo] = palloc(2 * sizeof(char));
459         values[vo][0] = (prev_mflags & MA_READ)?'t':'f';
460         values[vo][1] = '\0';
461         vo++;
462         values[vo] = palloc(2 * sizeof(char));
463         values[vo][0] = (prev_mflags & MA_WRITE)?'t':'f';
464         values[vo][1] = '\0';
465         vo++;
466         values[vo] = palloc(2 * sizeof(char));
467         values[vo][0] = (prev_mflags & MA_EXEC)?'t':'f';
468         values[vo][1] = '\0';
469         vo++;
470         values[vo] = palloc(2 * sizeof(char));
471         values[vo][0] = (prev_mflags & MA_SHARED)?'t':'f';
472         values[vo][1] = '\0';
473         vo++;
474         values[vo] = palloc(2 * sizeof(char));
475         values[vo][0] = (prev_mflags & MA_NORESERVE)?'t':'f';
476         values[vo][1] = '\0';
477         vo++;
478         values[vo] = palloc(2 * sizeof(char));
479         values[vo][0] = (prev_mflags & MA_RESERVED1)?'t':'f';
480         values[vo][1] = '\0';
481         vo++;
482
483         values[vo] = NULL;
484         if(prev_lname) {
485                 values[vo] = palloc(16 * sizeof(char));
486                 if(!strncmp(prev_lname, "  [ heap ", strlen("  [ heap "))) {
487                   snprintf(values[vo], 16, "%s", "heap");
488                 }
489                 else if(!strncmp(prev_lname, "  [ stack ", strlen("  [ stack "))) {
490                   snprintf(values[vo], 16, "%s", "stack");
491                 }
492                 else if(!strncmp(prev_lname, "  [ anon ", strlen("  [ anon "))) {
493                   snprintf(values[vo], 16, "%s", "anon");
494                 }
495                 else if(!strncmp(prev_lname, "  [ ism ", strlen("  [ ism "))) {
496                   snprintf(values[vo], 16, "%s", "shared");
497                 }
498                 else if(!strncmp(prev_lname, "  [ dism ", strlen("  [ dism "))) {
499                   snprintf(values[vo], 16, "%s", "shared");
500                 }
501                 else {
502                   snprintf(values[vo], 16, "%s", "file");
503                 }
504         }
505         vo++;
506
507         values[vo] = NULL;
508         if(prev_lname) {
509                 values[vo] = palloc(strlen(prev_lname)+1);
510                 strcpy(values[vo], prev_lname);
511         }
512         vo++;
513
514         return (0);
515 }
516
517 static int
518 perr(char *s)
519 {
520         if (!s) s = procname;
521         ereport(ERROR, (errmsg("%s: %s", s, strerror(errno))));
522         return (1);
523 }
524
525 static mapdata_t *
526 nextmap(void)
527 {
528         mapdata_t *newmaps;
529         int next;
530
531         if (map_count == map_alloc) {
532                 if (map_alloc == 0)
533                         next = 16;
534                 else
535                         next = map_alloc * 2;
536
537                 newmaps = realloc(maps, next * sizeof (mapdata_t));
538                 if (newmaps == NULL) {
539                         (void) perr("failed to allocate maps");
540                         return NULL;
541                 }
542                 (void) memset(newmaps + map_alloc, '\0',
543                     (next - map_alloc) * sizeof (mapdata_t));
544
545                 map_alloc = next;
546                 maps = newmaps;
547         }
548
549         return (&maps[map_count++]);
550 }
551
552 /*ARGSUSED*/
553 static int
554 gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname,
555     int last, int doswap)
556 {
557         mapdata_t *data;
558
559         /* Skip mappings which are outside the range specified by -A */
560         if (!address_in_range(xmap->pr_vaddr,
561                 xmap->pr_vaddr + xmap->pr_size, xmap->pr_pagesize))
562                 return (0);
563
564         data = nextmap();
565         data->md_xmap = *xmap;
566         if (data->md_objname != NULL)
567                 free(data->md_objname);
568         data->md_objname = objname ? strdup(objname) : NULL;
569         data->md_last = last;
570         data->md_doswap = doswap;
571
572         return (0);
573 }
574
575 static int
576 iter_map(proc_map_f *func, void *data)
577 {
578         int i;
579         int ret;
580
581         for (i = 0; i < map_count; i++) {
582                 if ((ret = func(data, &maps[i].md_map,
583                     maps[i].md_objname)) != 0)
584                         return (ret);
585         }
586
587         return (0);
588 }
589
590 static int
591 iter_xmap(proc_xmap_f *func, void *data)
592 {
593         int i;
594         int ret;
595
596         for (i = 0; i < map_count; i++) {
597                 if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname,
598                     maps[i].md_last, maps[i].md_doswap)) != 0)
599                         return (ret);
600         }
601
602         return (0);
603 }
604
605 /*
606  * Convert lgroup ID to string.
607  * returns dash when lgroup ID is invalid.
608  */
609 static char *
610 lgrp2str(lgrp_id_t lgrp)
611 {
612         static char lgrp_buf[20];
613         char *str = lgrp_buf;
614
615         (void) sprintf(str, lgrp == LGRP_NONE ? "   -" : "%4d", lgrp);
616         return (str);
617 }
618
619 /*
620  * Parse address range specification for -A option.
621  * The address range may have the following forms:
622  *
623  * address
624  *      start and end is set to address
625  * address,
626  *      start is set to address, end is set to INVALID_ADDRESS
627  * ,address
628  *      start is set to 0, end is set to address
629  * address1,address2
630  *      start is set to address1, end is set to address2
631  *
632  */
633 static int
634 parse_addr_range(char *input_str, uintptr_t *start, uintptr_t *end)
635 {
636         char *startp = input_str;
637         char *endp = strchr(input_str, ',');
638         ulong_t s = (ulong_t)INVALID_ADDRESS;
639         ulong_t e = (ulong_t)INVALID_ADDRESS;
640
641         if (endp != NULL) {
642                 /*
643                  * Comma is present. If there is nothing after comma, the end
644                  * remains set at INVALID_ADDRESS. Otherwise it is set to the
645                  * value after comma.
646                  */
647                 *endp = '\0';
648                 endp++;
649
650                 if ((*endp != '\0') && sscanf(endp, "%lx", &e) != 1)
651                         return (1);
652         }
653
654         if (startp != NULL) {
655                 /*
656                  * Read the start address, if it is specified. If the address is
657                  * missing, start will be set to INVALID_ADDRESS.
658                  */
659                 if ((*startp != '\0') && sscanf(startp, "%lx", &s) != 1)
660                         return (1);
661         }
662
663         /* If there is no comma, end becomes equal to start */
664         if (endp == NULL)
665                 e = s;
666
667         /*
668          * ,end implies 0..end range
669          */
670         if (e != INVALID_ADDRESS && s == INVALID_ADDRESS)
671                 s = 0;
672
673         *start = (uintptr_t)s;
674         *end = (uintptr_t)e;
675
676         /* Return error if neither start nor end address were specified */
677         return (! (s != INVALID_ADDRESS || e != INVALID_ADDRESS));
678 }
679
680 /*
681  * Check whether any portion of [start, end] segment is within the
682  * [start_addr, end_addr] range.
683  *
684  * Return values:
685  *   0 - address is outside the range
686  *   1 - address is within the range
687  */
688 static int
689 address_in_range(uintptr_t start, uintptr_t end, size_t psz)
690 {
691         int rc = 1;
692
693         /*
694          *  Nothing to do if there is no address range specified with -A
695          */
696         if (start_addr != INVALID_ADDRESS || end_addr != INVALID_ADDRESS) {
697                 /* The segment end is below the range start */
698                 if ((start_addr != INVALID_ADDRESS) &&
699                     (end < P2ALIGN(start_addr, psz)))
700                         rc = 0;
701
702                 /* The segment start is above the range end */
703                 if ((end_addr != INVALID_ADDRESS) &&
704                     (start > P2ALIGN(end_addr + psz, psz)))
705                         rc = 0;
706         }
707         return (rc);
708 }
709
710
711 PG_FUNCTION_INFO_V1(sol_pmap_pid);
712
713 Datum
714 sol_pmap_pid(PG_FUNCTION_ARGS)
715 {
716     FuncCallContext     *funcctx;
717     int                  call_cntr;
718     int                  max_calls;
719     TupleDesc            tupdesc;
720     AttInMetadata       *attinmeta;
721
722     struct rlimit rlim;
723     struct stat64 statbuf;
724     int gcode;
725     int rc = 1;
726     int tries = 0;
727     int prr_flags = 0;
728     psinfo_t psinfo;
729     int mapfd;
730     int i;
731     int old_pr_pid;
732
733 #define SAVEPID(Pr) (old_pr_pid = *((int *)(Pr)))
734 #define FAKEPID(Pr, pid) (*((int *)(Pr)) = (pid))
735 #define RESTOREPID(Pr) (*((int *)(Pr)) = old_pr_pid)
736
737   /* stuff done only on the first call of the function */
738      if (SRF_IS_FIRSTCALL())
739      {
740         char         ***values = NULL;
741         MemoryContext   oldcontext;
742         char            cpid[10];
743
744         /* create a function context for cross-call persistence */
745         funcctx = SRF_FIRSTCALL_INIT();
746
747         /* switch to memory context appropriate for multiple function calls */
748         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
749
750         snprintf(cpid, sizeof(cpid)-1, "%d", PG_GETARG_INT32(0));
751         map_count = 0;
752         do {
753                 /*
754                  * Make sure we'll have enough file descriptors to handle a target
755                  * that has many many mappings.
756                  */
757                 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
758                         rlim.rlim_cur = rlim.rlim_max;
759                         (void) setrlimit(RLIMIT_NOFILE, &rlim);
760                         /* (void) enable_extended_FILE_stdio(-1, -1); */
761                 }
762        
763        
764                 if ((Pr = proc_arg_grab(cpid, PR_ARG_ANY,
765                                         PGRAB_RDONLY, &gcode)) == NULL) {
766                         ereport(WARNING,
767                                 (errmsg("cannot examine %s: %s\n",
768                                         cpid, Pgrab_error(gcode)),
769                                 errhint("process not running")));
770                         rc++;
771                         break;
772                 }
773
774                 SAVEPID(Pr);
775                 FAKEPID(Pr, atoi(cpid));
776                 procname = cpid;         /* for perr() */
777        
778                 addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8;
779                 size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8;
780                 (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
781                 proc_unctrl_psinfo(&psinfo);
782        
783                 if (Pstate(Pr) != PS_DEAD) {
784                         static char buf[32];
785                         (void) snprintf(buf, sizeof (buf),
786                             "/proc/%d/map", (int)psinfo.pr_pid);
787                         if ((mapfd = open(buf, O_RDONLY)) < 0) {
788                                 ereport(ERROR, (errmsg("cannot examine %s: lost control of process", cpid)));
789                                 rc++;
790                                 RESTOREPID(Pr);
791                                 Prelease(Pr, prr_flags);
792                                 break;
793                         }
794                 } else {
795                         mapfd = -1;
796                 }
797        
798         again:
799                 map_count = 0;
800        
801                 if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) {
802        
803                         /*
804                          * Since we're grabbing the process readonly, we need
805                          * to make sure the address space doesn't change during
806                          * execution.
807                          */
808                         if (Pstate(Pr) != PS_DEAD) {
809                                 if (tries++ == MAX_TRIES) {
810                                         RESTOREPID(Pr);
811                                         Prelease(Pr, prr_flags);
812                                         (void) close(mapfd);
813                                         ereport(ERROR, (errmsg("cannot examine %s: address space is changing", cpid)));
814                                         break;
815                                 }
816        
817                                 if (fstat64(mapfd, &statbuf) != 0) {
818                                         RESTOREPID(Pr);
819                                         Prelease(Pr, prr_flags);
820                                         (void) close(mapfd);
821                                         ereport(ERROR, (errmsg("cannot examine %s: lost control of process", cpid)));
822                                         break;
823                                 }
824                         }
825        
826                         nstacks = psinfo.pr_nlwp * 2;
827                         stacks = calloc(nstacks, sizeof (stacks[0]));
828                         if (stacks != NULL) {
829                                 int n = 0;
830                                 (void) Plwp_iter(Pr, getstack, &n);
831                                 qsort(stacks, nstacks, sizeof (stacks[0]),
832                                     cmpstacks);
833                         }
834        
835                         if (Pgetauxval(Pr, AT_BASE) != -1L &&
836                             Prd_agent(Pr) == NULL) {
837                                 ereport(WARNING,
838                                         (errmsg("librtld_db failed to initialize")));
839                         }
840                 }
841
842                 rc += xmapping_iter(Pr, gather_xmap, NULL, 0);
843        
844                 /*
845                  * Ensure mappings are consistent.
846                  */
847                 if (Pstate(Pr) != PS_DEAD) {
848                         struct stat64 newbuf;
849        
850                         if (fstat64(mapfd, &newbuf) != 0 ||
851                             memcmp(&newbuf.st_mtim, &statbuf.st_mtim,
852                             sizeof (newbuf.st_mtim)) != 0) {
853                                 if (stacks != NULL) {
854                                         free(stacks);
855                                         stacks = NULL;
856                                 }
857                                 goto again;
858                         }
859                 }
860
861                 values = (char ***) palloc(map_count * sizeof(char **));
862                 for(i=0; i<map_count; i++) {
863                         values[i] = (char **) palloc(SOL_MAP_DATA_CNT * sizeof(char *));
864                         memset(values[i], 0, SOL_MAP_DATA_CNT * sizeof(char *));
865                         look_xmap_nopgsz(values[i], &maps[i].md_xmap,
866                                 maps[i].md_objname,
867                                 maps[i].md_last,
868                                 maps[i].md_doswap);
869                 }
870
871                 RESTOREPID(Pr);
872                 Prelease(Pr, prr_flags);
873                 if (mapfd != -1)
874                         (void) close(mapfd);
875         } while(0);
876
877         /* values get stashed for the rest of the call */
878         funcctx->user_fctx = values;
879
880         /* total number of tuples to be returned */
881         funcctx->max_calls = map_count;
882
883         /* Build a tuple descriptor for our result type */
884         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
885             ereport(ERROR,
886                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
887                      errmsg("function returning record called in context "
888                             "that cannot accept type record")));
889
890         /*
891          * generate attribute metadata needed later to produce tuples from raw
892          * C strings
893          */
894         attinmeta = TupleDescGetAttInMetadata(tupdesc);
895         funcctx->attinmeta = attinmeta;
896
897         MemoryContextSwitchTo(oldcontext);
898     }
899
900     /* stuff done on every call of the function */
901     funcctx = SRF_PERCALL_SETUP();
902
903     call_cntr = funcctx->call_cntr;
904     max_calls = funcctx->max_calls;
905     attinmeta = funcctx->attinmeta;
906
907     if (max_calls != map_count) {
908       ereport(WARNING,
909                 (errmsg("pmap internet inconsistency"),
910                 errhint("Try again")));
911       SRF_RETURN_DONE(funcctx);
912     }
913
914     if (call_cntr < max_calls)     /* do when there is more left to send */
915     {
916         HeapTuple    tuple;
917         Datum        result;
918         char      ***values;
919         /*
920          * Prepare a values array for building the returned tuple.
921          * This should be an array of C strings which will
922          * be processed later by the type input functions.
923          */
924
925         values = (char ***)funcctx->user_fctx;
926         /* build a tuple */
927         tuple = BuildTupleFromCStrings(attinmeta, values[call_cntr]);
928
929         /* make the tuple into a datum */
930         result = HeapTupleGetDatum(tuple);
931
932         SRF_RETURN_NEXT(funcctx, result);
933     }
934     else    /* do when there is no more left */
935     {
936         SRF_RETURN_DONE(funcctx);
937     }
938 }
Note: See TracBrowser for help on using the browser.