diff options
Diffstat (limited to 'tools/lib/lockdep')
55 files changed, 1486 insertions, 0 deletions
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile new file mode 100644 index 00000000000..52f9279c6c1 --- /dev/null +++ b/tools/lib/lockdep/Makefile @@ -0,0 +1,243 @@ +# file format version +FILE_VERSION = 1 + +LIBLOCKDEP_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) + +# Makefiles suck: This macro sets a default value of $(2) for the +# variable named by $(1), unless the variable has been set by +# environment or command line. This is necessary for CC and AR +# because make sets default values, so the simpler ?= approach +# won't work as expected. +define allow-override +  $(if $(or $(findstring environment,$(origin $(1))),\ +            $(findstring command line,$(origin $(1)))),,\ +    $(eval $(1) = $(2))) +endef + +# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. +$(call allow-override,CC,$(CROSS_COMPILE)gcc) +$(call allow-override,AR,$(CROSS_COMPILE)ar) + +INSTALL = install + +# Use DESTDIR for installing into a different root directory. +# This is useful for building a package. The program will be +# installed in this directory as if it was the root directory. +# Then the build tool can move it later. +DESTDIR ?= +DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' + +prefix ?= /usr/local +libdir_relative = lib +libdir = $(prefix)/$(libdir_relative) +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) + +export DESTDIR DESTDIR_SQ INSTALL + +# copy a bit from Linux kbuild + +ifeq ("$(origin V)", "command line") +  VERBOSE = $(V) +endif +ifndef VERBOSE +  VERBOSE = 0 +endif + +ifeq ("$(origin O)", "command line") +  BUILD_OUTPUT := $(O) +endif + +ifeq ($(BUILD_SRC),) +ifneq ($(BUILD_OUTPUT),) + +define build_output +	$(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT)	\ +	BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 +endef + +saved-output := $(BUILD_OUTPUT) +BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) +$(if $(BUILD_OUTPUT),, \ +     $(error output directory "$(saved-output)" does not exist)) + +all: sub-make + +gui: force +	$(call build_output, all_cmd) + +$(filter-out gui,$(MAKECMDGOALS)): sub-make + +sub-make: force +	$(call build_output, $(MAKECMDGOALS)) + + +# Leave processing to above invocation of make +skip-makefile := 1 + +endif # BUILD_OUTPUT +endif # BUILD_SRC + +# We process the rest of the Makefile if this is the final invocation of make +ifeq ($(skip-makefile),) + +srctree		:= $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))) +objtree		:= $(realpath $(CURDIR)) +src		:= $(srctree) +obj		:= $(objtree) + +export prefix libdir bindir src obj + +# Shell quotes +libdir_SQ = $(subst ','\'',$(libdir)) +bindir_SQ = $(subst ','\'',$(bindir)) + +LIB_FILE = liblockdep.a liblockdep.so.$(LIBLOCKDEP_VERSION) +BIN_FILE = lockdep + +CONFIG_INCLUDES = +CONFIG_LIBS	= +CONFIG_FLAGS	= + +OBJ		= $@ +N		= + +export Q VERBOSE + +INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES) + +# Set compile option CFLAGS if not set elsewhere +CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g + +override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) + +ifeq ($(VERBOSE),1) +  Q = +  print_compile = +  print_app_build = +  print_fpic_compile = +  print_shared_lib_compile = +  print_install = +else +  Q = @ +  print_compile =		echo '  CC                 '$(OBJ); +  print_app_build =		echo '  BUILD              '$(OBJ); +  print_fpic_compile =		echo '  CC FPIC            '$(OBJ); +  print_shared_lib_compile =	echo '  BUILD SHARED LIB   '$(OBJ); +  print_static_lib_build =	echo '  BUILD STATIC LIB   '$(OBJ); +  print_install =		echo '  INSTALL     '$1'	to	$(DESTDIR_SQ)$2'; +endif + +do_fpic_compile =					\ +	($(print_fpic_compile)				\ +	$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) + +do_app_build =						\ +	($(print_app_build)				\ +	$(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) + +do_compile_shared_library =			\ +	($(print_shared_lib_compile)		\ +	$(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -s $@ liblockdep.so)) + +do_build_static_lib =				\ +	($(print_static_lib_build)		\ +	$(RM) $@;  $(AR) rcs $@ $^) + + +define do_compile +	$(print_compile)						\ +	$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; +endef + +$(obj)/%.o: $(src)/%.c +	$(Q)$(call do_compile) + +%.o: $(src)/%.c +	$(Q)$(call do_compile) + +PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o + +ALL_OBJS = $(PEVENT_LIB_OBJS) + +CMD_TARGETS = $(LIB_FILE) + +TARGETS = $(CMD_TARGETS) + + +all: all_cmd + +all_cmd: $(CMD_TARGETS) + +liblockdep.so.$(LIBLOCKDEP_VERSION): $(PEVENT_LIB_OBJS) +	$(Q)$(do_compile_shared_library) + +liblockdep.a: $(PEVENT_LIB_OBJS) +	$(Q)$(do_build_static_lib) + +$(PEVENT_LIB_OBJS): %.o: $(src)/%.c +	$(Q)$(do_fpic_compile) + +## make deps + +all_objs := $(sort $(ALL_OBJS)) +all_deps := $(all_objs:%.o=.%.d) + +# let .d file also depends on the source and header files +define check_deps +		@set -e; $(RM) $@; \ +		$(CC) -MM $(CFLAGS) $< > $@.$$$$; \ +		sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ +		$(RM) $@.$$$$ +endef + +$(all_deps): .%.d: $(src)/%.c +	$(Q)$(call check_deps) + +$(all_objs) : %.o : .%.d + +dep_includes := $(wildcard $(all_deps)) + +ifneq ($(dep_includes),) + include $(dep_includes) +endif + +### Detect environment changes +TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE) + +tags:	force +	$(RM) tags +	find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ +	--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' + +TAGS:	force +	$(RM) TAGS +	find . -name '*.[ch]' | xargs etags \ +	--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' + +define do_install +	$(print_install)				\ +	if [ ! -d '$(DESTDIR_SQ)$2' ]; then		\ +		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2';	\ +	fi;						\ +	$(INSTALL) $1 '$(DESTDIR_SQ)$2' +endef + +install_lib: all_cmd +	$(Q)$(call do_install,$(LIB_FILE),$(libdir_SQ)) +	$(Q)$(call do_install,$(BIN_FILE),$(bindir_SQ)) + +install: install_lib + +clean: +	$(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d +	$(RM) tags TAGS + +endif # skip-makefile + +PHONY += force +force: + +# Declare the contents of the .PHONY variable as phony.  We keep that +# information in a variable so we can use it in if_changed and friends. +.PHONY: $(PHONY) diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c new file mode 100644 index 00000000000..8ef602f18a3 --- /dev/null +++ b/tools/lib/lockdep/common.c @@ -0,0 +1,33 @@ +#include <stddef.h> +#include <stdbool.h> +#include <linux/compiler.h> +#include <linux/lockdep.h> +#include <unistd.h> +#include <sys/syscall.h> + +static __thread struct task_struct current_obj; + +/* lockdep wants these */ +bool debug_locks = true; +bool debug_locks_silent; + +__attribute__((constructor)) static void liblockdep_init(void) +{ +	lockdep_init(); +} + +__attribute__((destructor)) static void liblockdep_exit(void) +{ +	debug_check_no_locks_held(¤t_obj); +} + +struct task_struct *__curr(void) +{ +	if (current_obj.pid == 0) { +		/* Makes lockdep output pretty */ +		prctl(PR_GET_NAME, current_obj.comm); +		current_obj.pid = syscall(__NR_gettid); +	} + +	return ¤t_obj; +} diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h new file mode 100644 index 00000000000..0bda630027c --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/common.h @@ -0,0 +1,50 @@ +#ifndef _LIBLOCKDEP_COMMON_H +#define _LIBLOCKDEP_COMMON_H + +#include <pthread.h> + +#define NR_LOCKDEP_CACHING_CLASSES 2 +#define MAX_LOCKDEP_SUBCLASSES 8UL + +#ifndef CALLER_ADDR0 +#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +#endif + +#ifndef _RET_IP_ +#define _RET_IP_ CALLER_ADDR0 +#endif + +#ifndef _THIS_IP_ +#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) +#endif + +struct lockdep_subclass_key { +	char __one_byte; +}; + +struct lock_class_key { +	struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; +}; + +struct lockdep_map { +	struct lock_class_key	*key; +	struct lock_class	*class_cache[NR_LOCKDEP_CACHING_CLASSES]; +	const char		*name; +#ifdef CONFIG_LOCK_STAT +	int			cpu; +	unsigned long		ip; +#endif +}; + +void lockdep_init_map(struct lockdep_map *lock, const char *name, +			struct lock_class_key *key, int subclass); +void lock_acquire(struct lockdep_map *lock, unsigned int subclass, +			int trylock, int read, int check, +			struct lockdep_map *nest_lock, unsigned long ip); +void lock_release(struct lockdep_map *lock, int nested, +			unsigned long ip); + +#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ +	{ .name = (_name), .key = (void *)(_key), } + +#endif diff --git a/tools/lib/lockdep/include/liblockdep/mutex.h b/tools/lib/lockdep/include/liblockdep/mutex.h new file mode 100644 index 00000000000..ee53a42818c --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/mutex.h @@ -0,0 +1,70 @@ +#ifndef _LIBLOCKDEP_MUTEX_H +#define _LIBLOCKDEP_MUTEX_H + +#include <pthread.h> +#include "common.h" + +struct liblockdep_pthread_mutex { +	pthread_mutex_t mutex; +	struct lockdep_map dep_map; +}; + +typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t; + +#define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx)			\ +		(const struct liblockdep_pthread_mutex) {		\ +	.mutex = PTHREAD_MUTEX_INITIALIZER,				\ +	.dep_map = STATIC_LOCKDEP_MAP_INIT(#mtx, &((&(mtx))->dep_map)),	\ +} + +static inline int __mutex_init(liblockdep_pthread_mutex_t *lock, +				const char *name, +				struct lock_class_key *key, +				const pthread_mutexattr_t *__mutexattr) +{ +	lockdep_init_map(&lock->dep_map, name, key, 0); +	return pthread_mutex_init(&lock->mutex, __mutexattr); +} + +#define liblockdep_pthread_mutex_init(mutex, mutexattr)		\ +({								\ +	static struct lock_class_key __key;			\ +								\ +	__mutex_init((mutex), #mutex, &__key, (mutexattr));	\ +}) + +static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_mutex_lock(&lock->mutex); +} + +static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock) +{ +	lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); +	return pthread_mutex_unlock(&lock->mutex); +} + +static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0; +} + +static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock) +{ +	return pthread_mutex_destroy(&lock->mutex); +} + +#ifdef __USE_LIBLOCKDEP + +#define pthread_mutex_t         liblockdep_pthread_mutex_t +#define pthread_mutex_init      liblockdep_pthread_mutex_init +#define pthread_mutex_lock      liblockdep_pthread_mutex_lock +#define pthread_mutex_unlock    liblockdep_pthread_mutex_unlock +#define pthread_mutex_trylock   liblockdep_pthread_mutex_trylock +#define pthread_mutex_destroy   liblockdep_pthread_mutex_destroy + +#endif + +#endif diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h new file mode 100644 index 00000000000..4ec03f86155 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/rwlock.h @@ -0,0 +1,86 @@ +#ifndef _LIBLOCKDEP_RWLOCK_H +#define _LIBLOCKDEP_RWLOCK_H + +#include <pthread.h> +#include "common.h" + +struct liblockdep_pthread_rwlock { +	pthread_rwlock_t rwlock; +	struct lockdep_map dep_map; +}; + +typedef struct liblockdep_pthread_rwlock liblockdep_pthread_rwlock_t; + +#define LIBLOCKDEP_PTHREAD_RWLOCK_INITIALIZER(rwl)			\ +		(struct liblockdep_pthread_rwlock) {			\ +	.rwlock = PTHREAD_RWLOCK_INITIALIZER,				\ +	.dep_map = STATIC_LOCKDEP_MAP_INIT(#rwl, &((&(rwl))->dep_map)),	\ +} + +static inline int __rwlock_init(liblockdep_pthread_rwlock_t *lock, +				const char *name, +				struct lock_class_key *key, +				const pthread_rwlockattr_t *attr) +{ +	lockdep_init_map(&lock->dep_map, name, key, 0); + +	return pthread_rwlock_init(&lock->rwlock, attr); +} + +#define liblockdep_pthread_rwlock_init(lock, attr)		\ +({							\ +	static struct lock_class_key __key;		\ +							\ +	__rwlock_init((lock), #lock, &__key, (attr));	\ +}) + +static inline int liblockdep_pthread_rwlock_rdlock(liblockdep_pthread_rwlock_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_rwlock_rdlock(&lock->rwlock); + +} + +static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock) +{ +	lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); +	return pthread_rwlock_unlock(&lock->rwlock); +} + +static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_rwlock_wrlock(&lock->rwlock); +} + +static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0; +} + +static inline int liblockdep_pthread_rwlock_trywlock(liblockdep_pthread_rwlock_t *lock) +{ +	lock_acquire(&lock->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); +	return pthread_rwlock_trywlock(&lock->rwlock) == 0 ? 1 : 0; +} + +static inline int liblockdep_rwlock_destroy(liblockdep_pthread_rwlock_t *lock) +{ +	return pthread_rwlock_destroy(&lock->rwlock); +} + +#ifdef __USE_LIBLOCKDEP + +#define pthread_rwlock_t		liblockdep_pthread_rwlock_t +#define pthread_rwlock_init		liblockdep_pthread_rwlock_init +#define pthread_rwlock_rdlock		liblockdep_pthread_rwlock_rdlock +#define pthread_rwlock_unlock		liblockdep_pthread_rwlock_unlock +#define pthread_rwlock_wrlock		liblockdep_pthread_rwlock_wrlock +#define pthread_rwlock_tryrdlock	liblockdep_pthread_rwlock_tryrdlock +#define pthread_rwlock_trywlock		liblockdep_pthread_rwlock_trywlock +#define pthread_rwlock_destroy		liblockdep_rwlock_destroy + +#endif + +#endif diff --git a/tools/lib/lockdep/lockdep b/tools/lib/lockdep/lockdep new file mode 100755 index 00000000000..49af9fe19f5 --- /dev/null +++ b/tools/lib/lockdep/lockdep @@ -0,0 +1,3 @@ +#!/bin/bash + +LD_PRELOAD="./liblockdep.so $LD_PRELOAD" "$@" diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c new file mode 100644 index 00000000000..f42b7e9aa48 --- /dev/null +++ b/tools/lib/lockdep/lockdep.c @@ -0,0 +1,2 @@ +#include <linux/lockdep.h> +#include "../../../kernel/locking/lockdep.c" diff --git a/tools/lib/lockdep/lockdep_internals.h b/tools/lib/lockdep/lockdep_internals.h new file mode 100644 index 00000000000..29d0c954cc2 --- /dev/null +++ b/tools/lib/lockdep/lockdep_internals.h @@ -0,0 +1 @@ +#include "../../../kernel/locking/lockdep_internals.h" diff --git a/tools/lib/lockdep/lockdep_states.h b/tools/lib/lockdep/lockdep_states.h new file mode 100644 index 00000000000..248d235efda --- /dev/null +++ b/tools/lib/lockdep/lockdep_states.h @@ -0,0 +1 @@ +#include "../../../kernel/locking/lockdep_states.h" diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c new file mode 100644 index 00000000000..6f803609e49 --- /dev/null +++ b/tools/lib/lockdep/preload.c @@ -0,0 +1,445 @@ +#define _GNU_SOURCE +#include <pthread.h> +#include <stdio.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <sysexits.h> +#include "include/liblockdep/mutex.h" +#include "../../../include/linux/rbtree.h" + +/** + * struct lock_lookup - liblockdep's view of a single unique lock + * @orig: pointer to the original pthread lock, used for lookups + * @dep_map: lockdep's dep_map structure + * @key: lockdep's key structure + * @node: rb-tree node used to store the lock in a global tree + * @name: a unique name for the lock + */ +struct lock_lookup { +	void *orig; /* Original pthread lock, used for lookups */ +	struct lockdep_map dep_map; /* Since all locks are dynamic, we need +				     * a dep_map and a key for each lock */ +	/* +	 * Wait, there's no support for key classes? Yup :( +	 * Most big projects wrap the pthread api with their own calls to +	 * be compatible with different locking methods. This means that +	 * "classes" will be brokes since the function that creates all +	 * locks will point to a generic locking function instead of the +	 * actual code that wants to do the locking. +	 */ +	struct lock_class_key key; +	struct rb_node node; +#define LIBLOCKDEP_MAX_LOCK_NAME 22 +	char name[LIBLOCKDEP_MAX_LOCK_NAME]; +}; + +/* This is where we store our locks */ +static struct rb_root locks = RB_ROOT; +static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER; + +/* pthread mutex API */ + +#ifdef __GLIBC__ +extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +extern int __pthread_mutex_lock(pthread_mutex_t *mutex); +extern int __pthread_mutex_trylock(pthread_mutex_t *mutex); +extern int __pthread_mutex_unlock(pthread_mutex_t *mutex); +extern int __pthread_mutex_destroy(pthread_mutex_t *mutex); +#else +#define __pthread_mutex_init	NULL +#define __pthread_mutex_lock	NULL +#define __pthread_mutex_trylock	NULL +#define __pthread_mutex_unlock	NULL +#define __pthread_mutex_destroy	NULL +#endif +static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex, +			const pthread_mutexattr_t *attr)	= __pthread_mutex_init; +static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex)	= __pthread_mutex_lock; +static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex)	= __pthread_mutex_trylock; +static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex)	= __pthread_mutex_unlock; +static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex)	= __pthread_mutex_destroy; + +/* pthread rwlock API */ + +#ifdef __GLIBC__ +extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); +extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock); +extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); +extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); +extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); +extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); +extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock); +#else +#define __pthread_rwlock_init		NULL +#define __pthread_rwlock_destroy	NULL +#define __pthread_rwlock_wrlock		NULL +#define __pthread_rwlock_trywrlock	NULL +#define __pthread_rwlock_rdlock		NULL +#define __pthread_rwlock_tryrdlock	NULL +#define __pthread_rwlock_unlock		NULL +#endif + +static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock, +			const pthread_rwlockattr_t *attr)		= __pthread_rwlock_init; +static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_destroy; +static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_rdlock; +static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_tryrdlock; +static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_trywrlock; +static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_wrlock; +static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock)	= __pthread_rwlock_unlock; + +enum { none, prepare, done, } __init_state; +static void init_preload(void); +static void try_init_preload(void) +{ +	if (__init_state != done) +		init_preload(); +} + +static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) +{ +	struct rb_node **node = &locks.rb_node; +	struct lock_lookup *l; + +	*parent = NULL; + +	while (*node) { +		l = rb_entry(*node, struct lock_lookup, node); + +		*parent = *node; +		if (lock < l->orig) +			node = &l->node.rb_left; +		else if (lock > l->orig) +			node = &l->node.rb_right; +		else +			return node; +	} + +	return node; +} + +#ifndef LIBLOCKDEP_STATIC_ENTRIES +#define LIBLOCKDEP_STATIC_ENTRIES	1024 +#endif + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; +static int __locks_nr; + +static inline bool is_static_lock(struct lock_lookup *lock) +{ +	return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks); +} + +static struct lock_lookup *alloc_lock(void) +{ +	if (__init_state != done) { +		/* +		 * Some programs attempt to initialize and use locks in their +		 * allocation path. This means that a call to malloc() would +		 * result in locks being initialized and locked. +		 * +		 * Why is it an issue for us? dlsym() below will try allocating +		 * to give us the original function. Since this allocation will +		 * result in a locking operations, we have to let pthread deal +		 * with it, but we can't! we don't have the pointer to the +		 * original API since we're inside dlsym() trying to get it +		 */ + +		int idx = __locks_nr++; +		if (idx >= ARRAY_SIZE(__locks)) { +			fprintf(stderr, +		"LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); +			exit(EX_UNAVAILABLE); +		} +		return __locks + idx; +	} + +	return malloc(sizeof(struct lock_lookup)); +} + +static inline void free_lock(struct lock_lookup *lock) +{ +	if (likely(!is_static_lock(lock))) +		free(lock); +} + +/** + * __get_lock - find or create a lock instance + * @lock: pointer to a pthread lock function + * + * Try to find an existing lock in the rbtree using the provided pointer. If + * one wasn't found - create it. + */ +static struct lock_lookup *__get_lock(void *lock) +{ +	struct rb_node **node, *parent; +	struct lock_lookup *l; + +	ll_pthread_rwlock_rdlock(&locks_rwlock); +	node = __get_lock_node(lock, &parent); +	ll_pthread_rwlock_unlock(&locks_rwlock); +	if (*node) { +		return rb_entry(*node, struct lock_lookup, node); +	} + +	/* We didn't find the lock, let's create it */ +	l = alloc_lock(); +	if (l == NULL) +		return NULL; + +	l->orig = lock; +	/* +	 * Currently the name of the lock is the ptr value of the pthread lock, +	 * while not optimal, it makes debugging a bit easier. +	 * +	 * TODO: Get the real name of the lock using libdwarf +	 */ +	sprintf(l->name, "%p", lock); +	lockdep_init_map(&l->dep_map, l->name, &l->key, 0); + +	ll_pthread_rwlock_wrlock(&locks_rwlock); +	/* This might have changed since the last time we fetched it */ +	node = __get_lock_node(lock, &parent); +	rb_link_node(&l->node, parent, node); +	rb_insert_color(&l->node, &locks); +	ll_pthread_rwlock_unlock(&locks_rwlock); + +	return l; +} + +static void __del_lock(struct lock_lookup *lock) +{ +	ll_pthread_rwlock_wrlock(&locks_rwlock); +	rb_erase(&lock->node, &locks); +	ll_pthread_rwlock_unlock(&locks_rwlock); +	free_lock(lock); +} + +int pthread_mutex_init(pthread_mutex_t *mutex, +			const pthread_mutexattr_t *attr) +{ +	int r; + +	/* +	 * We keep trying to init our preload module because there might be +	 * code in init sections that tries to touch locks before we are +	 * initialized, in that case we'll need to manually call preload +	 * to get us going. +	 * +	 * Funny enough, kernel's lockdep had the same issue, and used +	 * (almost) the same solution. See look_up_lock_class() in +	 * kernel/locking/lockdep.c for details. +	 */ +	try_init_preload(); + +	r = ll_pthread_mutex_init(mutex, attr); +	if (r == 0) +		/* +		 * We do a dummy initialization here so that lockdep could +		 * warn us if something fishy is going on - such as +		 * initializing a held lock. +		 */ +		__get_lock(mutex); + +	return r; +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ +	int r; + +	try_init_preload(); + +	lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, +			(unsigned long)_RET_IP_); +	/* +	 * Here's the thing with pthread mutexes: unlike the kernel variant, +	 * they can fail. +	 * +	 * This means that the behaviour here is a bit different from what's +	 * going on in the kernel: there we just tell lockdep that we took the +	 * lock before actually taking it, but here we must deal with the case +	 * that locking failed. +	 * +	 * To do that we'll "release" the lock if locking failed - this way +	 * we'll get lockdep doing the correct checks when we try to take +	 * the lock, and if that fails - we'll be back to the correct +	 * state by releasing it. +	 */ +	r = ll_pthread_mutex_lock(mutex); +	if (r) +		lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) +{ +	int r; + +	try_init_preload(); + +	lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); +	r = ll_pthread_mutex_trylock(mutex); +	if (r) +		lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ +	int r; + +	try_init_preload(); + +	lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); +	/* +	 * Just like taking a lock, only in reverse! +	 * +	 * If we fail releasing the lock, tell lockdep we're holding it again. +	 */ +	r = ll_pthread_mutex_unlock(mutex); +	if (r) +		lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ +	try_init_preload(); + +	/* +	 * Let's see if we're releasing a lock that's held. +	 * +	 * TODO: Hook into free() and add that check there as well. +	 */ +	debug_check_no_locks_freed(mutex, mutex + sizeof(*mutex)); +	__del_lock(__get_lock(mutex)); +	return ll_pthread_mutex_destroy(mutex); +} + +/* This is the rwlock part, very similar to what happened with mutex above */ +int pthread_rwlock_init(pthread_rwlock_t *rwlock, +			const pthread_rwlockattr_t *attr) +{ +	int r; + +	try_init_preload(); + +	r = ll_pthread_rwlock_init(rwlock, attr); +	if (r == 0) +		__get_lock(rwlock); + +	return r; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) +{ +	try_init_preload(); + +	debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock)); +	__del_lock(__get_lock(rwlock)); +	return ll_pthread_rwlock_destroy(rwlock); +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ +	int r; + +        init_preload(); + +	lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_); +	r = ll_pthread_rwlock_rdlock(rwlock); +	if (r) +		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ +	int r; + +        init_preload(); + +	lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_); +	r = ll_pthread_rwlock_tryrdlock(rwlock); +	if (r) +		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ +	int r; + +        init_preload(); + +	lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_); +	r = ll_pthread_rwlock_trywrlock(rwlock); +	if (r) +                lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ +	int r; + +        init_preload(); + +	lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); +	r = ll_pthread_rwlock_wrlock(rwlock); +	if (r) +		lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); + +	return r; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ +	int r; + +        init_preload(); + +	lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); +	r = ll_pthread_rwlock_unlock(rwlock); +	if (r) +		lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_); + +	return r; +} + +__attribute__((constructor)) static void init_preload(void) +{ +	if (__init_state == done) +		return; + +#ifndef __GLIBC__ +	__init_state = prepare; + +	ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init"); +	ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock"); +	ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock"); +	ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); +	ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); + +	ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init"); +	ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy"); +	ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock"); +	ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock"); +	ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock"); +	ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock"); +	ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); +#endif + +	lockdep_init(); + +	__init_state = done; +} diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c new file mode 100644 index 00000000000..f7f43033c8b --- /dev/null +++ b/tools/lib/lockdep/rbtree.c @@ -0,0 +1 @@ +#include "../../../lib/rbtree.c" diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh new file mode 100755 index 00000000000..5334ad9d39b --- /dev/null +++ b/tools/lib/lockdep/run_tests.sh @@ -0,0 +1,27 @@ +#! /bin/bash + +make &> /dev/null + +for i in `ls tests/*.c`; do +	testname=$(basename -s .c "$i") +	gcc -o tests/$testname -pthread -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null +	echo -ne "$testname... " +	if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then +		echo "PASSED!" +	else +		echo "FAILED!" +	fi +	rm tests/$testname +done + +for i in `ls tests/*.c`; do +	testname=$(basename -s .c "$i") +	gcc -o tests/$testname -pthread -lpthread -Iinclude $i &> /dev/null +	echo -ne "(PRELOAD) $testname... " +	if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then +		echo "PASSED!" +	else +		echo "FAILED!" +	fi +	rm tests/$testname +done diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c new file mode 100644 index 00000000000..0f782ff404a --- /dev/null +++ b/tools/lib/lockdep/tests/AA.c @@ -0,0 +1,13 @@ +#include <liblockdep/mutex.h> + +void main(void) +{ +	pthread_mutex_t a, b; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); + +	pthread_mutex_lock(&a); +	pthread_mutex_lock(&b); +	pthread_mutex_lock(&a); +} diff --git a/tools/lib/lockdep/tests/ABBA.c b/tools/lib/lockdep/tests/ABBA.c new file mode 100644 index 00000000000..07f0e29d548 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBA.c @@ -0,0 +1,13 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(b, a); +} diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c new file mode 100644 index 00000000000..843db09ac66 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCA.c @@ -0,0 +1,15 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b, c; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); +	pthread_mutex_init(&c, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(b, c); +	LOCK_UNLOCK_2(c, a); +} diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c new file mode 100644 index 00000000000..33620e268f8 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCDDA.c @@ -0,0 +1,17 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b, c, d; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); +	pthread_mutex_init(&c, NULL); +	pthread_mutex_init(&d, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(b, c); +	LOCK_UNLOCK_2(c, d); +	LOCK_UNLOCK_2(d, a); +} diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c new file mode 100644 index 00000000000..3fee51e3a68 --- /dev/null +++ b/tools/lib/lockdep/tests/ABCABC.c @@ -0,0 +1,15 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b, c; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); +	pthread_mutex_init(&c, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(c, a); +	LOCK_UNLOCK_2(b, c); +} diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c new file mode 100644 index 00000000000..427ba562c75 --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBCDA.c @@ -0,0 +1,17 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b, c, d; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); +	pthread_mutex_init(&c, NULL); +	pthread_mutex_init(&d, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(c, d); +	LOCK_UNLOCK_2(b, c); +	LOCK_UNLOCK_2(d, a); +} diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c new file mode 100644 index 00000000000..680c6cf3e91 --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBDDA.c @@ -0,0 +1,17 @@ +#include <liblockdep/mutex.h> +#include "common.h" + +void main(void) +{ +	pthread_mutex_t a, b, c, d; + +	pthread_mutex_init(&a, NULL); +	pthread_mutex_init(&b, NULL); +	pthread_mutex_init(&c, NULL); +	pthread_mutex_init(&d, NULL); + +	LOCK_UNLOCK_2(a, b); +	LOCK_UNLOCK_2(c, d); +	LOCK_UNLOCK_2(b, d); +	LOCK_UNLOCK_2(d, a); +} diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c new file mode 100644 index 00000000000..d44f77d7102 --- /dev/null +++ b/tools/lib/lockdep/tests/WW.c @@ -0,0 +1,13 @@ +#include <liblockdep/rwlock.h> + +void main(void) +{ +	pthread_rwlock_t a, b; + +	pthread_rwlock_init(&a, NULL); +	pthread_rwlock_init(&b, NULL); + +	pthread_rwlock_wrlock(&a); +	pthread_rwlock_rdlock(&b); +	pthread_rwlock_wrlock(&a); +} diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h new file mode 100644 index 00000000000..d89e94d47d8 --- /dev/null +++ b/tools/lib/lockdep/tests/common.h @@ -0,0 +1,12 @@ +#ifndef _LIBLOCKDEP_TEST_COMMON_H +#define _LIBLOCKDEP_TEST_COMMON_H + +#define LOCK_UNLOCK_2(a, b)			\ +	do {					\ +		pthread_mutex_lock(&(a));	\ +		pthread_mutex_lock(&(b));	\ +		pthread_mutex_unlock(&(b));	\ +		pthread_mutex_unlock(&(a));	\ +	} while(0) + +#endif diff --git a/tools/lib/lockdep/tests/unlock_balance.c b/tools/lib/lockdep/tests/unlock_balance.c new file mode 100644 index 00000000000..0bc62de686f --- /dev/null +++ b/tools/lib/lockdep/tests/unlock_balance.c @@ -0,0 +1,12 @@ +#include <liblockdep/mutex.h> + +void main(void) +{ +	pthread_mutex_t a; + +	pthread_mutex_init(&a, NULL); + +	pthread_mutex_lock(&a); +	pthread_mutex_unlock(&a); +	pthread_mutex_unlock(&a); +} diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h new file mode 100644 index 00000000000..d82b170bb21 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hash.h @@ -0,0 +1,6 @@ +#ifndef __ASM_GENERIC_HASH_H +#define __ASM_GENERIC_HASH_H + +/* Stub */ + +#endif /* __ASM_GENERIC_HASH_H */ diff --git a/tools/lib/lockdep/uinclude/asm/hweight.h b/tools/lib/lockdep/uinclude/asm/hweight.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hweight.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/asm/sections.h b/tools/lib/lockdep/uinclude/asm/sections.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/sections.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/bitops.h b/tools/lib/lockdep/uinclude/linux/bitops.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/bitops.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h new file mode 100644 index 00000000000..7ac838a1f19 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/compiler.h @@ -0,0 +1,7 @@ +#ifndef _LIBLOCKDEP_LINUX_COMPILER_H_ +#define _LIBLOCKDEP_LINUX_COMPILER_H_ + +#define __used		__attribute__((__unused__)) +#define unlikely + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/debug_locks.h b/tools/lib/lockdep/uinclude/linux/debug_locks.h new file mode 100644 index 00000000000..f38eb64df79 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/debug_locks.h @@ -0,0 +1,12 @@ +#ifndef _LIBLOCKDEP_DEBUG_LOCKS_H_ +#define _LIBLOCKDEP_DEBUG_LOCKS_H_ + +#include <stddef.h> +#include <linux/compiler.h> + +#define DEBUG_LOCKS_WARN_ON(x) (x) + +extern bool debug_locks; +extern bool debug_locks_silent; + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/delay.h b/tools/lib/lockdep/uinclude/linux/delay.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/delay.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/ftrace.h b/tools/lib/lockdep/uinclude/linux/ftrace.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/ftrace.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/gfp.h b/tools/lib/lockdep/uinclude/linux/gfp.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/gfp.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/hardirq.h b/tools/lib/lockdep/uinclude/linux/hardirq.h new file mode 100644 index 00000000000..c8f3f8f5872 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hardirq.h @@ -0,0 +1,11 @@ +#ifndef _LIBLOCKDEP_LINUX_HARDIRQ_H_ +#define _LIBLOCKDEP_LINUX_HARDIRQ_H_ + +#define SOFTIRQ_BITS	0UL +#define HARDIRQ_BITS	0UL +#define SOFTIRQ_SHIFT	0UL +#define HARDIRQ_SHIFT	0UL +#define hardirq_count()	0UL +#define softirq_count()	0UL + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/hash.h b/tools/lib/lockdep/uinclude/linux/hash.h new file mode 100644 index 00000000000..0f8479858dc --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hash.h @@ -0,0 +1 @@ +#include "../../../include/linux/hash.h" diff --git a/tools/lib/lockdep/uinclude/linux/interrupt.h b/tools/lib/lockdep/uinclude/linux/interrupt.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/interrupt.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/irqflags.h b/tools/lib/lockdep/uinclude/linux/irqflags.h new file mode 100644 index 00000000000..6cc296f0fad --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/irqflags.h @@ -0,0 +1,38 @@ +#ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ +#define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ + +# define trace_hardirq_context(p)	0 +# define trace_softirq_context(p)	0 +# define trace_hardirqs_enabled(p)	0 +# define trace_softirqs_enabled(p)	0 +# define trace_hardirq_enter()		do { } while (0) +# define trace_hardirq_exit()		do { } while (0) +# define lockdep_softirq_enter()	do { } while (0) +# define lockdep_softirq_exit()		do { } while (0) +# define INIT_TRACE_IRQFLAGS + +# define stop_critical_timings() do { } while (0) +# define start_critical_timings() do { } while (0) + +#define raw_local_irq_disable() do { } while (0) +#define raw_local_irq_enable() do { } while (0) +#define raw_local_irq_save(flags) ((flags) = 0) +#define raw_local_irq_restore(flags) do { } while (0) +#define raw_local_save_flags(flags) ((flags) = 0) +#define raw_irqs_disabled_flags(flags) do { } while (0) +#define raw_irqs_disabled() 0 +#define raw_safe_halt() + +#define local_irq_enable() do { } while (0) +#define local_irq_disable() do { } while (0) +#define local_irq_save(flags) ((flags) = 0) +#define local_irq_restore(flags) do { } while (0) +#define local_save_flags(flags)	((flags) = 0) +#define irqs_disabled() (1) +#define irqs_disabled_flags(flags) (0) +#define safe_halt() do { } while (0) + +#define trace_lock_release(x, y) +#define trace_lock_acquire(a, b, c, d, e, f, g) + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/kallsyms.h b/tools/lib/lockdep/uinclude/linux/kallsyms.h new file mode 100644 index 00000000000..b0f2dbdf1a1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kallsyms.h @@ -0,0 +1,32 @@ +#ifndef _LIBLOCKDEP_LINUX_KALLSYMS_H_ +#define _LIBLOCKDEP_LINUX_KALLSYMS_H_ + +#include <linux/kernel.h> +#include <stdio.h> + +#define KSYM_NAME_LEN 128 + +struct module; + +static inline const char *kallsyms_lookup(unsigned long addr, +					  unsigned long *symbolsize, +					  unsigned long *offset, +					  char **modname, char *namebuf) +{ +	return NULL; +} + +#include <execinfo.h> +#include <stdlib.h> +static inline void print_ip_sym(unsigned long ip) +{ +	char **name; + +	name = backtrace_symbols((void **)&ip, 1); + +	printf("%s\n", *name); + +	free(name); +} + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/kern_levels.h b/tools/lib/lockdep/uinclude/linux/kern_levels.h new file mode 100644 index 00000000000..3b9bade2869 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kern_levels.h @@ -0,0 +1,25 @@ +#ifndef __KERN_LEVELS_H__ +#define __KERN_LEVELS_H__ + +#define KERN_SOH	""		/* ASCII Start Of Header */ +#define KERN_SOH_ASCII	'' + +#define KERN_EMERG	KERN_SOH ""	/* system is unusable */ +#define KERN_ALERT	KERN_SOH ""	/* action must be taken immediately */ +#define KERN_CRIT	KERN_SOH ""	/* critical conditions */ +#define KERN_ERR	KERN_SOH ""	/* error conditions */ +#define KERN_WARNING	KERN_SOH ""	/* warning conditions */ +#define KERN_NOTICE	KERN_SOH ""	/* normal but significant condition */ +#define KERN_INFO	KERN_SOH ""	/* informational */ +#define KERN_DEBUG	KERN_SOH ""	/* debug-level messages */ + +#define KERN_DEFAULT	KERN_SOH ""	/* the default kernel loglevel */ + +/* + * Annotation for a "continued" line of log printout (only done after a + * line that had no enclosing \n). Only to be used by core/arch code + * during early bootup (a continued line is not SMP-safe otherwise). + */ +#define KERN_CONT	"" + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h new file mode 100644 index 00000000000..a11e3c357be --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kernel.h @@ -0,0 +1,44 @@ +#ifndef _LIBLOCKDEP_LINUX_KERNEL_H_ +#define _LIBLOCKDEP_LINUX_KERNEL_H_ + +#include <linux/export.h> +#include <linux/types.h> +#include <linux/rcu.h> +#include <linux/hardirq.h> +#include <linux/kern_levels.h> + +#ifndef container_of +#define container_of(ptr, type, member) ({			\ +	const typeof(((type *)0)->member) * __mptr = (ptr);	\ +	(type *)((char *)__mptr - offsetof(type, member)); }) +#endif + +#define max(x, y) ({				\ +	typeof(x) _max1 = (x);			\ +	typeof(y) _max2 = (y);			\ +	(void) (&_max1 == &_max2);		\ +	_max1 > _max2 ? _max1 : _max2; }) + +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +#define WARN_ON(x) (x) +#define WARN_ON_ONCE(x) (x) +#define likely(x) (x) +#define WARN(x, y, z) (x) +#define uninitialized_var(x) x +#define __init +#define noinline +#define list_add_tail_rcu list_add_tail + +#ifndef CALLER_ADDR0 +#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +#endif + +#ifndef _RET_IP_ +#define _RET_IP_ CALLER_ADDR0 +#endif + +#ifndef _THIS_IP_ +#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) +#endif + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/kmemcheck.h b/tools/lib/lockdep/uinclude/linux/kmemcheck.h new file mode 100644 index 00000000000..94d598bc6ab --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kmemcheck.h @@ -0,0 +1,8 @@ +#ifndef _LIBLOCKDEP_LINUX_KMEMCHECK_H_ +#define _LIBLOCKDEP_LINUX_KMEMCHECK_H_ + +static inline void kmemcheck_mark_initialized(void *address, unsigned int n) +{ +} + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/linkage.h b/tools/lib/lockdep/uinclude/linux/linkage.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/linkage.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/list.h b/tools/lib/lockdep/uinclude/linux/list.h new file mode 100644 index 00000000000..6e9ef31ed82 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/list.h @@ -0,0 +1 @@ +#include "../../../include/linux/list.h" diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h new file mode 100644 index 00000000000..c1552c28507 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h @@ -0,0 +1,58 @@ +#ifndef _LIBLOCKDEP_LOCKDEP_H_ +#define _LIBLOCKDEP_LOCKDEP_H_ + +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <string.h> +#include <limits.h> +#include <linux/utsname.h> + + +#define MAX_LOCK_DEPTH 2000UL + +#define asmlinkage +#define __visible + +#include "../../../include/linux/lockdep.h" + +struct task_struct { +	u64 curr_chain_key; +	int lockdep_depth; +	unsigned int lockdep_recursion; +	struct held_lock held_locks[MAX_LOCK_DEPTH]; +	gfp_t lockdep_reclaim_gfp; +	int pid; +	char comm[17]; +}; + +extern struct task_struct *__curr(void); + +#define current (__curr()) + +#define debug_locks_off() 1 +#define task_pid_nr(tsk) ((tsk)->pid) + +#define KSYM_NAME_LEN 128 +#define printk printf + +#define list_del_rcu list_del + +#define atomic_t unsigned long +#define atomic_inc(x) ((*(x))++) + +static struct new_utsname *init_utsname(void) +{ +	static struct new_utsname n = (struct new_utsname) { +		.release = "liblockdep", +		.version = LIBLOCKDEP_VERSION, +	}; + +	return &n; +} + +#define print_tainted() "" +#define static_obj(x) 1 + +#define debug_show_all_locks() + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/module.h b/tools/lib/lockdep/uinclude/linux/module.h new file mode 100644 index 00000000000..09c7a7be8cc --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/module.h @@ -0,0 +1,6 @@ +#ifndef _LIBLOCKDEP_LINUX_MODULE_H_ +#define _LIBLOCKDEP_LINUX_MODULE_H_ + +#define module_param(name, type, perm) + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/mutex.h b/tools/lib/lockdep/uinclude/linux/mutex.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/mutex.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/poison.h b/tools/lib/lockdep/uinclude/linux/poison.h new file mode 100644 index 00000000000..0c27bdf1423 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/poison.h @@ -0,0 +1 @@ +#include "../../../include/linux/poison.h" diff --git a/tools/lib/lockdep/uinclude/linux/prefetch.h b/tools/lib/lockdep/uinclude/linux/prefetch.h new file mode 100644 index 00000000000..d73fe6f850a --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/prefetch.h @@ -0,0 +1,6 @@ +#ifndef _LIBLOCKDEP_LINUX_PREFETCH_H_ +#define _LIBLOCKDEP_LINUX_PREFETCH_H + +static inline void prefetch(void *a __attribute__((unused))) { } + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/proc_fs.h b/tools/lib/lockdep/uinclude/linux/proc_fs.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/proc_fs.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/rbtree.h b/tools/lib/lockdep/uinclude/linux/rbtree.h new file mode 100644 index 00000000000..965901db486 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree.h @@ -0,0 +1 @@ +#include "../../../include/linux/rbtree.h" diff --git a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h new file mode 100644 index 00000000000..c3759477379 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h @@ -0,0 +1,2 @@ +#define __always_inline +#include "../../../include/linux/rbtree_augmented.h" diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/lib/lockdep/uinclude/linux/rcu.h new file mode 100644 index 00000000000..042ee8e463c --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rcu.h @@ -0,0 +1,21 @@ +#ifndef _LIBLOCKDEP_RCU_H_ +#define _LIBLOCKDEP_RCU_H_ + +int rcu_scheduler_active; + +static inline int rcu_lockdep_current_cpu_online(void) +{ +	return 1; +} + +static inline int rcu_is_cpu_idle(void) +{ +	return 1; +} + +static inline bool rcu_is_watching(void) +{ +	return false; +} + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/seq_file.h b/tools/lib/lockdep/uinclude/linux/seq_file.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/seq_file.h @@ -0,0 +1,3 @@ + +/* empty file */ + diff --git a/tools/lib/lockdep/uinclude/linux/spinlock.h b/tools/lib/lockdep/uinclude/linux/spinlock.h new file mode 100644 index 00000000000..68c1aa2bcba --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/spinlock.h @@ -0,0 +1,25 @@ +#ifndef _LIBLOCKDEP_SPINLOCK_H_ +#define _LIBLOCKDEP_SPINLOCK_H_ + +#include <pthread.h> +#include <stdbool.h> + +#define arch_spinlock_t pthread_mutex_t +#define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER + +static inline void arch_spin_lock(arch_spinlock_t *mutex) +{ +	pthread_mutex_lock(mutex); +} + +static inline void arch_spin_unlock(arch_spinlock_t *mutex) +{ +	pthread_mutex_unlock(mutex); +} + +static inline bool arch_spin_is_locked(arch_spinlock_t *mutex) +{ +	return true; +} + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/stacktrace.h b/tools/lib/lockdep/uinclude/linux/stacktrace.h new file mode 100644 index 00000000000..39aecc6b19d --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stacktrace.h @@ -0,0 +1,32 @@ +#ifndef _LIBLOCKDEP_LINUX_STACKTRACE_H_ +#define _LIBLOCKDEP_LINUX_STACKTRACE_H_ + +#include <execinfo.h> + +struct stack_trace { +	unsigned int nr_entries, max_entries; +	unsigned long *entries; +	int skip; +}; + +static inline void print_stack_trace(struct stack_trace *trace, int spaces) +{ +	backtrace_symbols_fd((void **)trace->entries, trace->nr_entries, 1); +} + +#define save_stack_trace(trace)	\ +	((trace)->nr_entries =	\ +		backtrace((void **)(trace)->entries, (trace)->max_entries)) + +static inline int dump_stack(void) +{ +	void *array[64]; +	size_t size; + +	size = backtrace(array, 64); +	backtrace_symbols_fd(array, size, 1); + +	return 0; +} + +#endif diff --git a/tools/lib/lockdep/uinclude/linux/stringify.h b/tools/lib/lockdep/uinclude/linux/stringify.h new file mode 100644 index 00000000000..05dfcd1ac11 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stringify.h @@ -0,0 +1,7 @@ +#ifndef _LIBLOCKDEP_LINUX_STRINGIFY_H_ +#define _LIBLOCKDEP_LINUX_STRINGIFY_H_ + +#define __stringify_1(x...)	#x +#define __stringify(x...)	__stringify_1(x) + +#endif diff --git a/tools/lib/lockdep/uinclude/trace/events/lock.h b/tools/lib/lockdep/uinclude/trace/events/lock.h new file mode 100644 index 00000000000..fab00ff936d --- /dev/null +++ b/tools/lib/lockdep/uinclude/trace/events/lock.h @@ -0,0 +1,3 @@ + +/* empty file */ +  | 
