From 82f426c231754da7c58ddbeca29c3e36baa0b291 Mon Sep 17 00:00:00 2001 From: ddomingo Date: Mon, 8 Sep 2008 14:29:23 +1000 Subject: added content for Ch1 and 2, to add more later --- .../en-US/Introduction.xml | 33 ++++++++++++++---- .../en-US/SystemTap_Beginners_Guide.ent | 3 +- .../en-US/Understanding_How_SystemTap_Works.xml | 40 ++++++++++++++++++++-- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml index 9285d0ae..f60ab2f3 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Introduction.xml @@ -5,15 +5,36 @@ Introduction - A short introduction on SystemTap_Beginners_Guide + SystemTap is a tracing and probing tool that provides users deep technical insight into what the operating system (particularly, the kernel) is doing at any given time. It provides information similar to the output of tools like netstat, ps, top, and iostat; however, SystemTap is designed to provide information that is more "granular" in nature. - + + For system administrators, SystemTap can be used as a performance monitoring tool for ∏. It is most useful when other similar tools cannot precisely pinpoint a bottleneck in the system, requiring a deep analysis of kernel activity. In the same manner, application developers can also use SystemTap to monitor, in finer detail, how their application behaves. + + + +
Goals - TBD - + The goal of SystemTap is to provide infrastructure to monitor the running Linux kernel for detailed analysis. This can assist in identifying the underlying cause of a performance or functional problem. + + Without SystemTap, monitoring the activity of a running kernel would require a tedious instrument, recompile, install, and reboot sequence. SystemTap is designed to eliminate this, allowing you to gather the same information by simply running its suite of tools against specific tapsets or SystemTap scripts. + + However, SystemTap was initially designed for users with intermediate to advanced knowledge of the kernel. This could present a steep learning curve for administrators or developers whose knowledge of the Linux kernel is little to none. + + In line with that, the main goal of the SystemTap Beginner's Guide is two-fold: + + + To introduce users to SystemTap, familiarize them with its architecture, and provide setup instructions for all kernel types. + + To provide pre-written SystemTap scripts for monitoring and forensic tasks, along with instructions on how to analyze their output. + + above, Short description on the underlying goals of SystemTap_Beginners_Guide, what we want to teach users. - +
Usage @@ -25,7 +46,7 @@
SystemTap Versus Other Monitoring Tools - Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) + ** Short summary; when is SystemTap suitable vs other popular monitoring tools (e.g. top, Oprofile, /proc) diff --git a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent index 46bb6c06..994cf1a4 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent +++ b/doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent @@ -1,3 +1,4 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index b3a1cbed..3194dba0 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -8,18 +8,52 @@ Short summary; probes, handlers, events + SystemTap allows users to write and reuse simple scripts to deeply examine the activities of a running Linux system. These scripts can be designed to extract data, filter it, and summarize it quickly (and safely), enabling the diagnosis of complex performance (or even functional) problems. + + The essential idea behind a SystemTap script is to name events, and to give them handlers. When SystemTap runs the script, SystemTap monitors for the event; once the event occurs, the Linux kernel then runs the handler as a quick sub-routine, then resumes. + + There are several kind of events; entering/exiting a function, timer expiration, session termination, etc. A handler is a series of script language statements that specify the work to be done whenever the event occurs. This work normally includes extracting data from the event context, storing them into internal variables, or printing results. +
Architecture - add diagram, describe architecture, enumerate common tools + ** add diagram, describe architecture, enumerate common tools -
+ + + ** architecture diagram must be simpler, if at all included + + + + ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc" + + + + test + + + A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion: + + + SystemTap Session + SystemTap first translates the script to C, running the system C compiler to create a kernel module from it. + + SystemTap then loads the module, then enables all the probed events by "hooking" those events into the kernel. + + As the events occur, their corresponding handlers are executed. + + Once the SystemTap session is terminated, the hooked events are disconnected from the kernel; afterwards, the kernel module is unloaded. + + +This sequence is driver from a single command-line program: stap. This program is SystemTap's main front-end tool. For more information about stap, refer to man stap (once SystemTap is set up on your machine). + +
SystemTap Scripts - definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them) + ** definition, significance, structure, very basic examples, reference to later chapter (how to read library of preset SystemTap scripts in this book, using them)
-- cgit From e36b5fc35d4033d5718eb8e101968b79d0360202 Mon Sep 17 00:00:00 2001 From: ddomingo Date: Mon, 8 Sep 2008 14:42:17 +1000 Subject: remove test tag --- .../en-US/Understanding_How_SystemTap_Works.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index 3194dba0..e418f561 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -26,10 +26,6 @@ ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc" - - - - test A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion: -- cgit From e6342ff8c11bbed1d2058507b918cf3c140e1322 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 8 Sep 2008 16:14:03 +0200 Subject: PR1288: runtime functions for avoiding certain addresses --- runtime/ChangeLog | 8 ++ runtime/addr-map.c | 181 +++++++++++++++++++++++++++++++++++++ runtime/loc2c-runtime.h | 230 ++++++++++++++++++++++++++++-------------------- runtime/runtime.h | 1 + 4 files changed, 326 insertions(+), 94 deletions(-) create mode 100644 runtime/addr-map.c diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 8f20ed11..eb091d01 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,11 @@ +2008-09-08 Tim Moore + + PR 1288 + * addr-map.c: New file with functions for looking up addresses + * loc2c-runtime.h (deref, store_deref): Use lookup_bad_addr to + avoid dereferencing known dangerous addresses. + * runtime.h: Include addr-map.c. + 2008-09-06 Frank Ch. Eigler PR 6445 diff --git a/runtime/addr-map.c b/runtime/addr-map.c new file mode 100644 index 00000000..8231b57f --- /dev/null +++ b/runtime/addr-map.c @@ -0,0 +1,181 @@ +/* -*- linux-c -*- + * Map of addresses to disallow. + * Copyright (C) 2005-2008 Red Hat Inc. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +#ifndef _ADDR_MAP_C_ +#define _ADDR_MAP_C_ 1 + +/** @file addr-map + * @brief Implements functions used by the deref macro to blacklist + * certain addresses. + */ + +struct addr_map_entry +{ + unsigned long min; + unsigned long max; +}; + +struct addr_map +{ + size_t size; + struct addr_map_entry entries[0]; +}; + +static DEFINE_SPINLOCK(addr_map_lock); + +struct addr_map* blackmap; + +/* Find address of entry where we can insert a new one. */ +static size_t +upper_bound(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end = map->size; + struct addr_map_entry *entry = 0; + + if (end == 0) + return 0; + do + { + size_t new_idx; + if (addr < map->entries[start].min) + return start; + if (addr >= map->entries[end-1].max) + return end; + new_idx = (end + start) / 2; + entry = &map->entries[new_idx]; + if (addr < entry->min) + end = new_idx; + else + start = new_idx + 1; + } while (end != start); + return entry - &map->entries[0]; +} + +static struct addr_map_entry* +lookup_addr_aux(unsigned long addr, struct addr_map* map) +{ + size_t start = 0; + size_t end; + if (!map) + return 0; + end = map->size; + if (map->size == 0) + return 0; + + do + { + int entry_idx; + struct addr_map_entry *entry = 0; + if (addr < map->entries[start].min || addr >= map->entries[end - 1].max) + return 0; + entry_idx = (end + start) / 2; + entry = &map->entries[entry_idx]; + if (entry->min <= addr && entry->max > addr) + return entry; + if (addr < entry->min) + end = entry_idx; + else + start = entry_idx + 1; + } while (start < end); + return 0; +} + +int +lookup_bad_addr(unsigned long addr) +{ + struct addr_map_entry* result = 0; + spin_lock(&addr_map_lock); + result = lookup_addr_aux(addr, blackmap); + spin_unlock(&addr_map_lock); + if (result) + return 1; + else + return 0; +} + + +int +add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, + struct addr_map_entry** existing_min, + struct addr_map_entry** existing_max) +{ + struct addr_map* new_map = 0; + struct addr_map* old_map = 0; + struct addr_map_entry* min_entry = 0; + struct addr_map_entry* max_entry = 0; + struct addr_map_entry* new_entry = 0; + size_t existing = 0; + + while (1) + { + size_t old_size; + spin_lock(&addr_map_lock); + old_map = blackmap; + if (!blackmap) + { + existing = 0; + old_size = 0; + } + else + { + min_entry = lookup_addr_aux(min_addr, blackmap); + max_entry = lookup_addr_aux(max_addr, blackmap); + if (min_entry || max_entry) + { + if (existing_min) + *existing_min = min_entry; + if (existing_max) + *existing_max = max_entry; + spin_unlock(&addr_map_lock); + return 1; + } + existing = upper_bound(min_addr, old_map); + old_size = old_map->size; + } + spin_unlock(&addr_map_lock); + new_map = kmalloc(sizeof(*new_map) + + sizeof(*new_entry) * (old_size + 1), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + spin_lock(&addr_map_lock); + if (blackmap != old_map) + { + kfree(new_map); + spin_unlock(&addr_map_lock); + continue; + } + new_entry = &new_map->entries[existing]; + new_entry->min = min_addr; + new_entry->max = max_addr; + if (old_map) + { + memcpy(&new_map->entries, old_map->entries, + existing * sizeof(*new_entry)); + if (old_map->size > existing) + memcpy(new_entry + 1, &old_map->entries[existing + 1], + (old_map->size - existing) * sizeof(*new_entry)); + } + new_map->size = blackmap->size + 1; + blackmap = new_map; + spin_unlock(&addr_map_lock); + if (old_map) + kfree(old_map); + return 0; + } +} + +void +delete_bad_addr_entry(struct addr_map_entry* entry) +{ +} + +#endif diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 1247da51..0af19edc 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -201,6 +201,8 @@ #define deref(size, addr) ({ \ intptr_t _i; \ + if (lookup_bad_addr((unsigned long)addr)) \ + __deref_bad(); \ switch (size) { \ case 1: _i = kread((u8 *)(addr)); break; \ case 2: _i = kread((u16 *)(addr)); break; \ @@ -213,6 +215,8 @@ }) #define store_deref(size, addr, value) ({ \ + if (lookup_bad_addr((unsigned long)addr)) \ + __store_deref_bad(); \ switch (size) { \ case 1: kwrite((u8 *)(addr), (value)); break; \ case 2: kwrite((u16 *)(addr), (value)); break; \ @@ -234,30 +238,36 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - default: _v = __get_user_bad(); \ - } \ - if (_bad) \ - DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + default: _v = __get_user_bad(); \ + } \ + if (_bad) \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - default: __put_user_bad(); \ - } \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break;\ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + default: __put_user_bad(); \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) @@ -268,14 +278,17 @@ extern void __store_deref_bad(void); int _bad = 0; \ u8 _b; u16 _w; u32 _l; u64 _q; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ - case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ - case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ - case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __get_user_asm(_b,addr,_bad,"b","b","=q",1); _v = _b; break; \ + case 2: __get_user_asm(_w,addr,_bad,"w","w","=r",1); _v = _w; break; \ + case 4: __get_user_asm(_l,addr,_bad,"l","","=r",1); _v = _l; break; \ + case 8: __get_user_asm(_q,addr,_bad,"q","","=r",1); _v = _q; break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -284,14 +297,17 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ - case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break; \ - case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break; \ - case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __put_user_asm(((u8)(value)),addr,_bad,"b","b","iq",1); break; \ + case 2: __put_user_asm(((u16)(value)),addr,_bad,"w","w","ir",1); break;\ + case 4: __put_user_asm(((u32)(value)),addr,_bad,"l","k","ir",1); break;\ + case 8: __put_user_asm(((u64)(value)),addr,_bad,"q","","Zr",1); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -301,13 +317,16 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __get_user_size(_v, addr, 1, _bad); break; \ - case 2: __get_user_size(_v, addr, 2, _bad); break; \ - case 4: __get_user_size(_v, addr, 4, _bad); break; \ - case 8: __get_user_size(_v, addr, 8, _bad); break; \ - default: __get_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __get_user_size(_v, addr, 1, _bad); break; \ + case 2: __get_user_size(_v, addr, 2, _bad); break; \ + case 4: __get_user_size(_v, addr, 4, _bad); break; \ + case 8: __get_user_size(_v, addr, 8, _bad); break; \ + default: __get_user_unknown(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -316,13 +335,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __put_user_size(value, addr, 1, _bad); break; \ - case 2: __put_user_size(value, addr, 2, _bad); break; \ - case 4: __put_user_size(value, addr, 4, _bad); break; \ - case 8: __put_user_size(value, addr, 8, _bad); break; \ - default: __put_user_unknown(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __put_user_size(value, addr, 1, _bad); break; \ + case 2: __put_user_size(value, addr, 2, _bad); break; \ + case 4: __put_user_size(value, addr, 4, _bad); break; \ + case 8: __put_user_size(value, addr, 8, _bad); break; \ + default: __put_user_unknown(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -373,30 +395,36 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v; \ - switch (size) \ - { \ - case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ - case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ - case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ - case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ - default: _v = __get_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_get_user_asm(_v,addr,_bad,"lbz"); break; \ + case 2: __stp_get_user_asm(_v,addr,_bad,"lhz"); break; \ + case 4: __stp_get_user_asm(_v,addr,_bad,"lwz"); break; \ + case 8: __stp_get_user_asm(_v,addr,_bad,"ld"); break; \ + default: _v = __get_user_bad(); \ + } \ if (_bad) \ - DEREF_FAULT(addr); \ + DEREF_FAULT(addr); \ _v; \ }) #define store_deref(size, addr, value) \ ({ \ int _bad = 0; \ - switch (size) \ - { \ - case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ - case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ - case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ - case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ - default: __put_user_bad(); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) \ + { \ + case 1: __stp_put_user_asm(((u8)(value)),addr,_bad,"stb"); break; \ + case 2: __stp_put_user_asm(((u16)(value)),addr,_bad,"sth"); break; \ + case 4: __stp_put_user_asm(((u32)(value)),addr,_bad,"stw"); break; \ + case 8: __stp_put_user_asm(((u64)(value)),addr,_bad, "std"); break; \ + default: __put_user_bad(); \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -541,12 +569,15 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ intptr_t _v=0; \ - switch (size){ \ - case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ - case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ - case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ - default: __get_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_get_user_asm_byte(_v, addr, _bad); break; \ + case 2: __stp_get_user_asm_half(_v, addr, _bad); break; \ + case 4: __stp_get_user_asm_word(_v, addr, _bad); break; \ + default: __get_user_bad(); break; \ + } \ if (_bad) \ DEREF_FAULT(addr); \ _v; \ @@ -555,13 +586,16 @@ extern void __store_deref_bad(void); #define store_deref(size, addr, value) \ ({ \ int _bad=0; \ - switch (size){ \ - case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ - case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ - case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ - case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ - default: __put_user_bad(); break; \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size){ \ + case 1: __stp_put_user_asm_byte(value, addr, _bad); break; \ + case 2: __stp_put_user_asm_half(value, addr, _bad); break; \ + case 4: __stp_put_user_asm_word(value, addr, _bad); break; \ + case 8: __stp_put_user_asm_dword(value, addr, _bad); break; \ + default: __put_user_bad(); break; \ + } \ if (_bad) \ STORE_DEREF_FAULT(addr); \ }) @@ -624,28 +658,31 @@ extern void __store_deref_bad(void); u8 _b; u16 _w; u32 _l; u64 _q; \ int _bad = 0; \ intptr_t _v = 0; \ - switch (size) { \ - case 1: { \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + switch (size) { \ + case 1: { \ __stp_get_asm(_b, addr, _bad, 1); \ _v = _b; \ break; \ - }; \ - case 2: { \ + }; \ + case 2: { \ __stp_get_asm(_w, addr, _bad, 2); \ _v = _w; \ break; \ - }; \ - case 4: { \ + }; \ + case 4: { \ __stp_get_asm(_l, addr, _bad, 4); \ _v = _l; \ break; \ - }; \ - case 8: { \ + }; \ + case 8: { \ __stp_get_asm(_q, addr, _bad, 8); \ _v = _q; \ break; \ - }; \ - default: \ + }; \ + default: \ _bad = -EFAULT; \ } \ if (_bad) \ @@ -657,12 +694,17 @@ extern void __store_deref_bad(void); ({ \ int _bad = 0; \ int i; \ - for(i=0;i>((size-i-1)*8)&0xff), \ - (u64)addr+i,_bad); \ - if (_bad) \ - STORE_DEREF_FAULT(addr); \ - } \ + if (lookup_bad_addr((unsigned long)addr)) \ + _bad = 1; \ + else \ + for(i=0;i>((size-i-1)*8)&0xff), \ + (u64)addr+i,_bad); \ + if (_bad) \ + break; \ + } \ + if (_bad) \ + STORE_DEREF_FAULT(addr); \ }) diff --git a/runtime/runtime.h b/runtime/runtime.h index 2711f531..fd0cac9e 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -88,6 +88,7 @@ static struct #ifdef STP_PERFMON #include "perf.c" #endif +#include "addr-map.c" /* Support functions for int64_t module parameters. */ int param_set_int64_t(const char *val, struct kernel_param *kp) -- cgit From a5e2a4c92910faf6ef6a2f84b6b58a85dece300c Mon Sep 17 00:00:00 2001 From: ddomingo Date: Tue, 9 Sep 2008 09:23:21 +1000 Subject: separated Scripts, edited accordingly --- doc/SystemTap_Beginners_Guide/en-US/Scripts.xml | 46 ++++++++++++++++++++++ .../en-US/Understanding_How_SystemTap_Works.xml | 7 ++-- 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 doc/SystemTap_Beginners_Guide/en-US/Scripts.xml diff --git a/doc/SystemTap_Beginners_Guide/en-US/Scripts.xml b/doc/SystemTap_Beginners_Guide/en-US/Scripts.xml new file mode 100644 index 00000000..abb087bc --- /dev/null +++ b/doc/SystemTap_Beginners_Guide/en-US/Scripts.xml @@ -0,0 +1,46 @@ + + + +
+ SystemTap Scripts + + + For the most part, SystemTap scripts are the foundation of each SystemTap session. The SystemTap scripts you use or write yourself instruct SystemTap on what type of information to trap, and what to do once that information is trapped. + + + + As stated in , SystemTap scripts are made up of two components: events and handlers. Once a SystemTap session is underway, SystemTap monitors the operating system for the specified events and executes the handlers as they occur. + + + + Note + An event and its corresponding handler is collectively called a probe. A SystemTap script can have multiple probes, in the same manner that each event can have multiple corresponding handlers. + + + + In terms of application development, using events and handlers is similar to inserting print statements in a program's sequence of commands. These print statements allow you to view a history of commands executed once the program is run. + + + + SystemTap scripts go one step further by allowing you more flexibility with regard to handlers. Events serve as the triggers for handlers to run; handlers can be specified to trap specified data and print it in a certain manner. + + + + +
+ Format + + SystemTap scripts use the following format: + +
+ + + +
+ diff --git a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml index e418f561..de5d41b0 100644 --- a/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml +++ b/doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml @@ -41,10 +41,11 @@ Once the SystemTap session is terminated, the hooked events are disconnected from the kernel; afterwards, the kernel module is unloaded. -This sequence is driver from a single command-line program: stap. This program is SystemTap's main front-end tool. For more information about stap, refer to man stap (once SystemTap is set up on your machine). +This sequence is driven from a single command-line program: stap. This program is SystemTap's main front-end tool. For more information about stap, refer to man stap (once SystemTap is set up on your machine).
- + +
Tapsets -- cgit From 094b05c79e7a69567f55514386f5f276ada60d0d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 8 Sep 2008 16:26:48 -0700 Subject: tiny grammar fix in NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ab035593..c7ddce45 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ * What's new - Target process mode (stap -c CMD or -x PID) now implicitly restricts all - "process.*" probes to the given child process. (It does not effect + "process.*" probes to the given child process. (It does not affect kernel.* or other probe types.) The CMD string is now executed directly, rather than via a /bin/sh -c subshell. -- cgit From 67a66a8b72d19dc1a1fd10db1c55e31a6e93b270 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 9 Sep 2008 11:42:28 +0200 Subject: Correct this_section_offset calculation in _stp_kallsyms_lookup. --- runtime/ChangeLog | 5 +++++ runtime/sym.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index eb091d01..71cd97e4 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,8 @@ +2008-09-09 Mark Wielaard + + * sym.c (_stp_kallsyms_lookup): Correct this_section_offset + calculation. + 2008-09-08 Tim Moore PR 1288 diff --git a/runtime/sym.c b/runtime/sym.c index dcdbaf69..b594d9c2 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -98,7 +98,7 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo unsigned long this_section_addr = _stp_modules[midx]->sections[secidx].addr; unsigned long this_section_offset; if (addr < this_section_addr) continue; - this_section_offset = this_section_addr - addr; + this_section_offset = addr - this_section_addr; if (this_section_offset < closest_section_offset) { closest_section_offset = this_section_offset; -- cgit From 4a0e1ceaed41df14fa3a4870c00c334a6dd8384f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:00:58 -0400 Subject: Add ia64 utrace support --- runtime/ChangeLog | 4 ++++ runtime/syscall.h | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 71cd97e4..9cca0759 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,7 @@ +2008-09-09 Masami Hiramatsu + + * syscall.h: Added ia64 support. + 2008-09-09 Mark Wielaard * sym.c (_stp_kallsyms_lookup): Correct this_section_offset diff --git a/runtime/syscall.h b/runtime/syscall.h index 24e93463..8416fd1d 100644 --- a/runtime/syscall.h +++ b/runtime/syscall.h @@ -66,7 +66,15 @@ #define MUNMAP_SYSCALL_NO(tsk) 91 #define MREMAP_SYSCALL_NO(tsk) 163 #endif - + +#if defined(__ia64__) +#define MMAP_SYSCALL_NO(tsk) 1151 +#define MMAP2_SYSCALL_NO(tsk) 1172 +#define MPROTECT_SYSCALL_NO(tsk) 1155 +#define MUNMAP_SYSCALL_NO(tsk) 1152 +#define MREMAP_SYSCALL_NO(tsk) 1156 +#endif + #if !defined(MMAP_SYSCALL_NO) || !defined(MMAP2_SYSCALL_NO) \ || !defined(MPROTECT_SYSCALL_NO) || !defined(MUNMAP_SYSCALL_NO) \ || !defined(MREMAP_SYSCALL_NO) @@ -95,6 +103,14 @@ __stp_user_syscall_nr(struct pt_regs *regs) } #endif +#if defined(__ia64__) +static inline unsigned long +__stp_user_syscall_nr(struct pt_regs *regs) +{ + return regs->r15; +} +#endif + #if defined(__i386__) || defined(__x86_64__) static inline long * __stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) @@ -129,6 +145,14 @@ __stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) } #endif +#if defined(__ia64__) +static inline long * +__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs) +{ + return ®s->r8; +} +#endif + #if defined(__i386__) || defined(__x86_64__) static inline long * __stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, @@ -211,4 +235,25 @@ __stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, } #endif +#if defined(__ia64__) +static inline long * +__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, + unsigned int n) +{ + struct ia64_stap_get_arbsp_param pa; + if (n > 5) { + _stp_error("syscall arg > 5"); + return NULL; + } + + pa.ip = regs->cr_iip; + unw_init_running(ia64_stap_get_arbsp, &pa); + if (pa.address == 0) + return NULL; + + return ia64_rse_skip_regs(pa.address, n); + +} +#endif + #endif /* _SYSCALL_H_ */ -- cgit From 901a409a01da22778ea15f7b9f938885bdc38847 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:01:37 -0400 Subject: Utrace on ia64 fast fetch-register support --- runtime/ChangeLog | 11 +++++++++++ runtime/regs-ia64.c | 21 +++++++++++++++------ runtime/syscall.h | 17 ++++++----------- runtime/task_finder.c | 6 ++++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 9cca0759..f7a844d8 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,14 @@ +2008-09-09 Masami Hiramatsu + + * regs-ia64.c (__ia64_fetch_register): Return the address of the + register. + (ia64_fetch_register): Use __ia64_fetch_register. + * syscall.h (____stp_user_syscall_arg): Use __ia64_fetch_register. + (__stp_user_syscall_arg): Wrapping ____stp_user_syscall_arg to pass the + unwind address cache. + * task_finder.c (__stp_utrace_task_finder_target_syscall_): Added dummy + unwind address cache. + 2008-09-09 Masami Hiramatsu * syscall.h: Added ia64 support. diff --git a/runtime/regs-ia64.c b/runtime/regs-ia64.c index fd8d8ca8..8ce3e4c3 100644 --- a/runtime/regs-ia64.c +++ b/runtime/regs-ia64.c @@ -61,27 +61,36 @@ static void ia64_stap_get_arbsp(struct unw_frame_info *info, void *arg) -(__offset + (regs->cr_ifs & 127)));\ } -static long ia64_fetch_register(int regno, struct pt_regs *pt_regs, unsigned long **cache) +static long * +__ia64_fetch_register(int regno, struct pt_regs *pt_regs, unsigned long **cache) { struct ia64_stap_get_arbsp_param pa; if (regno == 12) - return pt_regs->r12; + return &pt_regs->r12; if (regno >= 8 && regno <= 11) - return *(unsigned long *)(&pt_regs->r8 + regno - 8); + return (long *)(&pt_regs->r8 + regno - 8); else if (regno < 32 || regno > 127) - return 0; + return NULL; if (!*cache) { pa.ip = pt_regs->cr_iip; unw_init_running(ia64_stap_get_arbsp, &pa); if (pa.address == 0) - return 0; + return NULL; *cache = pa.address; } - return *ia64_rse_skip_regs(*cache, regno-32); + return ia64_rse_skip_regs(*cache, regno-32); +} + +static long +ia64_fetch_register(int regno, struct pt_regs *pt_regs, unsigned long **cache) +{ + long *reg; + reg = __ia64_fetch_register(regno, pt_regs, cache); + return (reg != NULL)? *reg : 0; } static void ia64_store_register(int regno, diff --git a/runtime/syscall.h b/runtime/syscall.h index 8416fd1d..24fc7b1c 100644 --- a/runtime/syscall.h +++ b/runtime/syscall.h @@ -236,23 +236,18 @@ __stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, #endif #if defined(__ia64__) +#define __stp_user_syscall_arg(task, regs, n) \ + ____stp_user_syscall_arg(task, regs, n, &c->unwaddr) + static inline long * -__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, - unsigned int n) +____stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs, + unsigned int n, unsigned long **cache) { - struct ia64_stap_get_arbsp_param pa; if (n > 5) { _stp_error("syscall arg > 5"); return NULL; } - - pa.ip = regs->cr_iip; - unw_init_running(ia64_stap_get_arbsp, &pa); - if (pa.address == 0) - return NULL; - - return ia64_rse_skip_regs(pa.address, n); - + return __ia64_fetch_register(n + 32, regs, cache); } #endif diff --git a/runtime/task_finder.c b/runtime/task_finder.c index 2d4eed15..cbb10d35 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -843,6 +843,9 @@ __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action, struct vm_area_struct *vma; unsigned long *arg0_addr, arg0; int rc; +#if defined(__ia64__) + struct { unsigned long *unwaddr; } _c = {.unwaddr = NULL}, *c = &_c; +#endif if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { debug_task_finder_detach(); @@ -950,6 +953,9 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action, struct mm_struct *mm; struct vm_area_struct *vma; struct __stp_tf_vma_entry *entry = NULL; +#if defined(__ia64__) + struct { unsigned long *unwaddr; } _c = {.unwaddr = NULL}, *c = &_c; +#endif if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) { debug_task_finder_detach(); -- cgit From bc54e71c6747fa2c234737d3a715b0decc3663b2 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:02:21 -0400 Subject: Add $name context variable support on marker probes --- ChangeLog | 13 ++++++++++ stapprobes.5.in | 2 ++ tapset/ChangeLog | 4 +++ tapset/marker.stp | 22 +++++++++++++++++ tapsets.cxx | 49 +++++++++++++++---------------------- testsuite/ChangeLog | 4 +++ testsuite/systemtap.base/marker.exp | 45 ++++++++++++++++++++++++++++++++++ translate.cxx | 2 ++ 8 files changed, 112 insertions(+), 29 deletions(-) create mode 100644 tapset/marker.stp diff --git a/ChangeLog b/ChangeLog index 09f661ae..cb5a6f4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-09-09 Masami Hiramatsu + + * stapprobes.5.in : Added a line for $name context variable. + * translate.cxx (c_unparser::emit_common_header): Add marker_name and + marker_format fields to context. + * tapsets.cxx (common_probe_entryfn_prologue) : Ditto. + (mark_derived_probe_group::emit_module_decls) : Ditto. + (mark_var_expanding_copy_visitor) : change visit_target_symbol_format + to visit_target_symbol_context. + (mark_var_expanding_copy_visitor::visit_target_symbol_context): handle + not only $format but also $name. + (mark_var_expanding_copy_visitor::visit_target_symbol): Ditto. + 2008-09-07 Frank Ch. Eigler * tapsets.cxx (build_blacklist): Add some x86 raw port-io spots. diff --git a/stapprobes.5.in b/stapprobes.5.in index 5281c40e..ecc6956c 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -520,6 +520,8 @@ and string parameters are passed in a type-safe manner. The marker format string associated with a marker is available in .BR $format . +And also the marker name string is avalable in +.BR $name . .SS PERFORMANCE MONITORING HARDWARE diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 39b6b93b..d3117620 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,7 @@ +2008-09-09 Masami Hiramatsu + + * marker.stp : New file, including marker context variable accessors. + 2008-09-01 Frank Ch. Eigler PR4225 merge. diff --git a/tapset/marker.stp b/tapset/marker.stp new file mode 100644 index 00000000..593ffaea --- /dev/null +++ b/tapset/marker.stp @@ -0,0 +1,22 @@ +// +// kernel marker tapset +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + +/* marker-only context accessors */ + + +function _mark_name_get:string () %{ + strlcpy (THIS->__retvalue, + (CONTEXT->marker_name)?CONTEXT->marker_name:"", + MAXSTRINGLEN); /* pure */ +%} + +function _mark_format_get:string () %{ + strlcpy (THIS->__retvalue, + (CONTEXT->marker_format)?CONTEXT->marker_format:"", + MAXSTRINGLEN); /* pure */ +%} diff --git a/tapsets.cxx b/tapsets.cxx index 64fa9d34..4774c0f6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -221,6 +221,8 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, // reset unwound address cache o->newline() << "c->pi = 0;"; o->newline() << "c->regparm = 0;"; + o->newline() << "c->marker_name = NULL;"; + o->newline() << "c->marker_format = NULL;"; o->newline() << "c->probe_point = 0;"; if (! interruptible) o->newline() << "c->actionremaining = MAXACTION;"; @@ -7758,7 +7760,7 @@ struct mark_var_expanding_copy_visitor: public var_expanding_copy_visitor void visit_target_symbol (target_symbol* e); void visit_target_symbol_arg (target_symbol* e); - void visit_target_symbol_format (target_symbol* e); + void visit_target_symbol_context (target_symbol* e); }; @@ -7865,48 +7867,37 @@ mark_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e) void -mark_var_expanding_copy_visitor::visit_target_symbol_format (target_symbol* e) +mark_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e) { - static bool function_synthesized = false; + string sname = e->base_name; if (is_active_lvalue (e)) - throw semantic_error("write to marker format not permitted", e->tok); + throw semantic_error("write to marker '" + sname + "' not permitted", e->tok); if (e->components.size() > 0) { switch (e->components[0].first) { case target_symbol::comp_literal_array_index: - throw semantic_error("marker format may not be used as array", + throw semantic_error("marker '" + sname + "' may not be used as array", e->tok); break; case target_symbol::comp_struct_member: - throw semantic_error("marker format may not be used as a structure", + throw semantic_error("marker '" + sname + "' may not be used as a structure", e->tok); break; default: - throw semantic_error ("invalid marker format use", e->tok); + throw semantic_error ("invalid marker '" + sname + "' use", e->tok); break; } } - string fname = string("_mark_format_get"); - - // Synthesize a function (if not already synthesized). - if (! function_synthesized) - { - function_synthesized = true; - functiondecl *fdecl = new functiondecl; - fdecl->tok = e->tok; - embeddedcode *ec = new embeddedcode; - ec->tok = e->tok; - - ec->code = string("strlcpy (THIS->__retvalue, CONTEXT->data, MAXSTRINGLEN); /* pure */"); - fdecl->name = fname; - fdecl->body = ec; - fdecl->type = pe_string; - sess.functions.push_back(fdecl); - } + string fname; + if (e->base_name == "$format") { + fname = string("_mark_format_get"); + } else { + fname = string("_mark_name_get"); + } // Synthesize a functioncall. functioncall* n = new functioncall; @@ -7923,10 +7914,10 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) if (e->base_name.substr(0,4) == "$arg") visit_target_symbol_arg (e); - else if (e->base_name == "$format") - visit_target_symbol_format (e); + else if (e->base_name == "$format" || e->base_name == "$name") + visit_target_symbol_context (e); else - throw semantic_error ("invalid target symbol for marker, $argN or $format expected", + throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected", e->tok); } @@ -8225,8 +8216,8 @@ mark_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;"; common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); s.op->newline() << "c->probe_point = smp->pp;"; - s.op->newline() << "c->data = (char *)smp->format;"; - + s.op->newline() << "c->marker_name = smp->name;"; + s.op->newline() << "c->marker_format = smp->format;"; s.op->newline() << "c->mark_va_list = args;"; s.op->newline() << "(*smp->ph) (c);"; s.op->newline() << "c->mark_va_list = NULL;"; diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 045772a3..52892e8d 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-09-09 Masami Hiramatsu + + * systemtap.base/marker.exp : Added testcases of $name. + 2008-09-06 Frank Ch. Eigler * systemtap.base/cmd_parse.exp: Adapt to sh-c-less "stap -c" diff --git a/testsuite/systemtap.base/marker.exp b/testsuite/systemtap.base/marker.exp index 89c0b8c3..0cacf60d 100644 --- a/testsuite/systemtap.base/marker.exp +++ b/testsuite/systemtap.base/marker.exp @@ -230,3 +230,48 @@ if {$kernel_markers_found == 0} { [lindex $kernel_marker_names 0] "foo"] stap_compile $TEST_NAME 0 $script } + +set TEST_NAME "K_MARKER18" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} else { + # Try compiling a script that prints the name string of a + # marker. + set script [format $kernel_script_arg \ + [lindex $kernel_marker_names 0] {\$name}] + stap_compile $TEST_NAME 1 $script +} + +set TEST_NAME "K_MARKER19" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} else { + # Try compiling a script that writes to a marker name string + # (which isn't allowed). + set script [format $kernel_script_arg2 \ + [lindex $kernel_marker_names 0] {\$name}] + stap_compile $TEST_NAME 0 $script +} + +set TEST_NAME "K_MARKER20" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} else { + # Try compiling a script that treats the marker name string as a + # structure (which isn't allowed). + set script [format $kernel_script_arg \ + [lindex $kernel_marker_names 0] {\$name->foo}] + stap_compile $TEST_NAME 0 $script +} + +set TEST_NAME "K_MARKER21" +if {$kernel_markers_found == 0} { + untested "$TEST_NAME : no kernel markers present" +} else { + # Try compiling a script that treats the marker name string like + # an array (which isn't allowed). + set script [format $kernel_script_arg \ + [lindex $kernel_marker_names 0] {\$name\[0\]}] + stap_compile $TEST_NAME 0 $script +} + diff --git a/translate.cxx b/translate.cxx index 2fe33314..e5435fac 100644 --- a/translate.cxx +++ b/translate.cxx @@ -881,6 +881,8 @@ c_unparser::emit_common_header () o->newline() << "struct kretprobe_instance *pi;"; o->newline() << "int regparm;"; o->newline() << "va_list *mark_va_list;"; + o->newline() << "const char * marker_name;"; + o->newline() << "const char * marker_format;"; o->newline() << "void *data;"; o->newline() << "#ifdef STP_TIMING"; o->newline() << "Stat *statp;"; -- cgit From 6270adc1ec2b89a201c932b94fb8ec8abc4e977f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:02:56 -0400 Subject: Add $argN context variables on per-process-syscall probes --- ChangeLog | 11 ++++++++ NEWS | 4 +++ stapprobes.5.in | 9 ++++-- tapset/ChangeLog | 4 +++ tapset/utrace.stp | 5 +++- tapsets.cxx | 83 ++++++++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 103 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index cb5a6f4b..df495cab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-09-09 Masami Hiramatsu + + * stapprobes.5.in: Added a description about $argN. + * NEWS: Ditto. + * tapsets.cxx (utrace_var_expanding_copy_visitor): Added + visit_target_symbol_arg() and visit_target_symbol_syscall(). + (visit_target_symbol_arg): New function for handling $argN. + (visit_target_symbol_syscall): New function for handling $syscall. + (visit_target_symbol): Use visit_target_symbol_arg() and + visit_target_symbol_syscall(). + 2008-09-09 Masami Hiramatsu * stapprobes.5.in : Added a line for $name context variable. diff --git a/NEWS b/NEWS index c7ddce45..b48870e2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ * What's new +- Additional context variables are available on user-space syscall probes. + - $argN ($arg1, $arg2, ... $arg6) in process(PATH_OR_PID).syscall + gives you the argument of the system call. + - Target process mode (stap -c CMD or -x PID) now implicitly restricts all "process.*" probes to the given child process. (It does not affect kernel.* or other probe types.) The CMD string is now executed directly, diff --git a/stapprobes.5.in b/stapprobes.5.in index ecc6956c..6e8c3ff2 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -421,8 +421,13 @@ probe gets called when a thread described by PID or PATH dies. A .B .syscall probe gets called when a thread described by PID or PATH makes a -system call. The system call number is available in the "$syscall" -context variable. +system call. The system call number is available in the +.BR $syscall +context variable, and the first 6 arguments of the system call +are available in the +.BR $argN +(ex. $arg1, $arg2, ...) context variable. + A .B .syscall.return probe gets called when a thread described by PID or PATH returns from a diff --git a/tapset/ChangeLog b/tapset/ChangeLog index d3117620..5a08ac63 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,7 @@ +2008-09-09 Masami Hiramatsu + + * utrace.stp: Added _utrace_syscall_arg(). + 2008-09-09 Masami Hiramatsu * marker.stp : New file, including marker context variable accessors. diff --git a/tapset/utrace.stp b/tapset/utrace.stp index 3831ca3c..2b661573 100644 --- a/tapset/utrace.stp +++ b/tapset/utrace.stp @@ -5,7 +5,10 @@ #include "syscall.h" %} - function _utrace_syscall_nr:long () %{ THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */ %} + +function _utrace_syscall_arg:long (n:long) %{ + THIS->__retvalue = *__stp_user_syscall_arg(current, CONTEXT->regs, (int)THIS->n); /* pure */ +%} diff --git a/tapsets.cxx b/tapsets.cxx index 4774c0f6..5941339c 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5846,6 +5846,8 @@ struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor enum utrace_derived_probe_flags flags; bool target_symbol_seen; + void visit_target_symbol_arg (target_symbol* e); + void visit_target_symbol_syscall (target_symbol* e); void visit_target_symbol (target_symbol* e); }; @@ -5923,18 +5925,61 @@ utrace_derived_probe::join_group (systemtap_session& s) void -utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) +utrace_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e) { - assert(e->base_name.size() > 0 && e->base_name[0] == '$'); + string argnum_s = e->base_name.substr(4,e->base_name.length()-4); + int argnum = atoi (argnum_s.c_str()); - if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN) - throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols", - e->tok); + if (flags != UDPF_SYSCALL) + throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", e->tok); - if (e->base_name != "$syscall") - throw semantic_error ("invalid target symbol for utrace probe, $syscall expected", - e->tok); + if (e->components.size() > 0) + { + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("utrace target variable '$argN' may not be used as array", + e->tok); + break; + case target_symbol::comp_struct_member: + throw semantic_error("utrace target variable '$argN' may not be used as a structure", + e->tok); + break; + default: + throw semantic_error ("invalid use of utrace target variable '$argN'", + e->tok); + break; + } + } + + // FIXME: max argnument number should not be hardcoded. + if (argnum < 1 || argnum > 6) + throw semantic_error ("invalid syscall argument number (1-6)", e->tok); + + bool lvalue = is_active_lvalue(e); + if (lvalue) + throw semantic_error("utrace '$argN' variable is read-only", e->tok); + // Remember that we've seen a target variable. + target_symbol_seen = true; + + // We're going to substitute a synthesized '_utrace_syscall_arg' + // function call for the '$argN' reference. + functioncall* n = new functioncall; + n->tok = e->tok; + n->function = "_utrace_syscall_arg"; + n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + + literal_number *num = new literal_number(argnum - 1); + num->tok = e->tok; + n->args.push_back(num); + + provide (this, n); +} + +void +utrace_var_expanding_copy_visitor::visit_target_symbol_syscall (target_symbol* e) +{ if (e->components.size() > 0) { switch (e->components[0].first) @@ -5956,12 +6001,12 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) bool lvalue = is_active_lvalue(e); if (lvalue) - throw semantic_error("utrace $syscall variable is read-only", e->tok); + throw semantic_error("utrace '$syscall' variable is read-only", e->tok); // Remember that we've seen a target variable. target_symbol_seen = true; - // We're going to substitute a synthesized '_syscall_nr_get' + // We're going to substitute a synthesized '_utrace_syscall_nr' // function call for the '$syscall' reference. functioncall* n = new functioncall; n->tok = e->tok; @@ -5971,6 +6016,24 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) provide (this, n); } +void +utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) +{ + assert(e->base_name.size() > 0 && e->base_name[0] == '$'); + + if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN) + throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols", + e->tok); + + if (e->base_name.substr(0,4) == "$arg") + visit_target_symbol_arg(e); + else if (e->base_name == "$syscall") + visit_target_symbol_syscall(e); + else + throw semantic_error ("invalid target symbol for utrace probe, $syscall or $argN expected", + e->tok); +} + struct utrace_builder: public derived_probe_builder { -- cgit From 5d67b47ccd850e53c6c6c72a6f63327faa190966 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:16:30 -0400 Subject: Add $return context variables on per-process-syscall.return probes --- ChangeLog | 10 ++++++++++ NEWS | 2 ++ stapprobes.5.in | 7 +++++-- tapset/ChangeLog | 4 ++++ tapset/utrace.stp | 4 ++++ tapsets.cxx | 32 ++++++++++++++++++++++---------- 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index df495cab..44cfc4cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-09-09 Masami Hiramatsu + + * stapprobes.5.in: Added a description about $return. + * NEWS: Ditto. + * tapsets.cxx (utrace_var_expanding_copy_visitor): Change + visit_target_symbol_syscall() to visit_target_symbol_context(). + (utrace_var_expanding_copy_visitor::visit_target_symbol_context): + Handle not only $syscall but also $return. + (utrace_var_expanding_copy_visitor::visit_target_symbol): Ditto. + 2008-09-09 Masami Hiramatsu * stapprobes.5.in: Added a description about $argN. diff --git a/NEWS b/NEWS index b48870e2..04ba292e 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ - Additional context variables are available on user-space syscall probes. - $argN ($arg1, $arg2, ... $arg6) in process(PATH_OR_PID).syscall gives you the argument of the system call. + - $return in process(PATH_OR_PID).syscall.return gives you the return + value of the system call. - Target process mode (stap -c CMD or -x PID) now implicitly restricts all "process.*" probes to the given child process. (It does not affect diff --git a/stapprobes.5.in b/stapprobes.5.in index 6e8c3ff2..36b36156 100644 --- a/stapprobes.5.in +++ b/stapprobes.5.in @@ -427,11 +427,14 @@ context variable, and the first 6 arguments of the system call are available in the .BR $argN (ex. $arg1, $arg2, ...) context variable. - A .B .syscall.return probe gets called when a thread described by PID or PATH returns from a -system call. The system call number is available in the "$syscall" +system call. The system call number is available in the +.BR $syscall +context variable, and the return value of the system call is available +in the +.BR $return context variable. A .B .itrace diff --git a/tapset/ChangeLog b/tapset/ChangeLog index 5a08ac63..3e2ebaf7 100644 --- a/tapset/ChangeLog +++ b/tapset/ChangeLog @@ -1,3 +1,7 @@ +2008-09-09 Masami Hiramatsu + + * utrace.stp: Added _utrace_syscall_return(). + 2008-09-09 Masami Hiramatsu * utrace.stp: Added _utrace_syscall_arg(). diff --git a/tapset/utrace.stp b/tapset/utrace.stp index 2b661573..34cb32c5 100644 --- a/tapset/utrace.stp +++ b/tapset/utrace.stp @@ -12,3 +12,7 @@ function _utrace_syscall_nr:long () %{ function _utrace_syscall_arg:long (n:long) %{ THIS->__retvalue = *__stp_user_syscall_arg(current, CONTEXT->regs, (int)THIS->n); /* pure */ %} + +function _utrace_syscall_return:long () %{ + THIS->__retvalue = *__stp_user_syscall_return_value(current, CONTEXT->regs); /* pure */ +%} diff --git a/tapsets.cxx b/tapsets.cxx index 5941339c..28f945fe 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5847,7 +5847,7 @@ struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor bool target_symbol_seen; void visit_target_symbol_arg (target_symbol* e); - void visit_target_symbol_syscall (target_symbol* e); + void visit_target_symbol_context (target_symbol* e); void visit_target_symbol (target_symbol* e); }; @@ -5978,22 +5978,24 @@ utrace_var_expanding_copy_visitor::visit_target_symbol_arg (target_symbol* e) } void -utrace_var_expanding_copy_visitor::visit_target_symbol_syscall (target_symbol* e) +utrace_var_expanding_copy_visitor::visit_target_symbol_context (target_symbol* e) { + string sname = e->base_name; + if (e->components.size() > 0) { switch (e->components[0].first) { case target_symbol::comp_literal_array_index: - throw semantic_error("utrace target variable '$syscall' may not be used as array", + throw semantic_error("utrace target variable '" + sname + "' may not be used as array", e->tok); break; case target_symbol::comp_struct_member: - throw semantic_error("utrace target variable '$syscall' may not be used as a structure", + throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure", e->tok); break; default: - throw semantic_error ("invalid use of utrace target variable '$syscall'", + throw semantic_error ("invalid use of utrace target variable '" + sname + "'", e->tok); break; } @@ -6001,7 +6003,17 @@ utrace_var_expanding_copy_visitor::visit_target_symbol_syscall (target_symbol* e bool lvalue = is_active_lvalue(e); if (lvalue) - throw semantic_error("utrace '$syscall' variable is read-only", e->tok); + throw semantic_error("utrace '" + sname + "' variable is read-only", e->tok); + + string fname; + if (sname == "$return") + { + if (flags != UDPF_SYSCALL_RETURN) + throw semantic_error ("only \"process(PATH_OR_PID).syscall.return\" support $return.", e->tok); + fname = "_utrace_syscall_return"; + } + else + fname = "_utrace_syscall_nr"; // Remember that we've seen a target variable. target_symbol_seen = true; @@ -6010,7 +6022,7 @@ utrace_var_expanding_copy_visitor::visit_target_symbol_syscall (target_symbol* e // function call for the '$syscall' reference. functioncall* n = new functioncall; n->tok = e->tok; - n->function = "_utrace_syscall_nr"; + n->function = fname; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session provide (this, n); @@ -6027,10 +6039,10 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) if (e->base_name.substr(0,4) == "$arg") visit_target_symbol_arg(e); - else if (e->base_name == "$syscall") - visit_target_symbol_syscall(e); + else if (e->base_name == "$syscall" || e->base_name == "$return") + visit_target_symbol_context(e); else - throw semantic_error ("invalid target symbol for utrace probe, $syscall or $argN expected", + throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected", e->tok); } -- cgit From 256d22cfb336b4cf0ec5b35bab89ca55ff5ce9ee Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 9 Sep 2008 16:32:59 -0400 Subject: Added tests for utrace-syscall probe context variables. --- testsuite/ChangeLog | 12 ++++++++++++ testsuite/buildok/per-process-syscall.stp | 18 ++++++++++++++++++ testsuite/semko/utrace15.stp | 4 ++++ testsuite/semko/utrace16.stp | 4 ++++ testsuite/semko/utrace17.stp | 4 ++++ testsuite/semko/utrace18.stp | 4 ++++ testsuite/semko/utrace19.stp | 4 ++++ testsuite/semko/utrace20.stp | 4 ++++ testsuite/semko/utrace21.stp | 4 ++++ testsuite/semko/utrace22.stp | 4 ++++ 10 files changed, 62 insertions(+) create mode 100755 testsuite/buildok/per-process-syscall.stp create mode 100755 testsuite/semko/utrace15.stp create mode 100755 testsuite/semko/utrace16.stp create mode 100755 testsuite/semko/utrace17.stp create mode 100755 testsuite/semko/utrace18.stp create mode 100755 testsuite/semko/utrace19.stp create mode 100755 testsuite/semko/utrace20.stp create mode 100755 testsuite/semko/utrace21.stp create mode 100755 testsuite/semko/utrace22.stp diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 52892e8d..4f0f567d 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2008-09-09 Masami Hiramatsu + + * buildok/per-process-syscall.stp: New test, for process.syscall test. + * semko/utrace15.stp: Ditto. + * semko/utrace16.stp: Ditto. + * semko/utrace17.stp: Ditto. + * semko/utrace18.stp: Ditto. + * semko/utrace19.stp: Ditto. + * semko/utrace20.stp: Ditto. + * semko/utrace21.stp: Ditto. + * semko/utrace22.stp: Ditto. + 2008-09-09 Masami Hiramatsu * systemtap.base/marker.exp : Added testcases of $name. diff --git a/testsuite/buildok/per-process-syscall.stp b/testsuite/buildok/per-process-syscall.stp new file mode 100755 index 00000000..c2c41c0b --- /dev/null +++ b/testsuite/buildok/per-process-syscall.stp @@ -0,0 +1,18 @@ +#! stap -p4 +# +# per-process syscall trace test + +probe process.syscall { +print($syscall) +print($arg1) +print($arg2) +print($arg3) +print($arg4) +print($arg5) +print($arg6) +} + +probe process.syscall.return { +print($syscall) +print($return) +} diff --git a/testsuite/semko/utrace15.stp b/testsuite/semko/utrace15.stp new file mode 100755 index 00000000..56d91e89 --- /dev/null +++ b/testsuite/semko/utrace15.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# write to $argN +probe process("/bin/cat").syscall { $arg1 = 1 } diff --git a/testsuite/semko/utrace16.stp b/testsuite/semko/utrace16.stp new file mode 100755 index 00000000..f88923d6 --- /dev/null +++ b/testsuite/semko/utrace16.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# treat $argN as a pointer +probe process("/bin/cat").syscall { print($arg1->foo) } diff --git a/testsuite/semko/utrace17.stp b/testsuite/semko/utrace17.stp new file mode 100755 index 00000000..3a296dff --- /dev/null +++ b/testsuite/semko/utrace17.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# treat $argN as an array +probe process("/bin/cat").syscall { print($arg1[0]) } diff --git a/testsuite/semko/utrace18.stp b/testsuite/semko/utrace18.stp new file mode 100755 index 00000000..5d4960db --- /dev/null +++ b/testsuite/semko/utrace18.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# write to $return +probe process("/bin/cat").syscall.return { $return = 1 } diff --git a/testsuite/semko/utrace19.stp b/testsuite/semko/utrace19.stp new file mode 100755 index 00000000..3d30dc5e --- /dev/null +++ b/testsuite/semko/utrace19.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# access to $return from syscall entry +probe process("/bin/cat").syscall { print($return) } diff --git a/testsuite/semko/utrace20.stp b/testsuite/semko/utrace20.stp new file mode 100755 index 00000000..15fdc4c5 --- /dev/null +++ b/testsuite/semko/utrace20.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# treat $return as an array +probe process("/bin/cat").syscall { print($return[0]) } diff --git a/testsuite/semko/utrace21.stp b/testsuite/semko/utrace21.stp new file mode 100755 index 00000000..aa29ec59 --- /dev/null +++ b/testsuite/semko/utrace21.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# treat $return as a pointer/structure +probe process("/bin/cat").syscall.return { print($return->foo) } diff --git a/testsuite/semko/utrace22.stp b/testsuite/semko/utrace22.stp new file mode 100755 index 00000000..710810f6 --- /dev/null +++ b/testsuite/semko/utrace22.stp @@ -0,0 +1,4 @@ +#! stap -p2 + +# access to $argN from syscall return +probe process("/bin/cat").syscall.return { print($arg1) } -- cgit