/* Copyright (C) 2008, 2009, 2010 Jiri Olsa This file is part of the latrace. The latrace is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The latrace is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the latrace (file COPYING). If not, see . */ #include #include #include #include #include #include #include #include #include #include "config.h" struct lt_config_audit cfg; static int init_ctl_config(char *file) { void *sh; int len; int page = sysconf(_SC_PAGE_SIZE); int fd; if (-1 == (fd = open(file, O_RDWR))) { perror("open failed"); return -1; } /* align the shared config length */ len = sizeof(struct lt_config_shared); len = (len + page) & ~(page - 1); sh = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if ((void *) -1 == sh) { PRINT_VERBOSE(&cfg, 1, "mmap failed: %s\n", strerror(errno)); return -1; } /* switching to the mmaped shared config */ cfg.sh = sh; /* PRINT_VERBOSE magic */ cfg.sh->sh = sh; return 0; } static int read_config(char *dir) { int fd; off_t len; char file[LT_MAXFILE]; memset(&cfg, 0, sizeof(cfg)); cfg.dir = dir; sprintf(file, "%s/config", dir); if (-1 == (fd = open(file, O_RDONLY))) { perror("open failed"); return -1; } if (-1 == read(fd, &cfg.sh_storage, sizeof(cfg.sh_storage))) { perror("read failed"); return -1; } if (-1 == (len = lseek(fd, 0, SEEK_END))) { perror("lseek failed"); return -1; } if (len != sizeof(cfg.sh_storage)) { printf("config file size differs\n"); return -1; } if (LT_CONFIG_MAGIC != cfg.sh_storage.magic) { printf("config file magic check failed\n"); return -1; } cfg.sh = cfg.sh_storage.sh = &cfg.sh_storage; /* * If we are not controled, we can close the file, * since we read everything we needed. */ close(fd); if (lt_sh(&cfg, ctl_config) && init_ctl_config(file)) printf("ctl config failed, carring on with standard\n"); return 0; } static int get_names(struct lt_config_audit *cfg, char *names, char **ptr) { char* s; int cnt = 0; PRINT_VERBOSE(cfg, 1, "names: [%s] max: %d\n", names, LT_NAMES_MAX); s = strchr(names, LT_NAMES_SEP); while(NULL != (s = strchr(names, LT_NAMES_SEP)) && (cnt < LT_NAMES_MAX)) { *s = 0x0; PRINT_VERBOSE(cfg, 1, "got: %s", names); ptr[cnt++] = names; names = ++s; } if (cnt) { ptr[cnt++] = names; PRINT_VERBOSE(cfg, 1, "got: %s\n", names); } if (!cnt && *names) { ptr[0] = names; cnt = 1; PRINT_VERBOSE(cfg, 1, "got: %s\n", names); } ptr[cnt] = NULL; if (!cnt) return -1; PRINT_VERBOSE(cfg, 1, "got %d entries\n", cnt); return cnt; } int audit_init(int argc, char **argv, char **env) { if (-1 == read_config(getenv("LT_DIR"))) return -1; #ifdef CONFIG_ARCH_HAVE_ARGS /* -Aa */ if (lt_sh(&cfg, args_enabled) && lt_args_init(cfg.sh)) return -1; #endif /* -t */ if ((*lt_sh(&cfg, libs_to)) && (-1 == (cfg.libs_to_cnt = get_names(&cfg, lt_sh(&cfg, libs_to), cfg.libs_to)))) { printf("latrace failed to parse libs to\n"); return -1; } /* -f */ if ((*lt_sh(&cfg, libs_from)) && (-1 == (cfg.libs_from_cnt = get_names(&cfg, lt_sh(&cfg, libs_from), cfg.libs_from)))) { printf("latrace failed to parse libs from\n"); return -1; } /* -l */ if ((*lt_sh(&cfg, libs_both)) && (-1 == (cfg.libs_both_cnt = get_names(&cfg, lt_sh(&cfg, libs_both), cfg.libs_both)))) { printf("latrace failed to parse libs from\n"); return -1; } /* -s */ if ((*lt_sh(&cfg, symbols)) && (-1 == (cfg.symbols_cnt = get_names(&cfg, lt_sh(&cfg, symbols), cfg.symbols)))) { printf("latrace failed to parse symbols\n"); return -1; } /* -n */ if ((*lt_sh(&cfg, symbols_omit)) && (-1 == (cfg.symbols_omit_cnt = get_names(&cfg, lt_sh(&cfg, symbols_omit), cfg.symbols_omit)))) { printf("latrace failed to parse symbols to omit\n"); return -1; } /* SYM_NOEXIT option */ if ((*lt_sh(&cfg, symbols_noexit)) && (-1 == (cfg.symbols_noexit_cnt = get_names(&cfg, lt_sh(&cfg, symbols_noexit), cfg.symbols_noexit)))) { printf("latrace failed to parse noexit symbols\n"); return -1; } /* -b */ if ((*lt_sh(&cfg, flow_below)) && (-1 == (cfg.flow_below_cnt = get_names(&cfg, lt_sh(&cfg, flow_below), cfg.flow_below)))) { printf("latrace failed to parse symbols in flow-below option\n"); return -1; } /* -L */ if (*lt_sh(&cfg, libs_subst)) { char *ptr[LT_NAMES_MAX]; int cnt; if (-1 == (cnt = get_names(&cfg, lt_sh(&cfg, libs_subst), ptr))) { printf("latrace failed to parse input for subst option\n"); return -1; } if (-1 == lt_objsearch_init(&cfg, ptr, cnt)) { printf("latrace failed to nitialize subst option\n"); return -1; } } /* -o FIXME put fout out of the shared structure */ lt_sh(&cfg, fout) = stdout; if ((*lt_sh(&cfg, output)) && (NULL == (lt_sh(&cfg, fout) = fopen(lt_sh(&cfg, output), "w")))) { printf("latrace failed to open output file %s\n", lt_sh(&cfg, output)); return -1; } /* -E */ if (lt_sh(&cfg, not_follow_exec)) unsetenv("LD_AUDIT"); /* -F */ if (lt_sh(&cfg, not_follow_fork)) lt_sh(&cfg, pid) = getpid(); /* enable global symbols if needed */ lt_sh(&cfg, global_symbols) = lt_sh(&cfg, args_enabled); PRINT_VERBOSE(&cfg, 1, "global_symbols %d\n", lt_sh(&cfg, global_symbols)); cfg.init_ok = 1; return 0; } void finalize(void) __attribute__((destructor)); void finalize(void) { if ((!lt_sh(&cfg, pipe)) && (*lt_sh(&cfg, output))) fclose(lt_sh(&cfg, fout)); }