summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhunt <hunt>2005-05-26 07:43:25 +0000
committerhunt <hunt>2005-05-26 07:43:25 +0000
commitabedf3db3774b54ee4ed227e3ae69e55fb0ff76c (patch)
tree77bf164eda3f977ba0e964c92493ea8c248fb6f3
parent3750373a50833fcda902407e5b260cb8c5799ad6 (diff)
downloadsystemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.tar.gz
systemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.tar.xz
systemtap-steved-abedf3db3774b54ee4ed227e3ae69e55fb0ff76c.zip
2005-05-26 Martin Hunt <hunt@redhat.com>
* current.c (_stp_sprint_regs): Implement for i386. * sym.c (_stp_symbol_sprint): Check name before trying to print it. (_stp_symbol_print): Change to macro that calls _stp_symbol_sprint().
-rw-r--r--runtime/ChangeLog8
-rw-r--r--runtime/Doxyfile12
-rw-r--r--runtime/README93
-rw-r--r--runtime/alloc.c11
-rw-r--r--runtime/current.c94
-rw-r--r--runtime/map-keys.c4
-rw-r--r--runtime/map.h47
-rw-r--r--runtime/print.c12
-rw-r--r--runtime/stack.c284
-rw-r--r--runtime/string.c3
-rw-r--r--runtime/sym.c30
11 files changed, 290 insertions, 308 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 7519e701..8ae68395 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,11 @@
+2005-05-26 Martin Hunt <hunt@redhat.com>
+
+ * current.c (_stp_sprint_regs): Implement for i386.
+
+ * sym.c (_stp_symbol_sprint): Check name before trying to
+ print it.
+ (_stp_symbol_print): Change to macro that calls _stp_symbol_sprint().
+
2005-05-18 Martin Hunt <hunt@redhat.com>
* print.c: All functions except _stp_print_flush() are
diff --git a/runtime/Doxyfile b/runtime/Doxyfile
index 0e8d4f9e..cebc99b3 100644
--- a/runtime/Doxyfile
+++ b/runtime/Doxyfile
@@ -17,13 +17,13 @@
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
-PROJECT_NAME = SystemTap
+PROJECT_NAME = "SystemTap Runtime"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.2
+PROJECT_NUMBER = 0.5
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -432,7 +432,7 @@ INPUT =
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
-FILE_PATTERNS = *.c *.h README TODO
+FILE_PATTERNS = *.c *.h README TODO map.doc
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@@ -444,7 +444,7 @@ RECURSIVE = YES
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
-EXCLUDE = docs tests relayfs stpd
+EXCLUDE = docs tests relayfs stpd transport user
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
# that are symbolic links (a Unix filesystem feature) are excluded from the input.
@@ -927,7 +927,7 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
-MACRO_EXPANSION = YES
+MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
@@ -961,7 +961,7 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
-PREDEFINED =
+PREDEFINED = __i386__
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/runtime/README b/runtime/README
index e0e32a37..aecb3282 100644
--- a/runtime/README
+++ b/runtime/README
@@ -3,8 +3,8 @@
@section intro_sec Introduction
This document describes the implementation of the SystemTap Runtime. It is intended for developers
-of the SystemTap Language translator or, possibly TapSet authors. These functions are not directly
-available from the SystemTap Language.
+of the SystemTap Language translator, TapSet authors or kprobes programmers.
+These functions are not directly available from the SystemTap Language.
The SystemTap Runtime Library consists of all functions
and code fragments needed by the compiler/translator to
@@ -13,7 +13,7 @@ also include I/O code to transmit its output from the kernel to userspace.
In addition to the library, the runtime includes a SystemTap user-space daemon
(stpd). Stpd grabs data sent from the I/O code in the runtime and displays it
-and/or saves it to files. Stpd (or a script invoking it) will handle other issues like
+and/or saves it to files. Stpd will handle other issues like
inserting and removing modules.
Stpd and the I/O code make use of both relayfs and netlink for communication. For
@@ -22,41 +22,58 @@ kernels without relayfs builtin, it is provided as a standalone module under the
@section design_sec Design
@subsection impl_sec Implementation
The library is written in C and is really not a library but a collection of code
-That can be conditionally included in a modules. It may become a library later, but for now
-there are some advantages to being able to change the sizes of static items with simple #defines.
+that can be conditionally included in a modules. This allows for a high degree of
+customization and efficiency.
@subsection map_sec Maps (Associative Arrays)
-Maps are implemented as hash lists. It is not expected that users will
-attempt to collect so much data in kernel space that performance problems will require
-more complex solutions such as AVL trees.
-
-Maps are created with _stp_map_new(). Each map can hold only one type of
-data; int64, string, or statistics. Each element belonging to a map can have up to 2 keys
-and a value. Implemented key types are strings and longs.
+Maps are implemented as hash lists. In order to efficiently handle maps with up to five keys of any combination
+of int64s and strings, the functions to create maps, set keys, and set and get values
+are all generated as needed. To do this, you must simply do some defines and
+include the proper files. For example, if you need a map with 3 keys, int64, int64, and string
+that stores strings, you need to do
+@code
+#define KEY1_TYPE INT64
+#define KEY2_TYPE INT64
+#define KEY3_TYPE STRING
+#include "map-keys.c"
+
+#define VALUE_TYPE STRING
+#include "map-values.c"
+
+#include "map.c"
+@endcode
+
+In the above example, maps are created with _stp_map_new_int64_int64_str(). All the
+generated functions start with a base name (such as _stp_map_new) and add the key types separated
+by underscores.
+
+Each map can hold only one type of data; int64, string, or statistics. Each element belonging to a map can have up to
+5 keys and a value. Implemented key types are strings and int64.
To simplify the implementation, the functions to set the key and the functions to set the data are separated.
-That means we need only 4 functions to set the key and 3 functions to set the value.
-
-For example:
-\code
-/* create a map with a max of 100 elements */
-MAP mymap = map_new(100, INT64);
+The map remembers what the current key is.
+For example, to continue our previous example,
+@code
+/* create a map with a max of 100 elements containing strings */
+MAP mymap = _stp_map_new_int64_int64_str(100, STRING);
-/* mymap[birth year] = 2000 */
-map_key_str (mymap, "birth year");
-map_set_int64 (mymap, 2000);
-\endcode
+/* mymap[100, 300, "Ohio"] = "Columbus" */
+_stp_map_key_int64_int64_str (mymap, 100, 300, "Ohio");
+_stp_map_set_str (mymap, "Columbus");
+@endcode
All elements have a default value of 0 (or NULL). Elements are only saved to the map when their value is set
-to something nonzero. This means that querying for the existance of a key is inexpensive because
-no element is created, just a hash table lookup.
+to something nonzero.
+
+For good examples, see the runtime/tests/maps directory or the example probes.
@subsection list_sec Lists
-A list is a special map which has internally ascending long integer keys. Adding a value to
+A list is a special map which has internally ascending int64 keys. Adding a value to
a list does not require setting a key first. Create a list with _stp_list_new(). Add to it
with _stp_list_add_str() and _stp_list_add_int64(). Clear it with _stp_list_clear().
@subsection string_sec Strings
+
One of the biggest restrictions the library has is that it cannot allocate things like strings off the stack.
It is also not a good idea to dynamically allocate space for strings with kmalloc(). That leaves us with
statically allocated space for strings. This is what is implemented in the String module. Strings use
@@ -91,12 +108,26 @@ at the top of the module and all output will go over a netlink channel.
In the SystemTap language, we will provide some simple functions to control the buffering policy, which
will control the use of netlink and parameters to relayfs and stpd.
-@section status_sec Status
-@li Maps are implemented and tested. Histograms are not yet finished.
-@li Copy_From_User functions are done.
-@li If maps overflow or memory runs out for some reason, globals are set but nothing is done yet.
-I expect to implement a function to tell the system to either ignore it or unload the module and quit.
-@li Stack functions need much improvement.
+
+@section started Getting Started
+@verbatim
+>cd stp/src/runtime
+>cd stpd
+> make
+>cd ../relayfs
+> make
+> cd ../transport
+make
+> cd ../probes/shellsnoop
+> make
+> su
+> ./stp shellsnoop.ko
+@endverbatim
+
+When building the example probes, ignore the warnings about relayfs and
+_stp_ctrl_xxx functions undefined. These are in other modules.
+
+Hit ^C to exit from a probe.
@section probe_sec Example Probes
diff --git a/runtime/alloc.c b/runtime/alloc.c
index 9b348b27..480484d3 100644
--- a/runtime/alloc.c
+++ b/runtime/alloc.c
@@ -1,7 +1,6 @@
-#ifndef _ALLOC_C_
+#ifndef _ALLOC_C_ /* -*- linux-c -*- */
#define _ALLOC_C_
-/* -*- linux-c -*- */
/** @file alloc.c
* @brief Memory functions.
*/
@@ -11,9 +10,6 @@
* send a signal to the user-space daemon that will trigger the module to
* be unloaded.
* @todo Need error handling for memory allocations
- * @todo Some of these currently use kmalloc (GFP_ATOMIC) for
- * small allocations. This should be evaluated for performance
- * and stability.
* @{
*/
@@ -25,7 +21,7 @@ enum errorcode _stp_error = ERR_NONE;
* probe where the process cannot sleep.
* @param len Number of bytes to allocate.
* @return a valid pointer on success or NULL on failure.
- * @bug Currently uses kmalloc (GFP_ATOMIC).
+ * @note Not currently used by the runtime. Deprecate?
*/
void *_stp_alloc(size_t len)
@@ -41,7 +37,7 @@ void *_stp_alloc(size_t len)
* probe where the process cannot sleep.
* @param len Number of bytes to allocate.
* @return a valid pointer on success or NULL on failure.
- * @bug Currently uses kmalloc (GFP_ATOMIC).
+ * @note Not currently used by the runtime. Deprecate?
*/
void *_stp_calloc(size_t len)
@@ -71,6 +67,7 @@ void *_stp_valloc(size_t len)
/** Frees memory allocated by _stp_alloc or _stp_calloc.
* @param ptr pointer to memory to free
+ * @note Not currently used by the runtime. Deprecate?
*/
void _stp_free(void *ptr)
diff --git a/runtime/current.c b/runtime/current.c
index 618c9fc9..4485ef2c 100644
--- a/runtime/current.c
+++ b/runtime/current.c
@@ -1,7 +1,8 @@
-#ifndef _CURRENT_C_
+#ifndef _CURRENT_C_ /* -*- linux-c -*- */
#define _CURRENT_C_
-/* -*- linux-c -*- */
+#include "regs.h"
+
/** @file current.c
* @brief Functions to get the current state.
*/
@@ -14,48 +15,37 @@
/** Get the current return address.
* Call from kprobes (not jprobes).
* @param regs The pt_regs saved by the kprobe.
- * @return The return address saved in esp or rsp.
+ * @return The return address saved in the stack pointer.
* @note i386 and x86_64 only so far.
*/
unsigned long _stp_ret_addr (struct pt_regs *regs)
{
-#ifdef __x86_64__
- unsigned long *ra = (unsigned long *)regs->rsp;
-#else
- unsigned long *ra = (unsigned long *)regs->esp;
-#endif
- if (ra)
- return *ra;
- else
- return 0;
+ unsigned long *ra = (unsigned long *)REG_SP(regs);
+
+ if (ra)
+ return *ra;
+ else
+ return 0;
}
#ifdef __x86_64__
-#include <linux/utsname.h>
-
-void _stp_print_regs(struct pt_regs * regs)
+void _stp_sprint_regs(String str, struct pt_regs * regs)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
unsigned int fsindex,gsindex;
unsigned int ds,cs,es;
- _stp_printf("\n");
- // print_modules();
- _stp_printf("Pid: %d, comm: %.20s %s\n",
- current->pid, current->comm, system_utsname.release);
- _stp_printf("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
- _stp_symbol_print (regs->rip);
- _stp_printf("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
- _stp_printf("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+ _stp_sprintf(str,"RIP: %016lx\nRSP: %016lx EFLAGS: %08lx\n", regs->rip, regs->rsp, regs->eflags);
+ _stp_sprintf(str,"RAX: %016lx RBX: %016lx RCX: %016lx\n",
regs->rax, regs->rbx, regs->rcx);
- _stp_printf("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+ _stp_sprintf(str,"RDX: %016lx RSI: %016lx RDI: %016lx\n",
regs->rdx, regs->rsi, regs->rdi);
- _stp_printf("RBP: %016lx R08: %016lx R09: %016lx\n",
+ _stp_sprintf(str,"RBP: %016lx R08: %016lx R09: %016lx\n",
regs->rbp, regs->r8, regs->r9);
- _stp_printf("R10: %016lx R11: %016lx R12: %016lx\n",
+ _stp_sprintf(str,"R10: %016lx R11: %016lx R12: %016lx\n",
regs->r10, regs->r11, regs->r12);
- _stp_printf("R13: %016lx R14: %016lx R15: %016lx\n",
+ _stp_sprintf(str,"R13: %016lx R14: %016lx R15: %016lx\n",
regs->r13, regs->r14, regs->r15);
asm("movl %%ds,%0" : "=r" (ds));
@@ -73,15 +63,55 @@ void _stp_print_regs(struct pt_regs * regs)
asm("movq %%cr3, %0": "=r" (cr3));
asm("movq %%cr4, %0": "=r" (cr4));
- _stp_printf("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
+ _stp_sprintf(str,"FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
fs,fsindex,gs,gsindex,shadowgs);
- _stp_printf("CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0);
- _stp_printf("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
- _stp_print_flush();
+ _stp_sprintf(str,"CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0);
+ _stp_sprintf(str,"CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
}
-#endif /* __x86_64__ */
+#elif defined (__i386__)
+/** Write the registers to a string.
+ * @param regs The pt_regs saved by the kprobe.
+ * @note i386 and x86_64 only so far.
+ */
+void _stp_sprint_regs(String str, struct pt_regs * regs)
+{
+ unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+
+ _stp_sprintf (str, "EIP: %08lx\n",regs->eip);
+ _stp_sprintf (str, "ESP: %08lx\n",regs->esp);
+ _stp_sprintf (str, "EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+ regs->eax,regs->ebx,regs->ecx,regs->edx);
+ _stp_sprintf (str, "ESI: %08lx EDI: %08lx EBP: %08lx",
+ regs->esi, regs->edi, regs->ebp);
+ _stp_sprintf (str, " DS: %04x ES: %04x\n",
+ 0xffff & regs->xds,0xffff & regs->xes);
+
+ __asm__("movl %%cr0, %0": "=r" (cr0));
+ __asm__("movl %%cr2, %0": "=r" (cr2));
+ __asm__("movl %%cr3, %0": "=r" (cr3));
+ /* This could fault if %cr4 does not exist */
+ __asm__("1: movl %%cr4, %0 \n"
+ "2: \n"
+ ".section __ex_table,\"a\" \n"
+ ".long 1b,2b \n"
+ ".previous \n"
+ : "=r" (cr4): "0" (0));
+ _stp_sprintf (str, "CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
+}
+
+#endif
+
+/** Print the registers.
+ * @param regs The pt_regs saved by the kprobe.
+ * @note i386 and x86_64 only so far.
+ */
+#define _stp_print_regs(regs) \
+ { \
+ _stp_sprint_regs(_stp_stdout,regs); \
+ _stp_print_flush(); \
+ }
/** @} */
#endif /* _CURRENT_C_ */
diff --git a/runtime/map-keys.c b/runtime/map-keys.c
index b51118ec..f9221410 100644
--- a/runtime/map-keys.c
+++ b/runtime/map-keys.c
@@ -271,8 +271,8 @@ static unsigned int KEYSYM(hash) (ALLKEYSD(key))
return (unsigned int) hash;
}
-/* _stp_map_new_key1_key2 (num, STAT, LINEAR, start, end, interval) */
-/* _stp_map_new_key1_key2 (num, STAT, LOG, buckets) */
+/* _stp_map_new_key1_key2 (num, HSTAT_LINEAR, start, end, interval) */
+/* _stp_map_new_key1_key2 (num, HSTAT_LOG, buckets) */
MAP KEYSYM(_stp_map_new) (unsigned max_entries, int valtype, ...)
{
diff --git a/runtime/map.h b/runtime/map.h
index e48ec574..6de06f17 100644
--- a/runtime/map.h
+++ b/runtime/map.h
@@ -5,19 +5,25 @@
* @brief Header file for maps and lists
*/
/** @addtogroup maps
- * @todo Needs to be made SMP-safe for when the big lock is removed from kprobes.
+ * @todo Needs a spinlock variable to help when locks are required on the map.
* @{
*/
+/** This sets the size of the hash table. */
#ifndef HASH_TABLE_BITS
#define HASH_TABLE_BITS 8
+/** This sets the size of the hash table. */
#define HASH_TABLE_SIZE (1<<HASH_TABLE_BITS)
#endif
+/** The maximum number of keys allowed. Reducing this can save a small
+amount of memory. Do not increase above 5. */
#ifndef MAX_KEY_ARITY
#define MAX_KEY_ARITY 5
#endif
+/** Maximum length of strings in maps. This sets the amount of space reserved
+ for each string. */
#ifndef MAP_STRING_LENGTH
#define MAP_STRING_LENGTH 256
#endif
@@ -25,15 +31,19 @@
/** histogram type */
enum histtype { HIST_NONE, HIST_LOG, HIST_LINEAR };
+/** @cond DONT_INCLUDE */
#define INT64 0
#define STRING 1
#define STAT 2
-#define END 3 /* end marker */
+#define END 3
+/** @endcond */
+/** Histogram is log 2 */
#define HSTAT_LOG (STAT | (HIST_LOG << 8))
+/** Histogram is linear */
#define HSTAT_LINEAR (STAT | (HIST_LINEAR << 8))
-/* Statistics are stored in this struct */
+/** Statistics are stored in this struct */
typedef struct {
int64_t count;
int64_t sum;
@@ -42,7 +52,7 @@ typedef struct {
} stat;
-/* Keys are either int64 or strings */
+/** Keys are either int64 or strings */
typedef union {
int64_t val;
char *strp;
@@ -125,25 +135,23 @@ typedef struct map_root *MAP;
/** Macro to call the proper _stp_map_key functions based on the
* types of the arguments.
- * @note May cause compiler warning on some GCCs
*/
#define _stp_map_key2(map, key1, key2) \
- ({ \
- if (__builtin_types_compatible_p (typeof (key1), char[])) \
- if (__builtin_types_compatible_p (typeof (key2), char[])) \
- _stp_map_key_str_str (map, (char *)(key1), (char *)(key2)); \
- else \
- _stp_map_key_str_long (map, (char *)(key1), (long)(key2)); \
- else \
- if (__builtin_types_compatible_p (typeof (key2), char[])) \
- _stp_map_key_long_str (map, (long)(key1), (char *)(key2)); \
- else \
- _stp_map_key_long_long (map, (long)(key1), (long)(key2)); \
- })
+({ \
+ if (__builtin_types_compatible_p (typeof (key1), char[])) \
+ if (__builtin_types_compatible_p (typeof (key2), char[])) \
+ _stp_map_key_str_str (map, (char *)(key1), (char *)(key2)); \
+ else \
+ _stp_map_key_str_int64 (map, (char *)(key1), (int64_t)(key2)); \
+ else \
+ if (__builtin_types_compatible_p (typeof (key2), char[])) \
+ _stp_map_key_int64_str (map, (int64_t)(key1), (char *)(key2)); \
+ else \
+ _stp_map_key_int64_int64 (map, (int64_t)(key1), (int64_t)(key2)); \
+})
/** Macro to call the proper _stp_map_key function based on the
* type of the argument.
- * @note May cause compiler warning on some GCCs
*/
#define _stp_map_key(map, key) \
({ \
@@ -155,7 +163,6 @@ typedef struct map_root *MAP;
/** Macro to call the proper _stp_map_set function based on the
* type of the argument.
- * @note May cause compiler warning on some GCCs
*/
#define _stp_map_set(map, val) \
({ \
@@ -199,6 +206,7 @@ typedef struct map_root *MAP;
})
+/** @cond DONT_INCLUDE */
/************* prototypes for map.c ****************/
int int64_eq_p(int64_t key1, int64_t key2);
@@ -241,4 +249,5 @@ void _stp_list_add_string(MAP, String);
void _stp_map_key_int64(MAP, int64_t);
void _stp_map_set_int64(MAP, int64_t);
int64_t _stp_map_get_int64(MAP);
+/** @endcond */
#endif /* _MAP_H_ */
diff --git a/runtime/print.c b/runtime/print.c
index 44776578..e9847ef8 100644
--- a/runtime/print.c
+++ b/runtime/print.c
@@ -64,9 +64,10 @@ void _stp_print_flush (void)
static char _stp_pbuf[NR_CPUS][STP_PRINT_BUF_LEN + STP_PRINT_BUF_START + 1];
-/** Send the print buffer now.
- * Output accumulates in the print buffer until this is called.
- * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
+/** Send the print buffer to the transport now.
+ * Output accumulates in the print buffer until it
+ * is filled, or this is called. This MUST be called before returning
+ * from a probe or accumulated output in the print buffer will be lost.
*/
void _stp_print_flush (void)
@@ -91,10 +92,7 @@ void _stp_print_flush (void)
/** Print into the print buffer.
* Like printf, except output goes to the print buffer.
* Safe because overflowing the buffer is not allowed.
- * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
*
- * @param fmt A printf-style format string followed by a
- * variable number of args.
* @sa _stp_print_flush()
*/
#define _stp_printf(args...) _stp_sprintf(_stp_stdout,args)
@@ -109,7 +107,6 @@ void _stp_print_flush (void)
/** Write a C string into the print buffer.
* Copies a string into a print buffer.
* Safe because overflowing the buffer is not allowed.
- * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
* This is more efficient than using _stp_printf() if you don't
* need fancy formatting.
*
@@ -122,7 +119,6 @@ void _stp_print_flush (void)
/** Write a String into the print buffer.
* Copies a String into a print buffer.
* Safe because overflowing the buffer is not allowed.
- * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
* This is more efficient than using _stp_printf() if you don't
* need fancy formatting.
*
diff --git a/runtime/stack.c b/runtime/stack.c
index f06475dc..1f7073f5 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -7,104 +7,22 @@
*/
/** @addtogroup stack Stack Tracing Functions
+ * Without frames the best that can be done here is to scan the stack and
+ * display everything that fits in the range of a valid IP. Things like function pointers
+ * on the stack will certainly result in bogus addresses in the backtrace.
+ *
+ * With debug info, we could get a proper backtrace, but it would be too slow to do
+ * during a probe. We can eventually make this a postprocessing feature.
+ *
* @{
*/
#include "sym.c"
+#include "regs.h"
static int (*_stp_kta)(unsigned long addr)=(void *)KTA;
-
-struct frame_head {
- struct frame_head * ebp;
- unsigned long ret;
-} __attribute__((packed));
-
-static struct frame_head *
-dump_backtrace(struct frame_head * head)
-{
- _stp_printf ("db: %lx\n", head->ret);
-
- /* frame pointers should strictly progress back up the stack
- * (towards higher addresses) */
- if (head >= head->ebp)
- return NULL;
-
- return head->ebp;
-}
-
-static int pages_present(struct frame_head * head)
-{
- struct mm_struct * mm = current->mm;
-
- /* FIXME: only necessary once per page */
- if (!check_user_page_readable(mm, (unsigned long)head))
- return 0;
-
- return check_user_page_readable(mm, (unsigned long)(head + 1));
-}
-
-static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
-{
- unsigned long headaddr = (unsigned long)head;
- unsigned long stack = (unsigned long)regs;
- unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
- _stp_log ("%lx %lx %lx\n", headaddr, stack, stack_base);
- return headaddr < stack_base;
-}
-
-void
-x86_backtrace(struct pt_regs * const regs, unsigned int depth)
-{
- struct frame_head *head;
-
-#ifdef CONFIG_X86_64
- head = (struct frame_head *)regs->rbp;
-#else
- head = (struct frame_head *)regs->ebp;
-#endif
-
- if (!user_mode(regs)) {
- _stp_log ("kernel mode\n");
- while (depth-- && valid_kernel_stack(head, regs))
- head = dump_backtrace(head);
- _stp_print_flush();
- return;
- }
-
-#ifdef CONFIG_SMP
- if (!spin_trylock(&current->mm->page_table_lock))
- return;
-#endif
-
- while (depth-- && head && pages_present(head))
- head = dump_backtrace(head);
-
-#ifdef CONFIG_SMP
- spin_unlock(&current->mm->page_table_lock);
-#endif
- _stp_print_flush();
-}
-
-
-#ifdef __x86_64__
-static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
-{
- unsigned long addr;
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack;
- if (_stp_kta(addr)) {
- if (verbose) {
- _stp_symbol_print (addr);
- _stp_print ("\n");
- } else
- _stp_printf ("0x%lx ", addr);
- }
- stack++;
- }
- _stp_print_flush();
-}
-
+#if defined (__x86_64__)
static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
{
@@ -113,151 +31,153 @@ static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, i
addr = *stack++;
if (_stp_kta(addr)) {
if (verbose) {
+ _stp_string_cat(str, " ");
_stp_symbol_sprint (str, addr);
- _stp_sprintf (str, "\n");
- } else
- _stp_sprintf (str, "0x%lx\n", addr);
+ _stp_string_cat (str, "\n");
+ } else
+ _stp_sprintf (str, " 0x%lx\n", addr);
}
}
}
-#else /* i386 */
+#elif defined (__i386__)
-static inline int valid_stack_ptr (struct thread_info *tinfo, void *p)
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
{
return p > (void *)tinfo &&
p < (void *)tinfo + THREAD_SIZE - 3;
}
-static inline unsigned long _stp_print_context_stack (
- struct thread_info *tinfo,
- unsigned long *stack,
- unsigned long ebp )
-{
- unsigned long addr;
-
-#ifdef CONFIG_FRAME_POINTER
- while (valid_stack_ptr(tinfo, (void *)ebp)) {
- addr = *(unsigned long *)(ebp + 4);
- _stp_symbol_print (addr);
- _stp_print_cstr("\n");
- ebp = *(unsigned long *)ebp;
- }
-#else
- while (valid_stack_ptr(tinfo, stack)) {
- addr = *stack++;
- if (_stp_kta (addr)) {
- _stp_symbol_print (addr);
- _stp_print_cstr ("\n");
- }
- }
-#endif
- _stp_print_flush();
- return ebp;
-}
-
-static inline unsigned long _stp_sprint_context_stack (
- String str,
- struct thread_info *tinfo,
- unsigned long *stack,
- unsigned long ebp )
+static inline unsigned long print_context_stack(String str, struct thread_info *tinfo,
+ unsigned long *stack, unsigned long ebp)
{
unsigned long addr;
#ifdef CONFIG_FRAME_POINTER
while (valid_stack_ptr(tinfo, (void *)ebp)) {
addr = *(unsigned long *)(ebp + 4);
+ _stp_string_cat(str, " ");
_stp_symbol_sprint (str, addr);
- _stp_string_cat (str, "\n");
+ _stp_string_cat(str, "\n");
ebp = *(unsigned long *)ebp;
}
#else
while (valid_stack_ptr(tinfo, stack)) {
addr = *stack++;
- if (_stp_kta (addr)) {
- _stp_symbol_sprint (str, addr);
- _stp_string_cat (str, "\n");
+ if (_stp_kta(addr)) {
+ _stp_string_cat(str, " ");
+ _stp_symbol_sprint(str, addr);
+ _stp_string_cat(str, "\n");
}
}
#endif
return ebp;
}
-static void __stp_stack_print (unsigned long *stack, int verbose, int levels)
+static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
{
unsigned long ebp;
/* Grab ebp right from our regs */
asm ("movl %%ebp, %0" : "=r" (ebp) : );
- while (stack) {
- struct thread_info *context = (struct thread_info *)
+ while (1) {
+ struct thread_info *context;
+ context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
- ebp = _stp_print_context_stack (context, stack, ebp);
+ ebp = print_context_stack(str, context, stack, ebp);
stack = (unsigned long*)context->previous_esp;
+ if (!stack)
+ break;
}
- _stp_print_flush ();
}
-static void __stp_stack_sprint (String str, unsigned long *stack, int verbose, int levels)
-{
- unsigned long ebp;
- /* Grab ebp right from our regs */
- asm ("movl %%ebp, %0" : "=r" (ebp) : );
-
- while (stack) {
- struct thread_info *context = (struct thread_info *)
- ((unsigned long)stack & (~(THREAD_SIZE - 1)));
- ebp = _stp_sprint_context_stack (str, context, stack, ebp);
- stack = (unsigned long*)context->previous_esp;
- }
-}
+#else
+#error "Unsupported architecture"
+#endif
-#endif /* i386 */
-/** Print stack dump.
- * Prints a stack dump to the print buffer.
- * @param verbose Verbosity
- * @param levels Number of levels to trace.
- * @todo Implement verbosity and levels parameters.
- * @bug levels parameter is not functional
+/** Writes stack backtrace to a String
+ *
+ * @param str String
+ * @param regs A pointer to the struct pt_regs.
+ * @returns Same String as was input with trace info appended,
*/
-
-void _stp_stack_jprint (int verbose, int levels)
+String _stp_stack_sprint (String str, struct pt_regs *regs)
{
- unsigned long stack;
- __stp_stack_print (&stack, verbose, levels);
+ _stp_sprintf (str, "trace for %d (%s)\n ", current->pid, current->comm);
+ _stp_symbol_sprint (str, REG_IP(regs));
+ _stp_string_cat(str, "\n");
+ __stp_stack_sprint (str, (unsigned long *)&REG_SP(regs), 1, 0);
+ return str;
}
-void _stp_stack_print (struct pt_regs *regs, int verbose, int levels)
-{
- if (verbose) {
- _stp_printf ("trace for %d (%s)\n", current->pid, current->comm);
- _stp_symbol_print (regs->rip);
- _stp_print ("\n");
- } else
- _stp_printf ("0x%lx ", regs->rip);
+/** Prints the stack backtrace
+ * @param regs A pointer to the struct pt_regs.
+ * @note Calls _stp_print_flush().
+ */
- __stp_stack_print ((unsigned long *)regs->rsp, verbose, levels);
-}
+#define _stp_stack_print(regs) \
+ { \
+ (void)_stp_stack_sprint(_stp_stdout,regs); \
+ _stp_print_flush(); \
+ }
-/** Writes stack dump to a String
- *
+/** Writes stack backtrace to a String.
+ * Use this when calling from a jprobe.
* @param str String
- * @param verbose Verbosity
- * @param levels Number of levels to trace.
- * @returns Same String as was input.
- * @todo Implement verbosity and levels parameters.
- * @bug levels parameter is not functional
+ * @returns Same String as was input with trace info appended,
+ * @sa _stp_stack_sprint()
+ */
+String _stp_stack_sprintj(String str)
+{
+ unsigned long stack;
+ _stp_sprintf (str, "trace for %d (%s)\n", current->pid, current->comm);
+ __stp_stack_sprint (str, &stack, 1, 0);
+ return str;
+}
+
+/** Prints the stack backtrace.
+ * Use this when calling from a jprobe.
+ * @sa _stp_stack_print()
+ * @note Calls _stp_print_flush().
*/
+#define _stp_stack_printj() \
+ { \
+ (void)_stp_stack_sprintj(_stp_stdout); \
+ _stp_print_flush(); \
+ }
-String _stp_stack_sprint (String str, int verbose, int levels)
+/** Writes the user stack backtrace to a String
+ * @param str String
+ * @returns Same String as was input with trace info appended,
+ * @note Currently limited to a depth of two. Works from jprobes and kprobes.
+ */
+String _stp_ustack_sprint (String str)
{
- unsigned long stack;
- __stp_stack_sprint (str, &stack, verbose, levels);
- return str;
+ struct pt_regs *nregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1;
+#if BITS_PER_LONG == 64
+ _stp_sprintf (str, " 0x%016lx : [user]\n", REG_IP(nregs));
+ if (REG_SP(nregs))
+ _stp_sprintf (str, " 0x%016lx : [user]\n", *(unsigned long *)REG_SP(nregs));
+#else
+ _stp_sprintf (str, " 0x%08lx : [user]\n", REG_IP(nregs));
+ if (REG_SP(nregs))
+ _stp_sprintf (str, " 0x%08lx : [user]\n", *(unsigned long *)REG_SP(nregs));
+#endif
+ return str;
}
+/** Prints the user stack backtrace
+ * @note Currently limited to a depth of two. Works from jprobes and kprobes.
+ * Calls _stp_print_flush().
+ */
+#define _stp_ustack_print() \
+ { \
+ (void)_stp_ustack_sprint(_stp_stdout); \
+ _stp_print_flush(); \
+ }
+
/** @} */
#endif /* _STACK_C_ */
diff --git a/runtime/string.c b/runtime/string.c
index 16a20dfb..f079bf89 100644
--- a/runtime/string.c
+++ b/runtime/string.c
@@ -34,7 +34,7 @@ static struct string _stp_string[STP_NUM_STRINGS][NR_CPUS];
typedef struct string *String;
/* set up a special stdout string */
-struct string __stp_stdout;
+static struct string __stp_stdout;
String _stp_stdout = &__stp_stdout;
void _stp_vsprintf (String str, const char *fmt, va_list args);
@@ -45,6 +45,7 @@ void _stp_vsprintf (String str, const char *fmt, va_list args);
* @param num Number of the preallocated String to use.
* #STP_NUM_STRINGS are statically allocated for our use. The
* translator (or author) should be sure to grab a free one.
+ * @returns An empty String.
*/
String _stp_string_init (int num)
diff --git a/runtime/sym.c b/runtime/sym.c
index 1eec0d1d..a1c04a65 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -36,11 +36,15 @@ String _stp_symbol_sprint (String str, unsigned long address)
name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf);
- _stp_sprintf (str, "0x%lx : ", address);
- if (modname)
- _stp_sprintf (str, "%s+%#lx/%#lx [%s]", name, offset, size, modname);
- else
- _stp_sprintf (str, "%s+%#lx/%#lx", name, offset, size);
+ _stp_sprintf (str, "0x%lx", address);
+
+ if (name) {
+ if (modname)
+ _stp_sprintf (str, " : %s+%#lx/%#lx [%s]", name, offset, size, modname);
+ else
+ _stp_sprintf (str, " : %s+%#lx/%#lx", name, offset, size);
+ }
+
return str;
}
@@ -51,21 +55,7 @@ String _stp_symbol_sprint (String str, unsigned long address)
* a probe because it is too time-consuming. Use at module exit time.
*/
-void _stp_symbol_print (unsigned long address)
-{
- char *modname;
- const char *name;
- unsigned long offset, size;
- char namebuf[KSYM_NAME_LEN+1];
-
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf);
-
- _stp_printf ("0x%lx : ", address);
- if (modname)
- _stp_printf ("%s+%#lx/%#lx [%s]", name, offset, size, modname);
- else
- _stp_printf ("%s+%#lx/%#lx", name, offset, size);
-}
+#define _stp_symbol_print(address) _stp_symbol_sprint(_stp_stdout,address)
/** @} */
#endif /* _SYM_C_ */