runtime/dyninst/runtime.h - systemtap
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
/* main dyninst header file
* Copyright (C) 2012 Red Hat Inc.
*
* This file is part of systemtap, and is free software. You can
* redistribute it and/or modify it under the terms of the GNU General
* Public License (GPL); either version 2, or (at your option) any
* later version.
*/
#ifndef _STAPDYN_RUNTIME_H_
#define _STAPDYN_RUNTIME_H_
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <sched.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/ptrace.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "loc2c-runtime.h"
#include "stapdyn.h"
#if __WORDSIZE == 64
#define CONFIG_64BIT 1
#endif
#define BITS_PER_LONG __WORDSIZE
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#include "linux_types.h"
#include "offset_list.h"
#ifndef NSEC_PER_SEC
#define NSEC_PER_SEC 1000000000L
#endif
#define _stp_timespec_sub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
if ((result)->tv_nsec < 0) { \
--(result)->tv_sec; \
(result)->tv_nsec += NSEC_PER_SEC; \
} \
} while (0)
#define simple_strtol strtol
// segments don't matter in dyninst...
#define USER_DS (1)
#define KERNEL_DS (-1)
typedef int mm_segment_t;
static inline mm_segment_t get_fs(void) { return 0; }
static inline void set_fs(mm_segment_t seg) { (void)seg; }
static inline int atomic_add_return(int i, atomic_t *v)
{
return __sync_add_and_fetch(&(v->counter), i);
}
static inline int atomic_sub_return(int i, atomic_t *v)
{
return __sync_sub_and_fetch(&(v->counter), i);
}
static inline int pseudo_atomic_cmpxchg(atomic_t *v, int oldval, int newval)
{
return __sync_val_compare_and_swap(&(v->counter), oldval, newval);
}
#include "linux_defs.h"
#define MODULE_DESCRIPTION(str)
#define MODULE_LICENSE(str)
#define MODULE_INFO(tag,info)
/* Semi-forward declarations from runtime_context.h, needed by stat.c/shm.c. */
static int _stp_runtime_num_contexts;
/* Semi-forward declarations from this file, needed by stat.c/transport.c. */
static int stp_pthread_mutex_init_shared(pthread_mutex_t *mutex);
static int stp_pthread_cond_init_shared(pthread_cond_t *cond);
#define for_each_possible_cpu(cpu) for ((cpu) = 0; (cpu) < _stp_runtime_num_contexts; (cpu)++)
#define yield() sched_yield()
#define access_ok(type, addr, size) 1
#define preempt_disable() 0
#define preempt_enable_no_resched() 0
static int _stp_sched_getcpu(void)
{
/* We prefer sched_getcpu directly, of course. It wasn't added until glibc
* 2.6 though, and has no direct feature indication, but CPU_ZERO_S was
* added shortly after too. */
#ifdef CPU_ZERO_S
return sched_getcpu();
#elif defined(SYS_getcpu)
/* A manual getcpu is fine too, though not necessarily as fast since it
* can't be optimized as a vdso/vsyscall. */
unsigned cpu;
int ret = syscall(SYS_getcpu, &cpu, NULL, NULL);
return (ret < 0) ? ret : (int)cpu;
#else
/* XXX Any other way to find our cpu? Manual vgetcpu? */
return -2;
#endif
}
/* see common_session_state.h */
static inline struct _stp_transport_session_data *stp_transport_data(void);
static inline struct _stp_session_attributes *stp_session_attributes(void);
/*
* By definition, we can only debug our own processes with dyninst, so
* assert_is_myproc() will never assert.
*
* FIXME: We might want to add the check back, to get a better error
* message.
*/
#define assert_is_myproc() do {} while (0)
#include "debug.h"
#include "io.c"
#include "alloc.c"
#include "shm.c"
#include "print.h"
#include "stp_string.c"
#include "arith.c"
#include "copy.c"
#include "../regs.c"
#include "task_finder.c"
#include "sym.c"
#include "perf.c"
#include "addr-map.c"
#include "stat.c"
#include "unwind.c"
#include "session_attributes.c"
/* Support function for int64_t module parameters. */
static int set_int64_t(const char *val, int64_t *mp)
{
char *endp;
long long ll;
if (!val)
return -EINVAL;
ll = strtoull(val, &endp, 0);
if ((endp == val) || ((int64_t)ll != ll) || (*endp != '\0'))
return -EINVAL;
*mp = (int64_t)ll;
return 0;
}
static int systemtap_module_init(void);
static void systemtap_module_exit(void);
static inline unsigned long _stap_hash_seed(); /* see common_session_state.h */
#define stap_hash_seed _stap_hash_seed()
typedef pthread_rwlock_t rwlock_t; /* for globals */
static int stp_pthread_mutex_init_shared(pthread_mutex_t *mutex)
{
int rc;
pthread_mutexattr_t attr;
rc = pthread_mutexattr_init(&attr);
if (rc != 0) {
_stp_error("pthread_mutexattr_init failed");
return rc;
}
rc = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
if (rc != 0) {
_stp_error("pthread_mutexattr_setpshared failed");
goto err_attr;
}
rc = pthread_mutex_init(mutex, &attr);
if (rc != 0) {
_stp_error("pthread_mutex_init failed");
goto err_attr;
}
err_attr:
(void)pthread_mutexattr_destroy(&attr);
return rc;
}
static int stp_pthread_cond_init_shared(pthread_cond_t *cond)
{
int rc;
pthread_condattr_t attr;
rc = pthread_condattr_init(&attr);
if (rc != 0) {
_stp_error("pthread_condattr_init failed");
return rc;
}
rc = pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
if (rc != 0) {
_stp_error("pthread_condattr_setpshared failed");
goto err_attr;
}
rc = pthread_cond_init(cond, &attr);
if (rc != 0) {
_stp_error("pthread_cond_init failed");
goto err_attr;
}
err_attr:
(void)pthread_condattr_destroy(&attr);
return rc;
}
static int stp_pthread_rwlock_init_shared(pthread_rwlock_t *rwlock)
{
int rc;
pthread_rwlockattr_t attr;
rc = pthread_rwlockattr_init(&attr);
if (rc != 0) {
_stp_error("pthread_rwlockattr_init failed");
return rc;
}
rc = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
if (rc != 0) {
_stp_error("pthread_rwlockattr_setpshared failed");
goto err_attr;
}
rc = pthread_rwlock_init(rwlock, &attr);
if (rc != 0) {
_stp_error("pthread_rwlock_init failed");
goto err_attr;
}
err_attr:
(void)pthread_rwlockattr_destroy(&attr);
return rc;
}
static inline void stp_synchronize_sched(void) { }
/*
* For stapdyn to work in a multiprocess environment, the module must be
* prepared to be loaded multiple times in different processes. Thus, we have
* to distinguish between process-level resource initialization and
* "session"-level (like probe begin/end/error).
*
* So stp_dyninst_ctor/dtor are the process-level functions, using gcc
* attributes to get called at the right time. One startup exception is
* stp_dyninst_shm_connect, which has to later be called manually with the shm
* path being used in this session.
*
* The session-level resources have to be started by the stapdyn mutator, and
* are called within stapdyn itself. This primarily involves allocating the
* shared memory and initializing its contents, but also running those global
* begin/end/error probes.
*
* NB: We used to keep code that tried to deal with stapdyn 2.0, which didn't
* know about shm initialization, and ran everything in the mutatees only.
* We've now broken that tie, and stp_dyninst_session_init will detect that
* shm wasn't initialized and bow out.
*/
static int _stp_runtime_contexts_init(void);
static int stp_dyninst_ctor_rc = 0;
__attribute__((constructor))
static void stp_dyninst_ctor(void)
{
int rc = 0;
rc = _stp_copy_init();
if (rc == 0)
rc = _stp_runtime_contexts_init();
if (rc == 0)
rc = _stp_print_init();
stp_dyninst_ctor_rc = rc;
}
const char* stp_dyninst_shm_init(void)
{
return _stp_shm_init();
}
int stp_dyninst_shm_connect(const char* name)
{
int rc;
/* We don't have a chance to indicate errors in the ctor, so do it here. */
if (stp_dyninst_ctor_rc != 0) {
return stp_dyninst_ctor_rc;
}
rc = _stp_shm_connect(name);
return rc;
}
int stp_dyninst_session_init(void)
{
/* We don't have a chance to indicate errors in the ctor, so do it here. */
if (stp_dyninst_ctor_rc != 0) {
return stp_dyninst_ctor_rc;
}
/* If shared memory has not been initialized yet, we're probably dealing
* with stapdyn 2.0 -- we no longer support this case. */
if (_stp_shm_base == NULL)
return -ENOMEM;
return systemtap_module_init();
}
/* This is called during systemtap_module_init, after globals/etc are set up,
* but before any probes are actually executed.
* (Perhaps it would be cleaner if the translator split those stages?)
*/
static int stp_dyninst_session_init_finished(void)
{
_stp_shm_finalize();
/* Now that the shared memory is finalized, start the
* transport. If we started it before now, allocations could have
* caused the base address of the shared memory to move around,
* which would cause the addresses of the mutexes to move
* around. */
return _stp_dyninst_transport_session_start();
}
void stp_dyninst_session_exit(void)
{
systemtap_module_exit();
}
static int _stp_exit_status = 0;
int stp_dyninst_exit_status(void)
{
return _stp_exit_status;
}
__attribute__((destructor))
static void stp_dyninst_dtor(void)
{
_stp_print_cleanup();
_stp_shm_destroy();
_stp_copy_destroy();
}
#endif /* _STAPDYN_RUNTIME_H_ */