summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-09-07 22:38:03 +0200
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-09-07 22:38:03 +0200
commit667b7a7c09f6fe86c9e72515afcc654cf3366c38 (patch)
tree4287ff835bd69af06aa270992ad1709dfe79bf77
parentaf7fcb19e21809ee6bdeefd997a853cebe316144 (diff)
downloadlatrace-667b7a7c09f6fe86c9e72515afcc654cf3366c38.tar.gz
latrace-667b7a7c09f6fe86c9e72515afcc654cf3366c38.tar.xz
latrace-667b7a7c09f6fe86c9e72515afcc654cf3366c38.zip
adding stack limits dynamic check
-rw-r--r--ChangeLog5
-rw-r--r--TODO1
-rw-r--r--doc/latrace.txt3
-rw-r--r--src/Makefile3
-rw-r--r--src/audit.c3
-rw-r--r--src/audit.h3
-rw-r--r--src/config.c21
-rw-r--r--src/config.h4
-rw-r--r--src/stack.c114
9 files changed, 148 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 9a7a4dd..e8a6c12 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2010-09-07 Jiri Olsa <olsajiri@gmail.com>
+ * adding stack limits dynamic check
+ - based on proposal from Akos Pasztory
+ - enabled by default, disable by new '-Y' option
+
2010-08-05 Jiri Olsa <olsajiri@gmail.com>
* changed config file magic defines
* separate arguments display code, so it could be
diff --git a/TODO b/TODO
index 47d02ac..0aef70a 100644
--- a/TODO
+++ b/TODO
@@ -6,6 +6,7 @@ olsajiri@gmail.com
for 0.5.10
- testing/fixing bugs
+ - make automated tests
for 0.6
- config - arrays in structures
diff --git a/doc/latrace.txt b/doc/latrace.txt
index 492561b..20be159 100644
--- a/doc/latrace.txt
+++ b/doc/latrace.txt
@@ -78,6 +78,9 @@ OPTIONS
*-y, --framesize number*::
framesize for storing the stack before pltexit (default 100)
+*-Y, --not-framesize-check*::
+ disable framesize check
+
*-I, --no-indent-sym*::
do no indent symbols based on the their stack depth
diff --git a/src/Makefile b/src/Makefile
index cada828..796028a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -27,7 +27,8 @@ AUDIT_OBJS=\
src/audit-init.o \
src/fifo.o \
src/output.o \
- src/objsearch.o
+ src/objsearch.o \
+ src/stack.o
ifeq ($(CONFIG_ARCH_HAVE_ARGS),y)
AUDIT_OBJS+=\
diff --git a/src/audit.c b/src/audit.c
index bba7e9f..2a97b75 100644
--- a/src/audit.c
+++ b/src/audit.c
@@ -294,7 +294,8 @@ pltenter(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
} while(0);
- *framesizep = lt_sh(&cfg, framesize);
+ *framesizep = lt_stack_framesize(&cfg, regs);
+
return sym->st_value;
}
diff --git a/src/audit.h b/src/audit.h
index 1b7d20f..2633944 100644
--- a/src/audit.h
+++ b/src/audit.h
@@ -29,18 +29,21 @@
# define pltenter la_i86_gnu_pltenter
# define pltexit la_i86_gnu_pltexit
# define La_regs La_i86_regs
+# define sp_reg lr_esp
# define La_retval La_i86_retval
# define int_retval lrv_eax
#elif defined __x86_64__
# define pltenter la_x86_64_gnu_pltenter
# define pltexit la_x86_64_gnu_pltexit
# define La_regs La_x86_64_regs
+# define sp_reg lr_rsp
# define La_retval La_x86_64_retval
# define int_retval lrv_rax
#elif defined __arm__
# define pltenter la_arm_gnu_pltenter
# define pltexit la_arm_gnu_pltexit
# define La_regs La_arm_regs
+# define sp_reg lr_sp
# define La_retval La_arm_retval
# define int_retval lrv_reg[0]
#elif defined __powerpc__ && __WORDSIZE == 32
diff --git a/src/config.c b/src/config.c
index 4b92b5b..18c07ba 100644
--- a/src/config.c
+++ b/src/config.c
@@ -51,6 +51,7 @@ static void usage()
#endif
printf("\n");
printf(" -y, --framesize number framesize for storing the stack before pltexit (default 1000)\n");
+ printf(" -Y, --not-framesize-check disable framesize check\n");
printf(" -F, --not-follow-fork dont follow fork calls - childs\n");
printf(" -E, --not-follow-exec dont follow exec calls\n");
printf("\n");
@@ -111,12 +112,13 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
cfg->sh = &cfg->sh_storage;
/* default values settings */
- lt_sh(cfg, magic) = LT_CONFIG_MAGIC;
- lt_sh(cfg, framesize) = 1000;
- lt_sh(cfg, fout) = stdout;
- lt_sh(cfg, indent_sym) = 1;
- lt_sh(cfg, indent_size) = 2;
- lt_sh(cfg, args_maxlen) = LR_ARGS_MAXLEN;
+ lt_sh(cfg, magic) = LT_CONFIG_MAGIC;
+ lt_sh(cfg, framesize) = 1000;
+ lt_sh(cfg, framesize_check) = 1;
+ lt_sh(cfg, fout) = stdout;
+ lt_sh(cfg, indent_sym) = 1;
+ lt_sh(cfg, indent_size) = 2;
+ lt_sh(cfg, args_maxlen) = LR_ARGS_MAXLEN;
lt_sh(cfg, args_detail_maxlen) = LR_ARGS_DETAIL_MAXLEN;
cfg->csort = LT_CSORT_CALL;
@@ -142,6 +144,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
{"enable-args", required_argument, 0, 'A'},
{"detail-args", required_argument, 0, 'D'},
{"framesize", required_argument, 0, 'y'},
+ {"not-framesize-check ", no_argument, 0, 'Y'},
{"lib-subst", required_argument, 0, 'L'},
{"verbose", no_argument, 0, 'v'},
{"hide-tid", no_argument, 0, 'T'},
@@ -154,7 +157,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "+s:l:t:f:vhi:BdISb:cC:y:L:po:a:ADVTFERq",
+ c = getopt_long(argc, argv, "+s:l:t:f:vhi:BdISb:cC:y:YL:po:a:ADVTFERq",
long_options, &option_index);
if (c == -1)
@@ -242,6 +245,10 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
lt_sh(cfg, framesize) = atoi(optarg);
break;
+ case 'Y':
+ lt_sh(cfg, framesize_check) = 0;
+ break;
+
case 'L':
if (strlen(optarg) > LT_SYMBOLS_MAXSIZE)
return -1;
diff --git a/src/config.h b/src/config.h
index 6213292..2a36c58 100644
--- a/src/config.h
+++ b/src/config.h
@@ -115,6 +115,7 @@ struct lt_config_shared {
int hide_tid;
int not_follow_exec;
int not_follow_fork;
+ int framesize_check;
unsigned int framesize;
/* for 'not_follow_fork' */
@@ -299,6 +300,9 @@ int lt_objsearch_init(struct lt_config_audit *cfg, char **ptr, int cnt);
char* lt_objsearch(struct lt_config_audit *cfg, const char *name,
uintptr_t *cookie, unsigned int flag);
+/* stack */
+int lt_stack_framesize(struct lt_config_audit *cfg, La_regs *regs);
+
#define PRINT(fmt, args...) \
do { \
char lpbuf[1024]; \
diff --git a/src/stack.c b/src/stack.c
new file mode 100644
index 0000000..ade5ef9
--- /dev/null
+++ b/src/stack.c
@@ -0,0 +1,114 @@
+
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "config.h"
+
+static __thread void *stack_start = NULL;
+static __thread void *stack_end = NULL;
+
+static unsigned long get_stack_size(struct lt_config_audit *cfg)
+{
+ static unsigned long stack_size = 0;
+ static struct rlimit rlim;
+
+ if (stack_size)
+ return stack_size;
+
+ if (getrlimit(RLIMIT_STACK, &rlim))
+ return 0;
+
+ PRINT_VERBOSE(cfg, 1, "stack size: %lx\n", rlim.rlim_cur);
+
+ return stack_size = rlim.rlim_cur;
+}
+
+/* find and update current stack boundaries */
+static int load_stack(struct lt_config_audit *cfg, void *sp)
+{
+ FILE *maps;
+ char line[128];
+ int found = 0;
+ void *start, *end;
+
+ maps = fopen("/proc/self/maps", "r");
+ if (!maps) {
+ PRINT_VERBOSE(cfg, 1, "failed to open maps: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+
+ while (!found && fgets(line, sizeof(line), maps)) {
+
+ if (1 != sscanf(line, "%*p-%p", &end))
+ continue;
+
+ /* FIXME
+ * what if the new stack is not GROWSDOWN?
+ * let's get the limit via RLIMIT_STACK,
+ * which should be ok for most cases now..
+ *
+ * it does not feel safe/complete, but probably better
+ * than nothing
+ */
+ start = end - get_stack_size(cfg);
+
+ found = ((start < sp) && (sp < end));
+
+ PRINT_VERBOSE(cfg, 1, "start %p, end %p, sp %p, in %d\n",
+ start, end, sp, found);
+ }
+
+ fclose(maps);
+
+ if (found) {
+ stack_start = start;
+ stack_end = end;
+ }
+
+ return found ? 0 : -1;
+}
+
+/* check the current stack pointer and check its boundaries */
+int lt_stack_framesize(struct lt_config_audit *cfg, La_regs *regs)
+{
+ void *sp_top, *sp_bottom;
+ void *sp = (void*) regs->sp_reg;
+ unsigned int framesize = lt_sh(cfg, framesize);
+
+ if (!lt_sh(cfg, framesize_check))
+ return framesize;
+
+ /* got here first time, or we are out of bounds */
+ if (!stack_start ||
+ (sp < stack_start || sp > stack_end)) {
+
+ /* we are screeeeeewed */
+ if (load_stack(cfg, sp))
+ return framesize;
+ }
+
+ /* FIXME what about stacks growing up.. arm might */
+ sp_top = sp + framesize;
+
+ if (sp_top > stack_end) {
+ framesize = stack_end - sp - 1;
+ PRINT_VERBOSE(cfg, 1,
+ "top reached, framesize changed to %lu\n",
+ framesize);
+ }
+
+ sp_bottom = sp - framesize;
+
+ if (sp_bottom < stack_start) {
+ framesize = sp - stack_start;
+ PRINT_VERBOSE(cfg, 1,
+ "bottom reached, framesize changed to %lu\n",
+ framesize);
+ }
+
+ return framesize;
+}