#include <sys/types.h>
#include "syscall.h"
#include "util.h"
#include "resolve.h"
static int _dl_traceplt;
struct tracespec {
int inverse;
char *spec;
};
static struct tracespec _dl_tracelib, _dl_tracefunc;
static const char *_dl_trace_parse_spec(const char *, struct tracespec *);
static int _dl_trace_match(const char *, struct tracespec *, int);
void
_dl_trace_setup(char **envp)
{
const char *var;
int inherit;
var = _dl_getenv("LD_TRACE_PLT", envp);
if (var == NULL)
return;
if (!_dl_trust) {
_dl_unsetenv("LD_TRACE_PLT", envp);
return;
}
_dl_traceplt = 1;
inherit = *var != '\0';
if (!inherit)
_dl_unsetenv("LD_TRACE_PLT", envp);
var = _dl_getenv("LD_TRACE_PLTSPEC", envp);
if (var != NULL) {
var = _dl_trace_parse_spec(var, &_dl_tracelib);
(void)_dl_trace_parse_spec(var, &_dl_tracefunc);
if (!inherit)
_dl_unsetenv("LD_TRACE_PLTSPEC", envp);
}
}
void
_dl_trace_object_setup(elf_object_t *object)
{
const char *basename, *slash;
object->traced = 0;
if (_dl_traceplt) {
basename = object->load_name;
while (*basename == '/') {
basename++;
slash = _dl_strchr(basename, '/');
if (slash == NULL)
break;
basename = slash;
}
if (_dl_trace_match(basename, &_dl_tracelib, 1))
object->traced = 1;
}
}
int
_dl_trace_plt(const elf_object_t *object, const char *symname)
{
if (!_dl_trace_match(symname, &_dl_tracefunc, 0))
return 0;
_dl_utrace(".plt object",
object->load_name, _dl_strlen(object->load_name));
_dl_utrace(".plt symbol",
symname, _dl_strlen(symname));
return 1;
}
const char *
_dl_trace_parse_spec(const char *var, struct tracespec *spec)
{
const char *start, *end;
if (*var == '!') {
spec->inverse = 1;
var++;
}
start = var;
end = _dl_strchr(start, ':');
if (end == NULL)
end = start + _dl_strlen(start);
if (end != start) {
spec->spec = _dl_malloc(1 + end - start);
if (spec->spec == NULL)
_dl_oom();
_dl_bcopy(start, spec->spec, end - start);
spec->spec[end - start] = '\0';
}
if (*end == ':')
end++;
return end;
}
static int
_dl_trace_match(const char *name, struct tracespec *spec, int allow_so)
{
const char *list, *end, *next;
size_t span;
int match;
if (spec->spec == NULL)
return 1;
match = 0;
list = spec->spec;
end = list + _dl_strlen(list);
while (*list != '\0') {
next = _dl_strchr(list, ',');
if (next == NULL)
next = end;
span = next - list;
if (span != 0 && *(next - 1) == '*')
span--;
if (span != 0 && _dl_strncmp(name, list, span) == 0) {
if (list[span] == '*' ||
name[span] == '\0' ||
(allow_so &&
_dl_strncmp(name + span, ".so", 3) == 0)) {
match = 1;
break;
}
}
while (*next == ',')
next++;
list = next;
}
return spec->inverse ? !match : match;
}