e28bd29d28164c113d6a21339974924f103f4beb
[platform/upstream/oprofile.git] / opjitconv / opjitconv.c
1 /**
2  * @file opjitconv.c
3  * Convert a jit dump file to an ELF file
4  *
5  * @remark Copyright 2007 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author Jens Wilke
9  * @Modifications Maynard Johnson
10  * @Modifications Daniel Hansel
11  * @Modifications Gisle Dankel
12  *
13  * Copyright IBM Corporation 2007
14  *
15  */
16
17 #include "opjitconv.h"
18 #include "op_file.h"
19 #include "op_libiberty.h"
20
21 #include <getopt.h>
22 #include <dirent.h>
23 #include <fnmatch.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <assert.h>
28 #include <pwd.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <wait.h>
37 #include <sys/file.h>
38
39 /*
40  * list head.  The linked list is used during parsing (parse_all) to
41  * hold all jitentry elements. After parsing, the program works on the
42  * array structures (entries_symbols_ascending, entries_address_ascending)
43  * and the linked list is not used any more.
44  */
45 struct jitentry * jitentry_list = NULL;
46 struct jitentry_debug_line * jitentry_debug_line_list = NULL;
47
48 /* Global variable for asymbols so we can free the storage later. */
49 asymbol ** syms;
50
51 /* jit dump header information */
52 enum bfd_architecture dump_bfd_arch;
53 int dump_bfd_mach;
54 char const * dump_bfd_target_name;
55
56 /* user information for special user 'oprofile' */
57 struct passwd * pw_oprofile;
58
59 char sys_cmd_buffer[PATH_MAX + 1];
60
61 /* the bfd handle of the ELF file we write */
62 bfd * cur_bfd;
63
64 /* count of jitentries in the list */
65 u32 entry_count;
66 /* maximul space in the entry arrays, needed to add entries */
67 u32 max_entry_count;
68 /* array pointing to all jit entries, sorted by symbol names */
69 struct jitentry ** entries_symbols_ascending;
70 /* array pointing to all jit entries sorted by address */
71 struct jitentry ** entries_address_ascending;
72
73 /* debug flag, print some information */
74 int debug;
75 /* indicates opjitconv invoked by non-root user via operf */
76 int non_root;
77 /* indicates we should delete jitdump files owned by the user */
78 int delete_jitdumps;
79 /* Session directory where sample data is stored */
80 char * session_dir;
81
82 static struct option long_options [] = {
83                                         { "session-dir", required_argument, NULL, 's'},
84                                         { "debug", no_argument, NULL, 'd'},
85                                         { "delete-jitdumps", no_argument, NULL, 'j'},
86                                         { "non-root", no_argument, NULL, 'n'},
87                                         { "help", no_argument, NULL, 'h'},
88                                         { NULL, 9, NULL, 0}
89 };
90 const char * short_options = "s:djnh";
91
92 LIST_HEAD(jitdump_deletion_candidates);
93
94 /*
95  *  Front-end processing from this point to end of the source.
96  *    From main(), the general flow is as follows:
97  *      1. Find all anonymous samples directories
98  *      2. Find all JIT dump files
99  *      3. For each JIT dump file:
100  *        3.1 Find matching anon samples dir (from list retrieved in step 1)
101  *        3.2 mmap the JIT dump file
102  *        3.3 Call op_jit_convert to create ELF file if necessary
103  */
104
105 /* Callback function used for get_matching_pathnames() call to obtain
106  * matching path names.
107  */
108 static void get_pathname(char const * pathname, void * name_list)
109 {
110         struct list_head * names = (struct list_head *) name_list;
111         struct pathname * pn = xmalloc(sizeof(struct pathname));
112         pn->name = xstrdup(pathname);
113         list_add(&pn->neighbor, names);
114 }
115
116 static void delete_pathname(struct pathname * pname)
117 {
118         free(pname->name);
119         list_del(&pname->neighbor);
120         free(pname);
121 }
122
123
124 static void delete_path_names_list(struct list_head * list)
125 {
126         struct list_head * pos1, * pos2;
127         list_for_each_safe(pos1, pos2, list) {
128                 struct pathname * pname = list_entry(pos1, struct pathname,
129                                                      neighbor);
130                 delete_pathname(pname);
131         }
132 }
133
134 static int mmap_jitdump(char const * dumpfile,
135         struct op_jitdump_info * file_info)
136 {
137         int rc = OP_JIT_CONV_OK;
138         int dumpfd;
139
140         dumpfd = open(dumpfile, O_RDONLY);
141         if (dumpfd < 0) {
142                 if (errno == ENOENT)
143                         rc = OP_JIT_CONV_NO_DUMPFILE;
144                 else
145                         rc = OP_JIT_CONV_FAIL;
146                 goto out;
147         }
148         rc = fstat(dumpfd, &file_info->dmp_file_stat);
149         if (rc < 0) {
150                 perror("opjitconv:fstat on dumpfile");
151                 rc = OP_JIT_CONV_FAIL;
152                 goto out;
153         }
154         file_info->dmp_file = mmap(0, file_info->dmp_file_stat.st_size,
155                                    PROT_READ, MAP_PRIVATE, dumpfd, 0);
156         if (file_info->dmp_file == MAP_FAILED) {
157                 perror("opjitconv:mmap\n");
158                 rc = OP_JIT_CONV_FAIL;
159         }
160 out:
161         if (dumpfd != -1)
162                 close(dumpfd);
163         return rc;
164 }
165
166 static char const * find_anon_dir_match(struct list_head * anon_dirs,
167                                         char const * proc_id)
168 {
169         struct list_head * pos;
170         /* Current PID_MAX_LIMIT (as defined in include/linux/threads.h) is
171          *         4 x 4 x 1024 * 1024 (for 64-bit kernels)
172          * So need to have space for 7 chars for proc_id.
173          */
174         char match_filter[12];
175         snprintf(match_filter, 12, "*/%s.*", proc_id);
176         list_for_each(pos, anon_dirs) {
177                 struct pathname * anon_dir =
178                         list_entry(pos, struct pathname, neighbor);
179                 if (!fnmatch(match_filter, anon_dir->name, 0))
180                         return anon_dir->name;
181         }
182         return NULL;
183 }
184
185 int change_owner(char * path)
186 {
187         int rc = OP_JIT_CONV_OK;
188         int fd;
189         
190         if (non_root)
191                 return rc;
192         fd = open(path, 0);
193         if (fd < 0) {
194                 printf("opjitconv: File cannot be opened for changing ownership.\n");
195                 rc = OP_JIT_CONV_FAIL;
196                 goto out;
197         }
198         if (fchown(fd, pw_oprofile->pw_uid, pw_oprofile->pw_gid) != 0) {
199                 printf("opjitconv: Changing ownership failed (%s).\n", strerror(errno));
200                 close(fd);
201                 rc = OP_JIT_CONV_FAIL;
202                 goto out;
203         }
204         close(fd);
205
206 out:
207         return rc;
208 }
209
210 /* Copies the given file to the temporary working directory and sets ownership
211  * to 'oprofile:oprofile'.
212  */
213 int copy_dumpfile(char const * dumpfile, char * tmp_dumpfile)
214 {
215 #define OP_JITCONV_USECS_TO_WAIT 1000
216         int file_locked = 0;
217         unsigned int usecs_waited = 0;
218         int rc = OP_JIT_CONV_OK;
219         int fd = open(dumpfile, O_RDONLY);
220         if (fd < 0) {
221                 perror("opjitconv failed to open JIT dumpfile");
222                 return OP_JIT_CONV_FAIL;
223         }
224 again:
225         // Need OS-level file locking here since opagent may still be writing to the file.
226         rc = flock(fd, LOCK_EX | LOCK_NB);
227         if (rc) {
228                 if (usecs_waited < OP_JITCONV_USECS_TO_WAIT) {
229                         usleep(100);
230                         usecs_waited += 100;
231                         goto again;
232                 } else {
233                         printf("opjitconv: Unable to obtain lock on %s.\n", dumpfile);
234                         rc = OP_JIT_CONV_FAIL;
235                         goto out;
236                 }
237         }
238         file_locked = 1;
239         sprintf(sys_cmd_buffer, "/bin/cp -p %s %s", dumpfile, tmp_dumpfile);
240         if (system(sys_cmd_buffer) != 0) {
241                 printf("opjitconv: Calling system() to copy files failed.\n");
242                 rc = OP_JIT_CONV_FAIL;
243                 goto out;
244         }
245
246         if (change_owner(tmp_dumpfile) != 0) {
247                 printf("opjitconv: Changing ownership of temporary dump file failed.\n");
248                 rc = OP_JIT_CONV_FAIL;
249                 goto out;
250         }
251         
252 out:
253 #undef OP_JITCONV_USECS_TO_WAIT
254         close(fd);
255         if (file_locked)
256                 flock(fd, LOCK_UN);
257
258         return rc;
259 }
260
261 /* Copies the created ELF file located in the temporary working directory to the
262  * final destination (i.e. given ELF file name) and sets ownership to the
263  * current user.
264  */
265 int copy_elffile(char * elf_file, char * tmp_elffile)
266 {
267         int rc = OP_JIT_CONV_OK;
268         int fd;
269
270         sprintf(sys_cmd_buffer, "/bin/cp -p %s %s", tmp_elffile, elf_file);
271         if (system(sys_cmd_buffer) != 0) {
272                 printf("opjitconv: Calling system() to copy files failed.\n");
273                 rc = OP_JIT_CONV_FAIL;
274                 goto out;
275         }
276
277         fd = open(elf_file, 0);
278         if (fd < 0) {
279                 printf("opjitconv: File cannot be opened for changing ownership.\n");
280                 rc = OP_JIT_CONV_FAIL;
281                 goto out;
282         }
283         if (fchown(fd, getuid(), getgid()) != 0) {
284                 printf("opjitconv: Changing ownership failed (%s).\n", strerror(errno));
285                 close(fd);
286                 rc = OP_JIT_CONV_FAIL;
287                 goto out;
288         }
289         close(fd);
290         
291 out:
292         return rc;
293 }
294
295 /* Look for an anonymous samples directory that matches the process ID
296  * given by the passed JIT dmp_pathname.  If none is found, it's an error
297  * since by agreement, all JIT dump files should be removed every time
298  * the user does --reset.  If we do find the matching samples directory,
299  * we create an ELF file (<proc_id>.jo) and place it in that directory.
300  */
301 static int process_jit_dumpfile(char const * dmp_pathname,
302                                 struct list_head * anon_sample_dirs,
303                                 unsigned long long start_time,
304                                 unsigned long long end_time,
305                                 char * tmp_conv_dir)
306 {
307         int result_dir_length, proc_id_length;
308         int rc = OP_JIT_CONV_OK;
309         int jofd;
310         struct stat file_stat;
311         time_t dumpfile_modtime;
312         struct op_jitdump_info dmp_info;
313         char * elf_file = NULL;
314         char * proc_id = NULL;
315         char const * anon_dir;
316         char const * dumpfilename = rindex(dmp_pathname, '/');
317         /* temporary copy of dump file created for conversion step */
318         char * tmp_dumpfile;
319         /* temporary ELF file created during conversion step */
320         char * tmp_elffile;
321         
322         verbprintf(debug, "Processing dumpfile %s\n", dmp_pathname);
323         
324         /* Check if the dump file is a symbolic link.
325          * We should not trust symbolic links because we only produce normal dump
326          * files (no links).
327          */
328         if (lstat(dmp_pathname, &file_stat) == -1) {
329                 printf("opjitconv: lstat for dumpfile failed (%s).\n", strerror(errno));
330                 rc = OP_JIT_CONV_FAIL;
331                 goto out;
332         }
333         if (S_ISLNK(file_stat.st_mode)) {
334                 printf("opjitconv: dumpfile path is corrupt (symbolic links not allowed).\n");
335                 rc = OP_JIT_CONV_FAIL;
336                 goto out;
337         }
338         
339         if (dumpfilename) {
340                 size_t tmp_conv_dir_length = strlen(tmp_conv_dir);
341                 char const * dot_dump = rindex(++dumpfilename, '.');
342                 if (!dot_dump)
343                         goto chk_proc_id;
344                 proc_id_length = dot_dump - dumpfilename;
345                 proc_id = xmalloc(proc_id_length + 1);
346                 memcpy(proc_id, dumpfilename, proc_id_length);
347                 proc_id[proc_id_length] = '\0';
348                 verbprintf(debug, "Found JIT dumpfile for process %s\n",
349                            proc_id);
350
351                 tmp_dumpfile = xmalloc(tmp_conv_dir_length + 1 + strlen(dumpfilename) + 1);
352                 strncpy(tmp_dumpfile, tmp_conv_dir, tmp_conv_dir_length);
353                 tmp_dumpfile[tmp_conv_dir_length] = '\0';
354                 strcat(tmp_dumpfile, "/");
355                 strcat(tmp_dumpfile, dumpfilename);
356         }
357 chk_proc_id:
358         if (!proc_id) {
359                 printf("opjitconv: dumpfile path is corrupt.\n");
360                 rc = OP_JIT_CONV_FAIL;
361                 goto out;
362         }
363         if (!(anon_dir = find_anon_dir_match(anon_sample_dirs, proc_id))) {
364                 /* When profiling with operf, opjitconv will remove old jitdump
365                  * files (see _cleanup_jitdumps() for details).  But this cleanup
366                  * strategy makes it quite likely that opjitconv will sometimes find
367                  * jitdump files that are not owned by the current user or are in use
368                  * by other operf users, thus, the current profile data would not have
369                  * matching anon samples for such jitdump files.
370                  */
371                 verbprintf(debug, "Informational message: No matching anon samples for %s\n",
372                            dmp_pathname);
373                 rc = OP_JIT_CONV_NO_MATCHING_ANON_SAMPLES;
374                 goto free_res1;
375         }
376         
377         if (copy_dumpfile(dmp_pathname, tmp_dumpfile) != OP_JIT_CONV_OK)
378                 goto free_res1;
379         
380         if ((rc = mmap_jitdump(tmp_dumpfile, &dmp_info)) == OP_JIT_CONV_OK) {
381                 char * anon_path_seg = rindex(anon_dir, '/');
382                 if (!anon_path_seg) {
383                         printf("opjitconv: Bad path for anon sample: %s\n",
384                                anon_dir);
385                         rc = OP_JIT_CONV_FAIL;
386                         goto free_res2;
387                 }
388                 result_dir_length = ++anon_path_seg - anon_dir;
389                 /* create final ELF file name */
390                 elf_file = xmalloc(result_dir_length +
391                                    strlen(proc_id) + strlen(".jo") + 1);
392                 strncpy(elf_file, anon_dir, result_dir_length);
393                 elf_file[result_dir_length] = '\0';
394                 strcat(elf_file, proc_id);
395                 strcat(elf_file, ".jo");
396                 /* create temporary ELF file name */
397                 tmp_elffile = xmalloc(strlen(tmp_conv_dir) + 1 +
398                                    strlen(proc_id) + strlen(".jo") + 1);
399                 strncpy(tmp_elffile, tmp_conv_dir, strlen(tmp_conv_dir));
400                 tmp_elffile[strlen(tmp_conv_dir)] = '\0';
401                 strcat(tmp_elffile, "/");
402                 strcat(tmp_elffile, proc_id);
403                 strcat(tmp_elffile, ".jo");
404
405                 // Check if final ELF file exists already
406                 jofd = open(elf_file, O_RDONLY);
407                 if (jofd < 0)
408                         goto create_elf;
409                 rc = fstat(jofd, &file_stat);
410                 close(jofd);
411                 if (rc < 0) {
412                         perror("opjitconv:fstat on .jo file");
413                         rc = OP_JIT_CONV_FAIL;
414                         goto free_res3;
415                 }
416                 if (dmp_info.dmp_file_stat.st_mtime >
417                     dmp_info.dmp_file_stat.st_ctime)
418                         dumpfile_modtime = dmp_info.dmp_file_stat.st_mtime;
419                 else
420                         dumpfile_modtime = dmp_info.dmp_file_stat.st_ctime;
421
422                 /* Final ELF file already exists, so if dumpfile has not been
423                  * modified since the ELF file's mod time, we don't need to
424                  * do ELF creation again.
425                  */
426                 if (!(file_stat.st_ctime < dumpfile_modtime ||
427                     file_stat.st_mtime < dumpfile_modtime)) {
428                         rc = OP_JIT_CONV_ALREADY_DONE;
429                         goto free_res3; 
430                 }
431
432         create_elf:
433                 verbprintf(debug, "Converting %s to %s\n", dmp_pathname,
434                            elf_file);
435                 /* Set eGID of the special user 'oprofile'. */
436                 if (!non_root && setegid(pw_oprofile->pw_gid) != 0) {
437                         perror("opjitconv: setegid to special user failed");
438                         rc = OP_JIT_CONV_FAIL;
439                         goto free_res3;
440                 }
441                 /* Set eUID of the special user 'oprofile'. */
442                 if (!non_root && seteuid(pw_oprofile->pw_uid) != 0) {
443                         perror("opjitconv: seteuid to special user failed");
444                         rc = OP_JIT_CONV_FAIL;
445                         goto free_res3;
446                 }
447                 /* Convert the dump file as the special user 'oprofile'. */
448                 rc = op_jit_convert(&dmp_info, tmp_elffile, start_time, end_time);
449                 if (rc < 0)
450                         goto free_res3;
451
452                 /* Set eUID back to the original user. */
453                 if (!non_root && seteuid(getuid()) != 0) {
454                         perror("opjitconv: seteuid to original user failed");
455                         rc = OP_JIT_CONV_FAIL;
456                         goto free_res3;
457                 }
458                 /* Set eGID back to the original user. */
459                 if (!non_root && setegid(getgid()) != 0) {
460                         perror("opjitconv: setegid to original user failed");
461                         rc = OP_JIT_CONV_FAIL;
462                         goto free_res3;
463                 }
464                 rc = copy_elffile(elf_file, tmp_elffile);
465         free_res3:
466                 free(elf_file);
467                 free(tmp_elffile);
468         free_res2:
469                 munmap(dmp_info.dmp_file, dmp_info.dmp_file_stat.st_size);
470         }
471 free_res1:
472         free(proc_id);
473         free(tmp_dumpfile);
474 out:
475         return rc;
476 }
477
478 /* If non-NULL value is returned, caller is responsible for freeing memory.*/
479 static char * get_procid_from_dirname(char * dirname)
480 {
481         char * ret = NULL;
482         if (dirname) {
483                 char * proc_id;
484                 int proc_id_length;
485                 char * fname = rindex(dirname, '/');
486                 char const * dot = index(++fname, '.');
487                 if (!dot)
488                         goto out;
489                 proc_id_length = dot - fname;
490                 proc_id = xmalloc(proc_id_length + 1);
491                 memcpy(proc_id, fname, proc_id_length);
492                 proc_id[proc_id_length] = '\0';
493                 ret = proc_id;
494         }
495 out:
496         return ret;
497 }
498 static void filter_anon_samples_list(struct list_head * anon_dirs)
499 {
500         struct procid {
501                 struct procid * next;
502                 char * pid;
503         };
504         struct procid * pid_list = NULL;
505         struct procid * id, * nxt;
506         struct list_head * pos1, * pos2;
507         list_for_each_safe(pos1, pos2, anon_dirs) {
508                 struct pathname * pname = list_entry(pos1, struct pathname,
509                                                      neighbor);
510                 char * proc_id = get_procid_from_dirname(pname->name);
511                 if (proc_id) {
512                         int found = 0;
513                         for (id = pid_list; id != NULL; id = id->next) {
514                                 if (!strcmp(id->pid, proc_id)) {
515                                         /* Already have an entry for this 
516                                          * process ID, so delete this entry
517                                          * from anon_dirs.
518                                          */
519                                         free(pname->name);
520                                         list_del(&pname->neighbor);
521                                         free(pname);
522                                         found = 1;
523                                 }
524                         }
525                         if (!found) {
526                                 struct procid * this_proc = 
527                                         xmalloc(sizeof(struct procid));
528                                 this_proc->pid = proc_id;
529                                 this_proc->next = pid_list;
530                                 pid_list = this_proc;
531                         }
532                 } else {
533                         printf("Unexpected result in processing anon sample"
534                                " directory\n");
535                 }
536         }
537         for (id = pid_list; id; id = nxt) {
538                 free(id->pid);
539                 nxt = id->next;
540                 free(id);
541         }
542 }
543
544
545 static void _add_jitdumps_to_deletion_list(void * all_jitdumps, char const * jitdump_dir )
546 {
547         struct list_head * jd_fnames = (struct list_head *) all_jitdumps;
548         struct list_head * pos1, *pos2;
549         size_t dir_len = strlen(jitdump_dir);
550
551         list_for_each_safe(pos1, pos2, jd_fnames) {
552                 struct pathname * dmpfile =
553                                 list_entry(pos1, struct pathname, neighbor);
554                 struct stat mystat;
555                 char dmpfile_pathname[dir_len + 20];
556                 int fd;
557                 memset(dmpfile_pathname, '\0', dir_len + 20);
558                 strcpy(dmpfile_pathname, jitdump_dir);
559                 strcat(dmpfile_pathname,dmpfile->name);
560                 fd = open(dmpfile_pathname, O_RDONLY);
561                 if (fd < 0) {
562                         // Non-fatal error, so just display debug message and continue
563                         verbprintf(debug, "opjitconv: cannot open jitdump file %s\n",
564                                    dmpfile_pathname);
565                         continue;
566                 }
567                 if (fstat(fd, &mystat) < 0) {
568                         // Non-fatal error, so just display debug message and continue
569                         verbprintf(debug, "opjitconv: cannot fstat jitdump file");
570                         close(fd);
571                         continue;
572                 }
573                 close(fd);
574                 if (!non_root || geteuid() == mystat.st_uid) {
575                         struct jitdump_deletion_candidate * jdc =
576                                         xmalloc(sizeof(struct jitdump_deletion_candidate));
577                         jdc->name = xstrdup(dmpfile->name);
578                         list_add(&jdc->neighbor, &jitdump_deletion_candidates);
579                 }
580         }
581 }
582
583 static int op_process_jit_dumpfiles(char const * session_dir,
584         unsigned long long start_time, unsigned long long end_time)
585 {
586         struct list_head * pos1, * pos2;
587         int rc = OP_JIT_CONV_OK;
588         char jitdumpfile[PATH_MAX + 1];
589         char oprofile_tmp_template[PATH_MAX + 1];
590         char const * jitdump_dir = "/tmp/.oprofile/jitdump/";
591
592         LIST_HEAD(jd_fnames);
593         char const * anon_dir_filter = "*/{dep}/{anon:anon}/[0-9]*.*";
594         LIST_HEAD(anon_dnames);
595         char const * samples_subdir = "/samples/current";
596         int samples_dir_len = strlen(session_dir) + strlen(samples_subdir);
597         char * samples_dir;
598         /* temporary working directory for dump file conversion step */
599         char * tmp_conv_dir = NULL;
600
601         if (non_root)
602                 sprintf(oprofile_tmp_template, "%s/tmp", session_dir);
603         else
604                 strcpy(oprofile_tmp_template, "/tmp/oprofile.XXXXXX");
605
606         /* Create a temporary working directory used for the conversion step.
607          */
608         if (non_root) {
609                 sprintf(sys_cmd_buffer, "/bin/rm -rf %s", oprofile_tmp_template);
610                 if (system(sys_cmd_buffer) != 0) {
611                         printf("opjitconv: Removing temporary working directory %s failed.\n",
612                                oprofile_tmp_template);
613                         rc = OP_JIT_CONV_TMPDIR_NOT_REMOVED;
614                 } else {
615                         if (!mkdir(oprofile_tmp_template, S_IRWXU | S_IRWXG ))
616                                 tmp_conv_dir = oprofile_tmp_template;
617                 }
618         } else {
619                 tmp_conv_dir = mkdtemp(oprofile_tmp_template);
620         }
621
622         if (tmp_conv_dir == NULL) {
623                 printf("opjitconv: Temporary working directory %s cannot be created.\n",
624                        oprofile_tmp_template);
625                 perror("Exiting due to error");
626                 rc = OP_JIT_CONV_FAIL;
627                 goto out;
628         }
629
630
631         errno = 0;
632         if ((rc = get_matching_pathnames(&jd_fnames, get_pathname,
633                 jitdump_dir, "*.dump", NO_RECURSION)) < 0
634                         || list_empty(&jd_fnames)) {
635                 if (errno) {
636                         if (errno != ENOENT) {
637                                 char msg[PATH_MAX];
638                                 strcpy(msg, "opjitconv: fatal error trying to find JIT dump files in ");
639                                 strcat(msg, jitdump_dir);
640                                 perror(msg);
641                                 rc = OP_JIT_CONV_FAIL;
642                         } else {
643                                 verbprintf(debug, "opjitconv: Non-fatal error trying to find JIT dump files in %s: %s\n",
644                                            jitdump_dir, strerror(errno));
645                                 rc = OP_JIT_CONV_NO_DUMPFILE;
646                         }
647                 }
648                 goto rm_tmp;
649         }
650
651         if (delete_jitdumps)
652                 _add_jitdumps_to_deletion_list(&jd_fnames, jitdump_dir);
653
654         /* Get user information (i.e. UID and GID) for special user 'oprofile'.
655          */
656         if (non_root) {
657                 pw_oprofile = NULL;
658         } else {
659                 pw_oprofile = getpwnam("oprofile");
660                 if (pw_oprofile == NULL) {
661                         printf("opjitconv: User information for special user oprofile cannot be found.\n");
662                         rc = OP_JIT_CONV_FAIL;
663                         goto rm_tmp;
664                 }
665         }
666
667         /* Change ownership of the temporary working directory to prevent other users
668          * to attack conversion process.
669          */
670         if (change_owner(tmp_conv_dir) != 0) {
671                 printf("opjitconv: Changing ownership of temporary directory failed.\n");
672                 rc = OP_JIT_CONV_FAIL;
673                 goto rm_tmp;
674         }
675         
676         samples_dir = xmalloc(samples_dir_len + 1);
677         sprintf(samples_dir, "%s%s", session_dir, samples_subdir);
678         if (get_matching_pathnames(&anon_dnames, get_pathname,
679                                     samples_dir, anon_dir_filter,
680                                     MATCH_DIR_ONLY_RECURSION) < 0
681             || list_empty(&anon_dnames)) {
682                 rc = OP_JIT_CONV_NO_ANON_SAMPLES;
683                 goto rm_tmp;
684         }
685         /* When using get_matching_pathnames to find anon samples,
686          * the list that's returned may contain multiple entries for
687          * one or more processes; e.g.,
688          *    6868.0x100000.0x103000
689          *    6868.0xdfe77000.0xdec40000
690          *    7012.0x100000.0x103000
691          *    7012.0xdfe77000.0xdec40000
692          *
693          * So we must filter the list so there's only one entry per
694          * process.
695          */
696         filter_anon_samples_list(&anon_dnames);
697
698         /* get_matching_pathnames returns only filename segment when
699          * NO_RECURSION is passed, so below, we add back the JIT
700          * dump directory path to the name.
701          */
702         list_for_each_safe(pos1, pos2, &jd_fnames) {
703                 struct pathname * dmpfile =
704                         list_entry(pos1, struct pathname, neighbor);
705                 strncpy(jitdumpfile, jitdump_dir, PATH_MAX);
706                 strncat(jitdumpfile, dmpfile->name, PATH_MAX);
707                 rc = process_jit_dumpfile(jitdumpfile, &anon_dnames,
708                                           start_time, end_time, tmp_conv_dir);
709                 if (rc == OP_JIT_CONV_FAIL) {
710                         verbprintf(debug, "JIT convert error %d\n", rc);
711                         goto rm_tmp;
712                 }
713                 delete_pathname(dmpfile);
714         }
715         delete_path_names_list(&anon_dnames);
716         
717 rm_tmp:
718         /* Delete temporary working directory with all its files
719          * (i.e. dump and ELF file).
720          */
721         sprintf(sys_cmd_buffer, "/bin/rm -rf '%s'", tmp_conv_dir);
722         if (system(sys_cmd_buffer) != 0) {
723                 printf("opjitconv: Removing temporary working directory failed.\n");
724                 rc = OP_JIT_CONV_TMPDIR_NOT_REMOVED;
725         }
726         
727 out:
728         return rc;
729 }
730
731 static void _cleanup_jitdumps(void)
732 {
733         struct list_head * pos1, *pos2;
734         char const * jitdump_dir = "/tmp/.oprofile/jitdump/";
735         size_t dir_len = strlen(jitdump_dir);
736         char dmpfile_pathname[dir_len + 20];
737         char proc_fd_dir[PATH_MAX];
738
739         if (!delete_jitdumps)
740                 return;
741
742         /* The delete_jitdumps flag tells us to try to delete the jitdump files we found
743          * that belong to this user.  Only operf should pass the --delete-jitdumps
744          * argument to opjitconv since legacy oprofile uses opcontrol to delete old
745          * jitdump files.
746          *
747          * The code below will only delete jitdump files that are not currently
748          * being used by another process.
749          */
750         list_for_each_safe(pos1, pos2, &jitdump_deletion_candidates) {
751                 DIR * dir;
752                 struct dirent * dirent;
753                 int pid;
754                 size_t dmpfile_name_len;
755                 int do_not_delete = 0;
756                 struct jitdump_deletion_candidate * cand = list_entry(pos1,
757                                                                       struct jitdump_deletion_candidate,
758                                                                       neighbor);
759                 memset(dmpfile_pathname, '\0', dir_len + 20);
760                 memset(proc_fd_dir, '\0', PATH_MAX);
761
762                 if ((sscanf(cand->name, "%d", &pid)) != 1) {
763                         verbprintf(debug, "Cannot get process id from jitdump file %s\n",
764                                    cand->name);
765                         continue;
766                 }
767
768                 strcpy(dmpfile_pathname, jitdump_dir);
769                 strcat(dmpfile_pathname, cand->name);
770                 dmpfile_name_len = strlen(dmpfile_pathname);
771
772                 sprintf(proc_fd_dir, "/proc/%d/fd/", pid);
773                 if ((dir = opendir(proc_fd_dir))) {
774                         size_t proc_fd_dir_len = strlen(proc_fd_dir);
775                         while ((dirent = readdir(dir))) {
776                                 if (dirent->d_type == DT_LNK) {
777                                         char buf[1024];
778                                         char fname[1024];
779                                         memset(buf, '\0', 1024);
780                                         memset(fname, '\0', 1024);
781                                         memset(buf, '\0', 1024);
782                                         strcpy(fname, proc_fd_dir);
783                                         strncat(fname, dirent->d_name, 1023 - proc_fd_dir_len);
784                                         if (readlink(fname, buf, 1023) > 0) {
785                                                 verbprintf(debug, "readlink found for %s\n", buf);
786                                                 if (strncmp(buf, dmpfile_pathname,
787                                                             dmpfile_name_len) == 0) {
788                                                         do_not_delete = 1;
789                                                         break;
790                                                 }
791                                         }
792                                 }
793                         }
794                         closedir(dir);
795                 }
796                 if (!do_not_delete) {
797                         if (remove(dmpfile_pathname))
798                                 verbprintf(debug, "Unable to delete %s: %s\n", dmpfile_pathname,
799                                            strerror(errno));
800                 }
801         }
802         list_for_each_safe(pos1, pos2, &jitdump_deletion_candidates) {
803                 struct jitdump_deletion_candidate * pname = list_entry(pos1,
804                                                                        struct jitdump_deletion_candidate,
805                                                                        neighbor);
806                 free(pname->name);
807                 list_del(&pname->neighbor);
808                 free(pname);
809         }
810
811 }
812
813 static void __print_usage(void)
814 {
815         fprintf(stderr, "usage: opjitconv [--debug | --non-root | --delete-jitdumps ] --session-dir=<dir> <starttime> <endtime>\n");
816 }
817
818 static int _process_args(int argc, char * const argv[])
819 {
820         int keep_trying = 1;
821         int idx_of_non_options = 0;
822         char * prev_env = getenv("POSIXLY_CORRECT");
823         setenv("POSIXLY_CORRECT", "1", 0);
824         while (keep_trying) {
825                 int option_idx = 0;
826                 int c = getopt_long(argc, argv, short_options, long_options, &option_idx);
827                 switch (c) {
828                 case -1:
829                         if (optind != argc) {
830                                 idx_of_non_options = optind;
831                         }
832                         keep_trying = 0;
833                         break;
834                 case '?':
835                         printf("non-option detected at optind %d\n", optind);
836                         keep_trying = 0;
837                         idx_of_non_options = -1;
838                         break;
839                 case 's':
840                         session_dir = optarg;
841                         break;
842                 case 'd':
843                         debug = 1;
844                         break;
845                 case 'n':
846                         non_root = 1;
847                         break;
848                 case 'j':
849                         delete_jitdumps = 1;
850                         break;
851                 case 'h':
852                         break;
853                 default:
854                         break;
855                 }
856         }
857
858         if (prev_env == NULL)
859                 unsetenv("POSIXLY_CORRECT");
860
861         return idx_of_non_options;
862 }
863
864 int main(int argc, char * const argv[])
865 {
866         unsigned long long start_time, end_time;
867         struct stat filestat;
868         int non_options_idx, rc = 0;
869         size_t sessdir_len = 0;
870
871         debug = 0;
872         non_root = 0;
873         delete_jitdumps = 0;
874         session_dir = NULL;
875         non_options_idx = _process_args(argc, argv);
876         // We need the session_dir and two non-option values passed -- starttime and endtime.
877         if (!session_dir || (non_options_idx != argc - 2)) {
878                 __print_usage();
879                 fflush(stdout);
880                 rc = EXIT_FAILURE;
881                 goto out;
882         }
883
884         /*
885          * Check for a maximum of 4096 bytes (Linux path name length limit) minus 16 bytes
886          * (to be used later for appending samples sub directory) minus 1 (for terminator).
887          * Integer overflows according to the session dir parameter (user controlled)
888          * are not possible anymore.
889          */
890         if ((sessdir_len = strlen(session_dir)) >= (PATH_MAX - 17)) {
891                 printf("opjitconv: Path name length limit exceeded for session directory\n");
892                 rc = EXIT_FAILURE;
893                 goto out;
894         }
895
896         if (stat(session_dir, &filestat)) {
897                 perror("stat operation on passed session-dir failed");
898                 rc = EXIT_FAILURE;
899                 goto out;
900         }
901         if (!S_ISDIR(filestat.st_mode)) {
902                 printf("Passed session-dir %s is not a directory\n", session_dir);
903                 rc = EXIT_FAILURE;
904                 goto out;
905         }
906
907         start_time = atol(argv[non_options_idx++]);
908         end_time = atol(argv[non_options_idx]);
909
910         if (start_time > end_time) {
911                 rc = EXIT_FAILURE;
912                 goto out;
913         }
914         verbprintf(debug, "start time/end time is %llu/%llu\n",
915                    start_time, end_time);
916         rc = op_process_jit_dumpfiles(session_dir, start_time, end_time);
917         if (delete_jitdumps)
918                 _cleanup_jitdumps();
919
920         if (rc > OP_JIT_CONV_OK) {
921                 verbprintf(debug, "opjitconv: Ending with rc = %d. This code"
922                            " is usually OK, but can be useful for debugging"
923                            " purposes.\n", rc);
924                 rc = OP_JIT_CONV_OK;
925         }
926         fflush(stdout);
927         if (rc == OP_JIT_CONV_OK)
928                 rc = EXIT_SUCCESS;
929         else
930                 rc = EXIT_FAILURE;
931 out:
932         _exit(rc);
933 }