opd_parse_proc.c

Go to the documentation of this file.
00001 
00012 #include "op_libiberty.h"
00013 
00014 #include "opd_parse_proc.h"
00015 #include "opd_proc.h"
00016 #include "opd_mapping.h"
00017 #include "opd_image.h"
00018 #include "opd_printf.h"
00019 
00020 #include "op_file.h"
00021 #include "op_fileio.h"
00022 
00023 #include <dirent.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 
00042 /* FIXME: handle (deleted) */
00043 static int opd_add_ascii_map(struct opd_proc * proc, char const * line,
00044                  char * const image_name)
00045 {
00046     unsigned long offset, start, end;
00047     struct opd_image * image;
00048     char const * cp = line;
00049 
00050     /* skip to protection field */
00051     while (*cp && *cp != ' ')
00052         cp++;
00053 
00054     /* handle rwx */
00055     if (!*cp || (!*(++cp)) || (!*(++cp)) || (*(++cp) != 'x'))
00056         return 0;
00057 
00058     /* get start and end from "40000000-4001f000" */
00059     if (sscanf(line, "%lx-%lx", &start, &end) != 2)
00060         return 0;
00061 
00062     /* "p " */
00063     cp += 2;
00064 
00065     /* read offset */
00066     if (sscanf(cp, "%lx", &offset) != 1)
00067         return 0;
00068 
00069     while (*cp && *cp != '/')
00070         cp++;
00071 
00072     if (!*cp)
00073         return 0;
00074 
00075     image = opd_get_image(cp, image_name, 0, proc->tid, proc->tgid);
00076     if (!image)
00077         return 0;
00078 
00079     opd_add_mapping(proc, image, start, offset, end);
00080 
00081     return 1;
00082 }
00083 
00084 
00092 static void opd_get_ascii_maps(struct opd_proc * proc)
00093 {
00094     FILE * fp;
00095     char mapsfile[20] = "/proc/";
00096     char * line;
00097     char exe_name[20];
00098     char * image_name;
00099     struct list_head * pos;
00100 
00101     snprintf(mapsfile + 6, 6, "%hu", proc->tid);
00102 
00103     strcpy(exe_name, mapsfile);
00104 
00105     strcat(mapsfile, "/maps");
00106 
00107     fp = op_try_open_file(mapsfile, "r");
00108     if (!fp)
00109         return;
00110 
00111     strcat(exe_name, "/exe");
00112     image_name = xmalloc(PATH_MAX);
00113     if (!realpath(exe_name, image_name))
00114         /* kernel thread are invalid symlink */
00115         strcpy(image_name, exe_name);
00116 
00117     verbprintf(vmisc, "image name %s for pid %u %u\n", image_name, proc->tid, proc->tgid);
00118 
00119     while (1) {
00120         line = op_get_line(fp);
00121         if (!line)
00122             break;
00123 
00124         opd_add_ascii_map(proc, line, image_name);
00125         free(line);
00126     }
00127 
00128     /* dae assume than the first map added is the primary image name, this
00129      * is always true at exec time but not for /proc/pid so restore
00130      * the primary image name
00131      */
00132     list_for_each(pos, &proc->maps) {
00133         struct opd_map * map = list_entry(pos, struct opd_map, next);
00134         if (!strcmp(map->image->name, image_name)) {
00135             if (pos != proc->maps.next) {
00136                 fprintf(stderr, "swap map for image %s from %s to %s\n", image_name, proc->name, map->image->name);
00137                 free((char *)proc->name);
00138                 proc->name = xstrdup(map->image->name);
00139             }
00140             break;
00141         }
00142     }
00143 
00144     if (list_empty(&proc->maps)) {
00145         /* we always need a valid proc->maps[0], we artificially give
00146          * a map of length zero so on no samples will never go to this
00147          * map. This is used only with --separate-samples and kernel
00148          * thread when adding vmlinux and module maps to proc->maps[]
00149          */
00150         /* FIXME: use the first field of /proc/pid/status as proc name
00151          * for now we use /proc/%pid/exe as name */
00152         struct opd_image * image = opd_get_image(image_name,
00153                                        image_name, 0, proc->tid, proc->tgid);
00154         if (image)
00155             opd_add_mapping(proc, image, 0, 0, 0);
00156     }
00157 
00158     if (image_name)
00159         free(image_name);
00160 
00161     op_close_file(fp);
00162 }
00163 
00164 
00165 static u32 read_tgid(u32 tid)
00166 {
00167     char status_file[30] = "/proc/";
00168     char * line;
00169     FILE * fp;
00170     u32 tgid;
00171 
00172     snprintf(status_file + 6, 6, "%hu", tid);
00173 
00174     strcat(status_file, "/status");
00175 
00176     fp = op_try_open_file(status_file, "r");
00177     if (!fp)
00178         return 0;
00179 
00180     while (1) {
00181         line = op_get_line(fp);
00182         if (!line)
00183             break;
00184 
00185         if (sscanf(line, "Tgid: %u", &tgid) == 1) {
00186             free(line);
00187             op_close_file(fp);
00188             return tgid;
00189         }
00190         free(line);
00191     }
00192 
00193     op_close_file(fp);
00194 
00195     return 0;
00196 }
00197 
00198 
00199 void opd_get_ascii_procs(void)
00200 {
00201     DIR * dir;
00202     struct dirent * dirent;
00203     struct opd_proc * proc;
00204     u32 pid;
00205 
00206     if (!(dir = opendir("/proc"))) {
00207         perror("oprofiled: /proc directory could not be opened. ");
00208         exit(EXIT_FAILURE);
00209     }
00210 
00211     while ((dirent = readdir(dir))) {
00212         if (sscanf(dirent->d_name, "%u", &pid) == 1) {
00213             u32 tgid = read_tgid(pid);
00214             verbprintf(vmisc, "ASCII added %u %u\n", pid, tgid);
00215             proc = opd_get_proc(pid, tgid);
00216             if (!proc)
00217                 proc = opd_new_proc(pid, tgid);
00218             opd_get_ascii_maps(proc);
00219         }
00220     }
00221 
00222     closedir(dir);
00223 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1