summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog34
-rw-r--r--NEWS8
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Introduction.xml33
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Scripts.xml46
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/SystemTap_Beginners_Guide.ent3
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Understanding_How_SystemTap_Works.xml39
-rw-r--r--runtime/ChangeLog28
-rw-r--r--runtime/addr-map.c181
-rw-r--r--runtime/loc2c-runtime.h230
-rw-r--r--runtime/regs-ia64.c21
-rw-r--r--runtime/runtime.h1
-rw-r--r--runtime/sym.c2
-rw-r--r--runtime/syscall.h42
-rw-r--r--runtime/task_finder.c6
-rw-r--r--stapprobes.5.in16
-rw-r--r--tapset/ChangeLog12
-rw-r--r--tapset/marker.stp22
-rw-r--r--tapset/utrace.stp9
-rw-r--r--tapsets.cxx152
-rw-r--r--testsuite/ChangeLog16
-rwxr-xr-xtestsuite/buildok/per-process-syscall.stp18
-rwxr-xr-xtestsuite/semko/utrace15.stp4
-rwxr-xr-xtestsuite/semko/utrace16.stp4
-rwxr-xr-xtestsuite/semko/utrace17.stp4
-rwxr-xr-xtestsuite/semko/utrace18.stp4
-rwxr-xr-xtestsuite/semko/utrace19.stp4
-rwxr-xr-xtestsuite/semko/utrace20.stp4
-rwxr-xr-xtestsuite/semko/utrace21.stp4
-rwxr-xr-xtestsuite/semko/utrace22.stp4
-rw-r--r--testsuite/systemtap.base/marker.exp45
-rw-r--r--translate.cxx2
31 files changed, 837 insertions, 161 deletions
diff --git a/ChangeLog b/ChangeLog
index 09f661ae..44cfc4cc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * 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 <mhiramat@redhat.com>
+
+ * 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 <mhiramat@redhat.com>
+
+ * 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 <fche@elastic.org>
* tapsets.cxx (build_blacklist): Add some x86 raw port-io spots.
diff --git a/NEWS b/NEWS
index ab035593..04ba292e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,13 @@
* 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.
+ - $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 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.
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 @@
<chapter id="introduction">
<title>Introduction</title>
<para>
- 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 <command>netstat</command>, <command>ps</command>, <command>top</command>, and <command>iostat</command>; however, SystemTap is designed to provide information that is more "granular" in nature.
</para>
-<formalpara>
+ <para>
+ For system administrators, SystemTap can be used as a performance monitoring tool for &PROD;. 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.
+ </para>
+
+<!--
+ <para>
+ SystemTap was developed as a Linux version of the DTrace tool (for <trademark>Sun Solaris</trademark>).
+ </para>
+ -->
+<section id="goals">
<title>Goals</title>
- <para>TBD</para>
-</formalpara>
+ <para>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.</para>
+
+ <para>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 <firstterm>tapsets</firstterm> or SystemTap scripts.</para>
+
+ <para>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.</para>
+
+ <para>In line with that, the main goal of the <citetitle>SystemTap Beginner's Guide</citetitle> is two-fold:</para>
+
+ <itemizedlist>
+ <listitem><para>To introduce users to SystemTap, familiarize them with its architecture, and provide setup instructions for all kernel types.</para></listitem>
+
+ <listitem><para>To provide pre-written SystemTap scripts for monitoring and forensic tasks, along with instructions on how to analyze their output.</para></listitem>
+ </itemizedlist>
+<!-- </formalpara> -->
<remark>above, Short description on the underlying goals of SystemTap_Beginners_Guide, what we want to teach users.</remark>
-
+</section>
<section id="intro-usage">
<title>Usage</title>
@@ -25,7 +46,7 @@
<section id="intro-systemtap-vs-others">
<title>SystemTap Versus Other Monitoring Tools</title>
<remark>
- 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)
</remark>
<formalpara>
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 @@
+<?xml version='1.0'?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+]>
+
+<section id="scripts">
+ <title>SystemTap Scripts</title>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ As stated in <xref linkend="understanding-how-systemtap-works"/>, SystemTap scripts are made up of two components: <emphasis>events</emphasis> and <emphasis>handlers</emphasis>. Once a SystemTap session is underway, SystemTap monitors the operating system for the specified events and executes the handlers as they occur.
+ </para>
+
+<note>
+ <title>Note</title>
+ <para>An event and its corresponding handler is collectively called a <emphasis>probe</emphasis>. A SystemTap script can have multiple probes, in the same manner that each event can have multiple corresponding handlers.</para>
+</note>
+
+ <para>
+ In terms of application development, using events and handlers is similar to inserting <command>print</command> statements in a program's sequence of commands. These <command>print</command> statements allow you to view a history of commands executed once the program is run.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+
+
+ <section id="systemtapscript-format">
+ <title>Format</title>
+ <para>
+ SystemTap scripts use the following format:
+ </para>
+ </section>
+
+ <!-- <section id="SystemTap_Beginners_Guide-Test-Section_2_Test">
+ <title>Section 2 Test</title>
+ <para>
+ Test of a section
+ </para>
+ </section>-->
+
+</section>
+
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 @@
<!ENTITY PRODUCT "Red_Hat_Enterprise_Linux 5">
<!ENTITY BOOKID "SystemTap_Beginners_Guide">
-<!ENTITY YEAR "2009"> \ No newline at end of file
+<!ENTITY YEAR "2009">
+<!ENTITY RHEL "Red Hat Enterprise Linux 5"> \ 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..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
@@ -8,21 +8,52 @@
Short summary; probes, handlers, events
</remark>
+ <para>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.</para>
+
+ <para> The essential idea behind a SystemTap script is to name <emphasis>events</emphasis>, and to give them <emphasis>handlers</emphasis>. 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.</para>
+
+ <para>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.</para>
+
<section id="understanding-architecture-tools">
<title>Architecture</title>
<remark>
- add diagram, describe architecture, enumerate common tools
+ ** add diagram, describe architecture, enumerate common tools
</remark>
- </section>
+
+ <remark>
+ ** architecture diagram must be simpler, if at all included
+ </remark>
+
+ <remark>
+ ** add design advantages? e.g. "building kmods on-the-fly allows safer execution of script etc etc"
+ </remark>
+
+ <para>A SystemTap session begins when you run a SystemTap script. This session occurs in the following fashion:</para>
+
+<procedure>
+ <title>SystemTap Session</title>
+ <step><para>SystemTap first translates the script to C, running the system C compiler to create a kernel module from it.</para></step>
+
+ <step><para>SystemTap then loads the module, then enables all the probed events by "hooking" those events into the kernel.</para></step>
+
+ <step><para>As the events occur, their corresponding handlers are executed.</para></step>
+ <step><para>Once the SystemTap session is terminated, the hooked events are disconnected from the kernel; afterwards, the kernel module is unloaded.</para></step>
+</procedure>
+
+<para>This sequence is driven from a single command-line program: <command>stap</command>. This program is SystemTap's main front-end tool. For more information about <command>stap</command>, refer to <command>man stap</command> (once SystemTap is set up on your machine).</para>
+
+</section>
+<xi:include href="Scripts.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+<!--
<section id="understanding-scripts">
<title>SystemTap Scripts</title>
<remark>
- 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)
</remark>
</section>
-
+ -->
<section id="understanding-tapsets">
<title>Tapsets</title>
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 8f20ed11..f7a844d8 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,31 @@
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * 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 <mhiramat@redhat.com>
+
+ * syscall.h: Added ia64 support.
+
+2008-09-09 Mark Wielaard <mwielaard@redhat.com>
+
+ * sym.c (_stp_kallsyms_lookup): Correct this_section_offset
+ calculation.
+
+2008-09-08 Tim Moore <timoore@redhat.com>
+
+ 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 <fche@elastic.org>
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++){ \
- __stp_put_asm((u8)(value>>((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++){ \
+ __stp_put_asm((u8)(value>>((size-i-1)*8)&0xff), \
+ (u64)addr+i,_bad); \
+ if (_bad) \
+ break; \
+ } \
+ if (_bad) \
+ STORE_DEREF_FAULT(addr); \
})
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/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)
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;
diff --git a/runtime/syscall.h b/runtime/syscall.h
index 24e93463..24fc7b1c 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 &regs->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,20 @@ __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, unsigned long **cache)
+{
+ if (n > 5) {
+ _stp_error("syscall arg > 5");
+ return NULL;
+ }
+ return __ia64_fetch_register(n + 32, regs, cache);
+}
+#endif
+
#endif /* _SYSCALL_H_ */
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();
diff --git a/stapprobes.5.in b/stapprobes.5.in
index 5281c40e..36b36156 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -421,12 +421,20 @@ 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
-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
@@ -520,6 +528,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..3e2ebaf7 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,15 @@
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * utrace.stp: Added _utrace_syscall_return().
+
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * utrace.stp: Added _utrace_syscall_arg().
+
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * marker.stp : New file, including marker context variable accessors.
+
2008-09-01 Frank Ch. Eigler <fche@elastic.org>
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/tapset/utrace.stp b/tapset/utrace.stp
index 3831ca3c..34cb32c5 100644
--- a/tapset/utrace.stp
+++ b/tapset/utrace.stp
@@ -5,7 +5,14 @@
#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 */
+%}
+
+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 64fa9d34..28f945fe 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;";
@@ -5844,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_context (target_symbol* e);
void visit_target_symbol (target_symbol* e);
};
@@ -5921,32 +5925,77 @@ 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 <functioncall*> (this, n);
+}
+
+void
+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;
}
@@ -5954,21 +6003,49 @@ 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 '" + 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;
- // 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;
- n->function = "_utrace_syscall_nr";
+ n->function = fname;
n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
provide <functioncall*> (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" || e->base_name == "$return")
+ visit_target_symbol_context(e);
+ else
+ throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected",
+ e->tok);
+}
+
struct utrace_builder: public derived_probe_builder
{
@@ -7758,7 +7835,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 +7942,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 +7989,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 +8291,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 14d20744..3effc92f 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -3,6 +3,22 @@
* systemtap.base/uprobes.*: Tweak regexps for read-only src tree
tolerance.
+2008-09-09 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * 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 <mhiramat@redhat.com>
+
+ * systemtap.base/marker.exp : Added testcases of $name.
+
2008-09-06 Frank Ch. Eigler <fche@elastic.org>
* systemtap.base/cmd_parse.exp: Adapt to sh-c-less "stap -c"
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) }
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;";