mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 00:16:11 +00:00
182 lines
5.5 KiB
C
182 lines
5.5 KiB
C
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2014-2015 Philippe Waroquiers
|
|
|
|
This program 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 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
/* This file is used to generate target executable(s) getoff-<platform>
|
|
In a bi-arch setup, this is used to build 2 executables
|
|
(for the primary and secondary platforms).
|
|
|
|
This program uses user space libraries to retrieve some platform
|
|
dependent offsets needed for Valgrind core, but that cannot (easily)
|
|
be retrieved by Valgrind core.
|
|
|
|
This is currently used only for handling the gdbsrv QGetTlsAddr query :
|
|
it only computes and outputs lm_modid_offset in struct link_map
|
|
of the dynamic linker. In theory, we should also compute the offset needed
|
|
to get the dtv from the thread register/pointer/...
|
|
Currently, the various valgrind-low-xxxxxx.c files are hardcoding this
|
|
offset as it is deemed (?) stable, and there is no clear way how to
|
|
compute this dtv offset.
|
|
|
|
The getoff-<platform> executable will be launched automatically by
|
|
Valgrind gdbserver when the first QGetTlsAddr query is retrieved.
|
|
|
|
On plaforms that do not support __thread and/or that do not provide
|
|
dlinfo RTLD_DI_TLS_MODID, this executable produces no output. */
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
#include <config.h>
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_DLINFO_RTLD_DI_TLS_MODID
|
|
#include <link.h>
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
/* true if arg matches the provided option */
|
|
static
|
|
int is_opt(char* arg, const char *option)
|
|
{
|
|
int option_len = strlen(option);
|
|
if (option[option_len-1] == '=')
|
|
return (0 == strncmp(option, arg, option_len));
|
|
else
|
|
return (0 == strcmp(option, arg));
|
|
}
|
|
|
|
static int verbose = 0;
|
|
|
|
static
|
|
void usage (char* progname)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s [--help] [-h] [-v] [-o <outputfile>]\n"
|
|
"Outputs various user space offsets\n"
|
|
"By default, outputs on stdout.\n"
|
|
"Use -o to output to <outputfile>\n"
|
|
"-v : be more verbose\n",
|
|
progname);
|
|
|
|
}
|
|
|
|
int main (int argc, char** argv)
|
|
{
|
|
int i;
|
|
FILE *outputfile;
|
|
int nr_errors = 0;
|
|
|
|
outputfile = stdout;
|
|
|
|
i = 1;
|
|
while (i < argc) {
|
|
if (is_opt(argv[i], "--help") || is_opt(argv[i], "-h")) {
|
|
usage(argv[0]);
|
|
exit(0);
|
|
} else if (is_opt(argv[i], "-v")) {
|
|
verbose++;
|
|
} else if (is_opt(argv[i], "-o")) {
|
|
if (i+1 == argc) {
|
|
fprintf(stderr,
|
|
"missing output file for -o option\n"
|
|
"Use --help for more information.\n");
|
|
exit (1);
|
|
}
|
|
i++;
|
|
outputfile = fopen(argv[i], "w");
|
|
if (outputfile == NULL) {
|
|
fprintf(stderr, "Could not fopen %s in write mode\n", argv[i]);
|
|
perror ("fopen output file failed");
|
|
exit (1);
|
|
}
|
|
} else {
|
|
fprintf (stderr,
|
|
"unknown or invalid argument %s\n"
|
|
"Use --help for more information.\n",
|
|
argv[i]);
|
|
exit(1);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
#ifdef HAVE_DLINFO_RTLD_DI_TLS_MODID
|
|
/* Compute offset of lm_modid in struct link_map.
|
|
This is needed to support QGetTlsAddr gdbsrv query.
|
|
Computation is done using an ugly hack, but less ugly than
|
|
hardcoding the offset depending on the glibc version and
|
|
platform.
|
|
The below works, based the assumption that RTLD_DI_TLS_MODID
|
|
just access and returns directly the field in the dummy
|
|
link_map structure we have prepared.
|
|
|
|
If glibc debug info is installed on your system, you can
|
|
also find this offset by doing in GDB:
|
|
p &((struct link_map*)0x0)->l_tls_modid
|
|
(see also coregrind/m_gdbserver/valgrind_low.h target_get_dtv
|
|
comments).
|
|
*/
|
|
{
|
|
#define MAX_LINKMAP_WORDS 10000
|
|
size_t dummy_link_map[MAX_LINKMAP_WORDS];
|
|
size_t off;
|
|
size_t modid_offset;
|
|
for (off = 0; off < MAX_LINKMAP_WORDS; off++)
|
|
dummy_link_map[off] = off;
|
|
if (dlinfo ((void*)dummy_link_map, RTLD_DI_TLS_MODID,
|
|
&modid_offset) == 0) {
|
|
assert(modid_offset >= 0 && modid_offset < MAX_LINKMAP_WORDS);
|
|
fprintf(outputfile,
|
|
"lm_modid_offset 0x%zx\n", modid_offset*sizeof(size_t));
|
|
} else {
|
|
fprintf(stderr,
|
|
"Error computing lm_modid_offset.\n"
|
|
"dlinfo error %s\n", dlerror());
|
|
nr_errors++;
|
|
}
|
|
#undef MAX_LINKMAP_WORDS
|
|
}
|
|
|
|
if (outputfile != stdout)
|
|
if (fclose (outputfile) != 0) {
|
|
perror ("fclose output file failed\n");
|
|
nr_errors++;
|
|
}
|
|
#else
|
|
if (verbose)
|
|
fprintf(stderr,
|
|
"cannot compute lm_modid_offset.\n"
|
|
"configure did not define HAVE_DLINFO_RTLD_DI_TLS_MODID.\n");
|
|
#endif
|
|
|
|
if (nr_errors == 0)
|
|
exit(0);
|
|
else
|
|
exit(1);
|
|
}
|