File: [local] / src / libexec / ld.so / trace.c (download)
Revision 1.5, Sat Jan 8 06:49:41 2022 UTC (2 years, 5 months ago) by guenther
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, OPENBSD_7_1_BASE, OPENBSD_7_1, HEAD Changes since 1.4: +2 -2 lines
Prep .c files for removing the #includes from */archdep.h
* replace #include "archdep.h" with #includes of what is used, pulling in
"syscall.h", "util.h", and "archdep.h" as needed
* delete #include <sys/syscall.h> from syscall.h
* only pull in <sys/stat.h> to the three files that use _dl_fstat(),
forward declare struct stat in syscall.h for the others
* NBBY is for <sys/select.h> macros; just use '8' in dl_printf.c
* <machine/vmparam.h> is only needed on i386; conditionalize it
* stop using __LDPGSZ: use _MAX_PAGE_SHIFT (already used by malloc.c)
where necessary
* delete other bogus #includes, order legit per style: <sys/*> then
<*/*>, then <*>, then "*"
dir.c improvement from jsg@
ok and testing assistance deraadt@
|
/* $OpenBSD: trace.c,v 1.5 2022/01/08 06:49:41 guenther Exp $ */
/*
* Copyright (c) 2013 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include "syscall.h"
#include "util.h"
#include "resolve.h"
/*
* Library call tracing routines.
*/
static int _dl_traceplt;
struct tracespec {
int inverse; /* blacklist instead of whitelist */
char *spec; /* comma separated spec entries */
};
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;
/*
* We expect LD_TRACE_PLT to be empty unless trace inheritance has
* been setup by ltrace(1). We can then clear the environment
* variable to avoid useless work in our children, should we fork
* any.
*/
inherit = *var != '\0';
if (!inherit)
_dl_unsetenv("LD_TRACE_PLT", envp);
/*
* Check for a fine-grained trace specification, and extract the
* library and function lists, if any.
*/
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; /* keep tracing */
}
/*
* Extract a trace specification field, and setup the tracespec struct
* accordingly.
*/
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;
}
/*
* Check if a given name matches a trace specification list.
*/
static int
_dl_trace_match(const char *name, struct tracespec *spec, int allow_so)
{
const char *list, *end, *next;
size_t span;
int match;
/* no spec means trace everything */
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 the object name matches the specification
* fragment so far, it's a match if:
* + the specification ends in a star (wildcard
* match)
* + there are no remaining chars in both the
* object name and the specification (exact
* match)
* + the specification ends (no star) and the
* object name continues with ".so" (radix
* match) and `allow_so' is nonzero.
*/
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;
}