관리-도구
편집 파일: runtime.h
/* 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 /* stapdyn doesn't deal with mixed-architectures yet. */ #define _stp_is_compat_task() 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_ */