Skip to content

Instantly share code, notes, and snippets.

@compnerd
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save compnerd/929b113f86d1ddd8166a to your computer and use it in GitHub Desktop.
Save compnerd/929b113f86d1ddd8166a to your computer and use it in GitHub Desktop.
/**
* Copyright © 2015 Saleem Abdulrasool <compnerd@compnerd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/
/* x86_64-pc-linux-gnu-cc -std=c11 -fpic -shared -Wall -Werror %s -o libtrace.so -ldl */
#define _GNU_SOURCE
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/auxv.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <dirent.h>
#include <execinfo.h>
#include <fcntl.h>
#include <regex.h>
#include <unistd.h>
#define COUNTOF(array) ((sizeof(array) / sizeof(*array)))
static const char *patterns[] = {
"/usr/[^/]+/share",
};
static int fd = -1;
static bool initialised = false;
static regex_t paths[COUNTOF(patterns)];
void __attribute__ (( constructor )) constructor() {
for (unsigned path = 0; path < COUNTOF(paths); ++path)
if (regcomp(&paths[path], patterns[path], REG_EXTENDED | REG_NOSUB))
return perror("unable to compile pattern");
initialised = true;
}
void __attribute__ (( destructor )) destructor() {
if (fd >= 0)
close(fd);
for (unsigned path = 0; path < COUNTOF(paths); ++path)
regfree(&paths[path]);
}
static int get_fd() {
char *buffer = NULL;
if (fd >= 0)
return fd;
asprintf(&buffer, "%s/%u-%s-XXXXXX", getenv("TMPDIR") ?: "/tmp", getpid(),
strrchr((char *)getauxval(AT_EXECFN), '/') + 1);
fd = mkostemp(buffer, O_CLOEXEC | O_EXCL | O_SYNC | O_CREAT);
if (fd < 0) {
perror("unable to open log file");
free(buffer);
return 0;
}
free(buffer);
return fd;
}
static bool match(const char *string) {
if (!initialised)
return false;
for (unsigned path = 0; path < COUNTOF(paths); ++path)
if (!regexec(&paths[path], string, 0, NULL, 0))
return true;
return false;
}
static void print_backtrace() {
void *frame[128];
size_t frames;
frames = backtrace(frame, COUNTOF(frame));
backtrace_symbols_fd(frame, frames, get_fd());
}
FILE *fopen(const char *path, const char *mode) {
static FILE *(*real_fopen)(const char *, const char *) = NULL;
if (real_fopen == NULL)
real_fopen =
(FILE *(*)(const char *, const char *))dlsym(RTLD_NEXT, "fopen");
assert(real_fopen && "unable to find fopen(3)");
if (match(path)) {
dprintf(get_fd(), "fopen(%s, %s)\n", path, mode);
print_backtrace();
dprintf(get_fd(), " \r\n");
}
return real_fopen(path, mode);
}
int open(const char *pathname, int flags, ...) {
static int (*real_open)(const char *, int, ...) = NULL;
if (real_open == NULL)
real_open = (int (*)(const char *, int, ...))dlsym(RTLD_NEXT, "open");
assert(real_open && "unable to find open(2)");
if (match(pathname)) {
dprintf(get_fd(), "open(%s, %u, ...)\n", pathname, flags);
print_backtrace();
dprintf(get_fd(), " \r\n");
}
return real_open(pathname, flags);
}
int openat(int dirfd, const char *pathname, int flags, ...) {
static int (*real_openat)(int, const char *, int, ...) = NULL;
if (real_openat == NULL)
real_openat =
(int (*)(int, const char *, int, ...))dlsym(RTLD_NEXT, "openat");
assert(real_openat && "unable to find openat(2)");
if (match(pathname)) {
dprintf(get_fd(), "openat(%u, %s, %u, ...)\n", dirfd, pathname, flags);
print_backtrace();
dprintf(get_fd(), " \r\n");
}
return real_openat(dirfd, pathname, flags);
}
DIR *opendir(const char *name) {
static DIR *(*real_opendir)(const char *) = NULL;
if (real_opendir == NULL)
real_opendir = (DIR *(*)(const char *))dlsym(RTLD_NEXT, "opendir");
assert(real_opendir && "unable to find opendir(3)");
if (match(name)) {
dprintf(get_fd(), "opendir(%s)\n", name);
print_backtrace();
dprintf(get_fd(), " \r\n");
}
return real_opendir(name);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment