diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/staprun/ChangeLog | 412 | ||||
-rw-r--r-- | runtime/staprun/ChangeLog~ | 396 | ||||
-rw-r--r-- | runtime/staprun/Makefile | 15 | ||||
-rw-r--r-- | runtime/staprun/ctl.c | 40 | ||||
-rw-r--r-- | runtime/staprun/mainloop.c | 374 | ||||
-rw-r--r-- | runtime/staprun/relay.c | 189 | ||||
-rw-r--r-- | runtime/staprun/relay_old.c | 277 | ||||
-rw-r--r-- | runtime/staprun/staprun.c | 158 | ||||
-rw-r--r-- | runtime/staprun/staprun.h | 91 | ||||
-rw-r--r-- | runtime/staprun/stp_merge.c | 119 | ||||
-rw-r--r-- | runtime/staprun/stp_merge.c~ | 119 | ||||
-rw-r--r-- | runtime/staprun/symbols.c | 226 |
12 files changed, 2416 insertions, 0 deletions
diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog new file mode 100644 index 00000000..9f8a6595 --- /dev/null +++ b/runtime/staprun/ChangeLog @@ -0,0 +1,412 @@ +2007-03-14 Martin Hunt <hunt@redhat.com> + + * staprun.c: Renamed from stpd.c. Removed quiet and print_only + options. Added "-x" option as an alias for "-t". Removed "-m" + option. Updated arg processing to leave 4 slots for modoptions[]. + Bump the priority of staprun. + * ctl.c: New. Transport control channel functions. + * relay.c: New. Relayfs control functions for new transport. + * relay_old.c: New. Relayfs control functions for older + versions of relayfs. + * mainloop.c: New. Staprun main loop. + * staprun.h: Renamed from librelay.h. Cleaned up. + + * stap_merge.c: Renamed. Updated for modified save format. + + +2006-12-11 Martin Hunt <hunt@redhat.com> + + * symbols.c (get_sections): Set buffer sizes to large enough + sizes to hold all possible values, but also include checks in case + we are wrong. + +2006-11-15 Martin Hunt <hunt@redhat.com> + + * symbols.c (do_kernel_symbols): Add sizeof(long) to sym_base + to preserve 64-bit alignment. + +2006-11-09 Martin Hunt <hunt@redhat.com> + + * librelay.c: Change all references to transport messages + to use the new names with "_stp" prefix. + (stp_main_loop): For STP_SYMBOLS, check pointer size and + endianess to confirm staprun is compatible with the kernel. + + * librelay.h: Move a bunch of common includes here. + * stpd.c: Cleanup includes. + * symbols.c: Ditto. + +2006-11-02 Martin Hunt <hunt@redhat.com> + + * symbols.c: New file. Sends symbol and module information to + the systemtap module. + + * librelay.c (stp_main_loop): Add STP_MODULE and STP_SYMBOLS + message handling. + + * librelay.h: Add some new function prototypes. + + * Makefile (CFLAGS): Set to be the same as for building modules. + Added symbols.c to sources. + +2006-10-10 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (merge_output): Add check for min when writing + output, otherwise last write happens twice. + +2006-09-26 David Smith <dsmith@redhat.com> + + * Makefile: Changed 'stpd' references to 'staprun'. + * librelay.c: Ditto. + * stpd.c: Ditto. + +2006-09-25 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (kill_percpu_threads): Remove printf. + (wait_for_percpu_threads): New. + (process_subbufs): Remove processing, processing_mutex, exit + thread if exiting flag set. + (read_last_buffers): Removed. + (cleanup_and_exit): Remove call to read_last_buffers, wait for + threads to read flushed buffers instead. + (stp_main_loop): Remove mutex init. + +2006-09-22 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (init_relayfs): Cleanup if stp_check fails. + +2006-09-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (init_relayfs): Add debugfs path to relay files and + add new systemtap directory to path. + (init_stp): rmmod module on failure. + (merge_output): Remove debugging printfs left in code. + (close_relay_files): Clear relay_file descriptor after close. + (cleanup_and_exit): Allow cleanup and exit even if there was an + error opening relay files. + (stp_main_loop): Call cleanup_and_exit() if init_relayfs() fails. + +2006-09-18 Martin Hunt <hunt@redhat.com> + + * stpd.c (usage): Remove "-m" option. + (main): Print warning if "-m" is used. + * librelay.c (merge_output): Rewrite to handle + new format that support binary. + (stp_main_loop): Read merge option from the + transport info message. + +2006-09-13 Martin Hunt <hunt@redhat.com> + + * librelay.c (init_relayfs): Exec stp_check and find + relay_filebase. + + * librelay.h (stp_main_loop): Fix declaration of init_stp(). + + * stpd.c (usage): Remove "-r" option. + (main): Don't find stpd_filebase and don't send it to init_stp(). + + +2006-08-02 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Use modname rather than driver_pid in + stpd_filebase. + +2006-07-20 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): If module doesn't start, kill any + target command. + +2006-06-23 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (cleanup_and_exit): Close relay files even if + not merging. + +2006-06-13 Martin Hunt <hunt@redhat.com> + + * librelay.c (start_cmd): Rewrite using sigwait() to eliminate + a race. + +2006-05-18 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): Set output to always be line + buffered. + +2006-04-08 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): Write with fwrite() instead + of fputs() so we can write binary data. + +2006-04-05 Martin Hunt <hunt@redhat.com> + * librelay.c (merge_output): Remove ANSI codes and write + warning to stderr. + +2006-04-05 Martin Hunt <hunt@redhat.com> + * librelay.c (merge_output): Set the output filename if necessary. + (merge_output): + + * stpd.c (main): Don't reset output_filename just because + relayfs is possible. Move that code to librelay.c. + +2006-04-04 Roland McGrath <roland@redhat.com> + + * stpd.c (main): Cast f_type when comparing; type differs by machine. + +2006-04-04 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Check that /mnt/relay is actually relayfs. + +2006-03-15 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Add runtime check for relayfs vs relay-on-proc. + +2006-03-06 Martin Hunt <hunt@redhat.com> + + * librelay.c (start_cmd): Set proper uid/gid before execing + command. + (system_cmd): New function. + (cleanup_and_exit): Wait for any child processes to complete. + (stp_main_loop): Recognize STP_SYSTEM message. + + * stpd.c (main): Add support for "-u username". + +2006-02-25 Martin Hunt <hunt@redhat.com> + + * librelay.c (init_stp): Better error handling and cleanup. + +2006-02-23 Frank Ch. Eigler <fche@elastic.org> + + PR 1304 + * stpd.c (mdooptions): New array. + (main): Populate it with leftover arguments. + * librelay.c (init_stp): Pass it to execve(). + +2005-12-08 Frank Ch. Eigler <fche@elastic.org> + + PR 1937 + * stpd.c (main): Support new "-d" option. + (usage): Document it. + * librelay.c (driver_poll): New function to react to death of + driver process. + (stp_main_loop): Call it if "-d PID" given. Treat SIGHUP like others. + +2005-10-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c: Move output_file var to stpd.c. + (stp_main_loop): If the output_file option was specified, + and streaming mode is being used, send output to the file + instead of stdout. If !streaming, send output to the file + instead of probe.out. + * stpd.c (usage): Add comment for -o option. + (main): Add -o option. + +2005-10-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (merge_output): Switch to binary TIMESTAMP. + * stp_dump.c (main): Switch to binary TIMESTAMP. + * stp_merge.c (main): Switch to binary TIMESTAMP. + +2005-10-14 Tom Zanussi <zanussi@us.ibm.com> + + PR 1476 + * librelay.c: Add flag for buffer processing. + (reader_thread): Disable/enable cancel state around buffer + processing, and update flag to show we're busy processing. + (cleanup_and_exit): Wait for any threads busy processing. + (stp_main_loop): Initialize processing mutex. + +2005-09-06 Martin Hunt <hunt@redhat.com> + + * librelay.c: Remove all USE_PROCFS ifdefs. + (sig_usr): Signal handler for SIGUSR1. + (start_cmd): New function to handle "-c" option, forks() + off a new process then waits for SIGUSR1 to exec it. + (init_stp): Call start_cmd(). + (stp_main_loop): Set a signal handler for SIGCHLD. + + * stpd.c (main): Add "-t" and "-c" options. + (usage): Update with new options. + +2005-08-29 Martin Hunt <hunt@redhat.com> + + * stpd.c main): Add enable_relayfs flag. + Turn it off with "-r". + +2005-08-24 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): Removed the "Exiting..." + message for now. + +2005-08-24 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): Reestablish signal handler so + impatient people don't hit ^C twice and terminate the + program before it saves the data and removes the module. + Also print a message to stderr that it is exiting. + (stp_main_loop): Write OOB data (warnings, errors, etc) + to stderr instead of stdout. + * librelay.h: Write debug info to stderr. + * Makefile: add librelay.h to dependencies. + +2005-08-23 Martin Hunt <hunt@redhat.com> + + * librelay.c (merge_output): Don't add an extra \n. + +2005-08-23 Martin Hunt <hunt@redhat.com> + + * librelay.c (read_last_buffers): New function. Directly grab the + last buffers. + (info_pending): Deleted. + (request_last_buffers): Deleted. + +2005-08-22 Martin Hunt <hunt@redhat.com> + + * Makefile (debug): Add debug target. + * librelay.h (dbug): Define. + * librelay.c: Enable some dbug lines. + +2005-08-19 Martin Hunt <hunt@redhat.com> + + * librelay.c (reader_thread): Check the return value for write(). + +2005-08-19 Frank Ch. Eigler <fche@elastic.org> + + * librelay.c (modpath): New global. Use it for insmod only. + * stpd.c (main): Set both modpath and modname, to support + modules specified by full path name. + +2005-08-19 Martin Hunt <hunt@redhat.com> + + * stpd.c (main): Simplify buffer size code. + * librelay.c: Major changes to support procfs instead of netlink. + +2005-08-03 Tom Zanussi <trz@us.ibm.com> + + * librelay.c: Track subbuf info requests/replies + so we know unequivocally when it's ok to do final + processing. + (reader_thread): Remove buffer-full warning. + +2005-08-03 Martin Hunt <hunt@redhat.com> + * librelay.c (init_stp): Change variable name to eliminate shadow warning. + +2005-08-03 Martin Hunt <hunt@redhat.com> + * librelay.c (open_control_channel): Set the receive buffer + to 512K, or the max allowed. + + * stpd.c: Remove "-n" subbug option and change "-b" option + so you can specify buffering in different ways. Add a verbose option. + Exec the "stp_check" script. + +2005-08-01 Frank Ch. Eigler <fche@redhat.com> + + * librelay.c: Correct fwrite api usage. + * all: Correct copyright holder name. + +2005-08-01 Martin Hunt <hunt@redhat.com> + + * librelay.h: Get structs and enums from + ../transport/transport_msgs.h to eliminate duplication. + + * librelay.c (send_request): Retry if send fails. + (open_relayfs_files): Use fopen() instead of open() for the + percpu tmpfiles. + (request_last_buffers): Just send cpu number for STP_BUF_INFO request. + (reader_thread): Ditto. + (process_subbufs): Use fwrite_unlocked() instead of write(). + (sigchld): Removed. + (init_stp): Go back to using system() instead of fork and exec + to load module. When done, send a TRANSPORT_INFO request. + (cleanup_and_exit): Change parameter to simple flag to + indicate if the module needs removing. + (sigproc): Remove complicated logic and just send STP_EXIT. + (stp_main_loop): When receiving STP_TRANSPORT_INFO, set + the local params and reply with a STP_START. When + receiving STP_START, there was an error, so cleanup and exit. + + * stpd.c (main): Added new options to set number of + buffers and their size. + +2005-07-29 Roland McGrath <roland@redhat.com> + + * librelay.c (process_subbufs): Use unsigned for I. + (sigproc): Add __attribute__((unused)) on parameter. + (sigchld): Likewise. Avoid shadowing global variable name. + (stp_main_loop): Add a cast. + +2005-07-18 Martin Hunt <hunt@redhat.com> + + * stp_merge.c (main): Fix dropped count calculation. + +2005-07-14 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (reader_thread): Add missing pthread_mutex_lock + +2005-07-14 Frank Ch. Eigler <fche@redhat.com> + + * stpd.c (main): Pass !quiet mode to init_stp(). + * librelay.c (init_relayfs): Be quiet if !print_totals. + +2005-07-13 Martin Hunt <hunt@redhat.com> + + * stpd.c (usage): Fix usage string. + + * librelay.c (init_stp): Change last arg to NULL, not 0. + +2005-07-08 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigchld): Signal handler to detect + completion of module loading. + (init_stp): Use fork/exec instead of system() so + we can get async signal of module load success/failure. + (cleanup_and_exit): New function. + (sigproc): If module is not loaded, don't send message to it. + (stp_main_loop): Call cleanup_and_exit() when STP_EXIT + is received. Don't send a request for the transport + mode. The module will send notification to the daemon + when it is ready. + + * stpd.c (main): Don't print message until module + is loaded. + +2005-07-01 Martin Hunt <hunt@redhat.com> + + * librelay.c: Removed the color coding of cpu output. + +2005-06-28 Martin Hunt <hunt@redhat.com> + + * librelay.c (merge_output): Use unlocked stdio + to improve speed. + + * stp_merge.c: New file. + + * Makefile: Add stp_merge. + +2005-06-27 Martin Hunt <hunt@redhat.com> + + * stpd.c (main): Add new command line arg, "-m" + to disable the per-cpu merging. + + * librelay.c (merge_output): Replacement for sort_output(). + Efficiently merges per-cpu streams. + + +2005-06-20 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c: Large refactoring, important changes are + added transport_mode command, for relayfs transport + display results only when probe completes and/or write + output file, merge, sort and delete the per-cpu files + in postprocessing, refactor so that relayfs files aren't + created until transport command received, removed sigalrm, + read the final subbuffers on exit + + * stpd.c: Remove all command-line args except for -p + and -q as well as all code related to buffer sizes. + + * librelay.h: Add transport mode command and struct. + +2005-05-16 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): If STP_EXIT send fails, keep retrying + every 10ms. + (init_stp): Don't set n_subbufs and subbuf_size params. diff --git a/runtime/staprun/ChangeLog~ b/runtime/staprun/ChangeLog~ new file mode 100644 index 00000000..858f4e66 --- /dev/null +++ b/runtime/staprun/ChangeLog~ @@ -0,0 +1,396 @@ +2006-12-11 Martin Hunt <hunt@redhat.com> + + * symbols.c (get_sections): Set buffer sizes to large enough + sizes to hold all possible values, but also include checks in case + we are wrong. + +2006-11-15 Martin Hunt <hunt@redhat.com> + + * symbols.c (do_kernel_symbols): Add sizeof(long) to sym_base + to preserve 64-bit alignment. + +2006-11-09 Martin Hunt <hunt@redhat.com> + + * librelay.c: Change all references to transport messages + to use the new names with "_stp" prefix. + (stp_main_loop): For STP_SYMBOLS, check pointer size and + endianess to confirm staprun is compatible with the kernel. + + * librelay.h: Move a bunch of common includes here. + * stpd.c: Cleanup includes. + * symbols.c: Ditto. + +2006-11-02 Martin Hunt <hunt@redhat.com> + + * symbols.c: New file. Sends symbol and module information to + the systemtap module. + + * librelay.c (stp_main_loop): Add STP_MODULE and STP_SYMBOLS + message handling. + + * librelay.h: Add some new function prototypes. + + * Makefile (CFLAGS): Set to be the same as for building modules. + Added symbols.c to sources. + +2006-10-10 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (merge_output): Add check for min when writing + output, otherwise last write happens twice. + +2006-09-26 David Smith <dsmith@redhat.com> + + * Makefile: Changed 'stpd' references to 'staprun'. + * librelay.c: Ditto. + * stpd.c: Ditto. + +2006-09-25 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (kill_percpu_threads): Remove printf. + (wait_for_percpu_threads): New. + (process_subbufs): Remove processing, processing_mutex, exit + thread if exiting flag set. + (read_last_buffers): Removed. + (cleanup_and_exit): Remove call to read_last_buffers, wait for + threads to read flushed buffers instead. + (stp_main_loop): Remove mutex init. + +2006-09-22 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (init_relayfs): Cleanup if stp_check fails. + +2006-09-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (init_relayfs): Add debugfs path to relay files and + add new systemtap directory to path. + (init_stp): rmmod module on failure. + (merge_output): Remove debugging printfs left in code. + (close_relay_files): Clear relay_file descriptor after close. + (cleanup_and_exit): Allow cleanup and exit even if there was an + error opening relay files. + (stp_main_loop): Call cleanup_and_exit() if init_relayfs() fails. + +2006-09-18 Martin Hunt <hunt@redhat.com> + + * stpd.c (usage): Remove "-m" option. + (main): Print warning if "-m" is used. + * librelay.c (merge_output): Rewrite to handle + new format that support binary. + (stp_main_loop): Read merge option from the + transport info message. + +2006-09-13 Martin Hunt <hunt@redhat.com> + + * librelay.c (init_relayfs): Exec stp_check and find + relay_filebase. + + * librelay.h (stp_main_loop): Fix declaration of init_stp(). + + * stpd.c (usage): Remove "-r" option. + (main): Don't find stpd_filebase and don't send it to init_stp(). + + +2006-08-02 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Use modname rather than driver_pid in + stpd_filebase. + +2006-07-20 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): If module doesn't start, kill any + target command. + +2006-06-23 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (cleanup_and_exit): Close relay files even if + not merging. + +2006-06-13 Martin Hunt <hunt@redhat.com> + + * librelay.c (start_cmd): Rewrite using sigwait() to eliminate + a race. + +2006-05-18 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): Set output to always be line + buffered. + +2006-04-08 Martin Hunt <hunt@redhat.com> + + * librelay.c (stp_main_loop): Write with fwrite() instead + of fputs() so we can write binary data. + +2006-04-05 Martin Hunt <hunt@redhat.com> + * librelay.c (merge_output): Remove ANSI codes and write + warning to stderr. + +2006-04-05 Martin Hunt <hunt@redhat.com> + * librelay.c (merge_output): Set the output filename if necessary. + (merge_output): + + * stpd.c (main): Don't reset output_filename just because + relayfs is possible. Move that code to librelay.c. + +2006-04-04 Roland McGrath <roland@redhat.com> + + * stpd.c (main): Cast f_type when comparing; type differs by machine. + +2006-04-04 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Check that /mnt/relay is actually relayfs. + +2006-03-15 Tom Zanussi <zanussi@us.ibm.com> + + * stpd.c (main): Add runtime check for relayfs vs relay-on-proc. + +2006-03-06 Martin Hunt <hunt@redhat.com> + + * librelay.c (start_cmd): Set proper uid/gid before execing + command. + (system_cmd): New function. + (cleanup_and_exit): Wait for any child processes to complete. + (stp_main_loop): Recognize STP_SYSTEM message. + + * stpd.c (main): Add support for "-u username". + +2006-02-25 Martin Hunt <hunt@redhat.com> + + * librelay.c (init_stp): Better error handling and cleanup. + +2006-02-23 Frank Ch. Eigler <fche@elastic.org> + + PR 1304 + * stpd.c (mdooptions): New array. + (main): Populate it with leftover arguments. + * librelay.c (init_stp): Pass it to execve(). + +2005-12-08 Frank Ch. Eigler <fche@elastic.org> + + PR 1937 + * stpd.c (main): Support new "-d" option. + (usage): Document it. + * librelay.c (driver_poll): New function to react to death of + driver process. + (stp_main_loop): Call it if "-d PID" given. Treat SIGHUP like others. + +2005-10-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c: Move output_file var to stpd.c. + (stp_main_loop): If the output_file option was specified, + and streaming mode is being used, send output to the file + instead of stdout. If !streaming, send output to the file + instead of probe.out. + * stpd.c (usage): Add comment for -o option. + (main): Add -o option. + +2005-10-19 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (merge_output): Switch to binary TIMESTAMP. + * stp_dump.c (main): Switch to binary TIMESTAMP. + * stp_merge.c (main): Switch to binary TIMESTAMP. + +2005-10-14 Tom Zanussi <zanussi@us.ibm.com> + + PR 1476 + * librelay.c: Add flag for buffer processing. + (reader_thread): Disable/enable cancel state around buffer + processing, and update flag to show we're busy processing. + (cleanup_and_exit): Wait for any threads busy processing. + (stp_main_loop): Initialize processing mutex. + +2005-09-06 Martin Hunt <hunt@redhat.com> + + * librelay.c: Remove all USE_PROCFS ifdefs. + (sig_usr): Signal handler for SIGUSR1. + (start_cmd): New function to handle "-c" option, forks() + off a new process then waits for SIGUSR1 to exec it. + (init_stp): Call start_cmd(). + (stp_main_loop): Set a signal handler for SIGCHLD. + + * stpd.c (main): Add "-t" and "-c" options. + (usage): Update with new options. + +2005-08-29 Martin Hunt <hunt@redhat.com> + + * stpd.c main): Add enable_relayfs flag. + Turn it off with "-r". + +2005-08-24 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): Removed the "Exiting..." + message for now. + +2005-08-24 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): Reestablish signal handler so + impatient people don't hit ^C twice and terminate the + program before it saves the data and removes the module. + Also print a message to stderr that it is exiting. + (stp_main_loop): Write OOB data (warnings, errors, etc) + to stderr instead of stdout. + * librelay.h: Write debug info to stderr. + * Makefile: add librelay.h to dependencies. + +2005-08-23 Martin Hunt <hunt@redhat.com> + + * librelay.c (merge_output): Don't add an extra \n. + +2005-08-23 Martin Hunt <hunt@redhat.com> + + * librelay.c (read_last_buffers): New function. Directly grab the + last buffers. + (info_pending): Deleted. + (request_last_buffers): Deleted. + +2005-08-22 Martin Hunt <hunt@redhat.com> + + * Makefile (debug): Add debug target. + * librelay.h (dbug): Define. + * librelay.c: Enable some dbug lines. + +2005-08-19 Martin Hunt <hunt@redhat.com> + + * librelay.c (reader_thread): Check the return value for write(). + +2005-08-19 Frank Ch. Eigler <fche@elastic.org> + + * librelay.c (modpath): New global. Use it for insmod only. + * stpd.c (main): Set both modpath and modname, to support + modules specified by full path name. + +2005-08-19 Martin Hunt <hunt@redhat.com> + + * stpd.c (main): Simplify buffer size code. + * librelay.c: Major changes to support procfs instead of netlink. + +2005-08-03 Tom Zanussi <trz@us.ibm.com> + + * librelay.c: Track subbuf info requests/replies + so we know unequivocally when it's ok to do final + processing. + (reader_thread): Remove buffer-full warning. + +2005-08-03 Martin Hunt <hunt@redhat.com> + * librelay.c (init_stp): Change variable name to eliminate shadow warning. + +2005-08-03 Martin Hunt <hunt@redhat.com> + * librelay.c (open_control_channel): Set the receive buffer + to 512K, or the max allowed. + + * stpd.c: Remove "-n" subbug option and change "-b" option + so you can specify buffering in different ways. Add a verbose option. + Exec the "stp_check" script. + +2005-08-01 Frank Ch. Eigler <fche@redhat.com> + + * librelay.c: Correct fwrite api usage. + * all: Correct copyright holder name. + +2005-08-01 Martin Hunt <hunt@redhat.com> + + * librelay.h: Get structs and enums from + ../transport/transport_msgs.h to eliminate duplication. + + * librelay.c (send_request): Retry if send fails. + (open_relayfs_files): Use fopen() instead of open() for the + percpu tmpfiles. + (request_last_buffers): Just send cpu number for STP_BUF_INFO request. + (reader_thread): Ditto. + (process_subbufs): Use fwrite_unlocked() instead of write(). + (sigchld): Removed. + (init_stp): Go back to using system() instead of fork and exec + to load module. When done, send a TRANSPORT_INFO request. + (cleanup_and_exit): Change parameter to simple flag to + indicate if the module needs removing. + (sigproc): Remove complicated logic and just send STP_EXIT. + (stp_main_loop): When receiving STP_TRANSPORT_INFO, set + the local params and reply with a STP_START. When + receiving STP_START, there was an error, so cleanup and exit. + + * stpd.c (main): Added new options to set number of + buffers and their size. + +2005-07-29 Roland McGrath <roland@redhat.com> + + * librelay.c (process_subbufs): Use unsigned for I. + (sigproc): Add __attribute__((unused)) on parameter. + (sigchld): Likewise. Avoid shadowing global variable name. + (stp_main_loop): Add a cast. + +2005-07-18 Martin Hunt <hunt@redhat.com> + + * stp_merge.c (main): Fix dropped count calculation. + +2005-07-14 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c (reader_thread): Add missing pthread_mutex_lock + +2005-07-14 Frank Ch. Eigler <fche@redhat.com> + + * stpd.c (main): Pass !quiet mode to init_stp(). + * librelay.c (init_relayfs): Be quiet if !print_totals. + +2005-07-13 Martin Hunt <hunt@redhat.com> + + * stpd.c (usage): Fix usage string. + + * librelay.c (init_stp): Change last arg to NULL, not 0. + +2005-07-08 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigchld): Signal handler to detect + completion of module loading. + (init_stp): Use fork/exec instead of system() so + we can get async signal of module load success/failure. + (cleanup_and_exit): New function. + (sigproc): If module is not loaded, don't send message to it. + (stp_main_loop): Call cleanup_and_exit() when STP_EXIT + is received. Don't send a request for the transport + mode. The module will send notification to the daemon + when it is ready. + + * stpd.c (main): Don't print message until module + is loaded. + +2005-07-01 Martin Hunt <hunt@redhat.com> + + * librelay.c: Removed the color coding of cpu output. + +2005-06-28 Martin Hunt <hunt@redhat.com> + + * librelay.c (merge_output): Use unlocked stdio + to improve speed. + + * stp_merge.c: New file. + + * Makefile: Add stp_merge. + +2005-06-27 Martin Hunt <hunt@redhat.com> + + * stpd.c (main): Add new command line arg, "-m" + to disable the per-cpu merging. + + * librelay.c (merge_output): Replacement for sort_output(). + Efficiently merges per-cpu streams. + + +2005-06-20 Tom Zanussi <zanussi@us.ibm.com> + + * librelay.c: Large refactoring, important changes are + added transport_mode command, for relayfs transport + display results only when probe completes and/or write + output file, merge, sort and delete the per-cpu files + in postprocessing, refactor so that relayfs files aren't + created until transport command received, removed sigalrm, + read the final subbuffers on exit + + * stpd.c: Remove all command-line args except for -p + and -q as well as all code related to buffer sizes. + + * librelay.h: Add transport mode command and struct. + +2005-05-16 Martin Hunt <hunt@redhat.com> + + * librelay.c (sigproc): If STP_EXIT send fails, keep retrying + every 10ms. + (init_stp): Don't set n_subbufs and subbuf_size params. diff --git a/runtime/staprun/Makefile b/runtime/staprun/Makefile new file mode 100644 index 00000000..e8dd680d --- /dev/null +++ b/runtime/staprun/Makefile @@ -0,0 +1,15 @@ +CFLAGS = -Wall -std=gnu99 -D_GNU_SOURCE -fexceptions -Wall -Werror -Wshadow -Wunused + +all: staprun stp_merge + +staprun: staprun.c mainloop.c relay.c ctl.c symbols.c ../transport/transport_msgs.h staprun.h + gcc -O3 $(CFLAGS) -o staprun staprun.c mainloop.c symbols.c ctl.c relay.c relay_old.c -lpthread + +stp_merge: stp_merge.c + gcc -O3 $(CFLAGS) -o stp_merge stp_merge.c + +debug: staprun.c mainloop.c relay.c ctl.c symbols.c ../transport/transport_msgs.h staprun.h + gcc -g -D DEBUG $(CFLAGS) -o staprun staprun.c mainloop.c symbols.c ctl.c relay.c relay_old.c -lpthread + +clean: + /bin/rm -f staprun stp_merge *.o *~ diff --git a/runtime/staprun/ctl.c b/runtime/staprun/ctl.c new file mode 100644 index 00000000..9336631c --- /dev/null +++ b/runtime/staprun/ctl.c @@ -0,0 +1,40 @@ +/* -*- linux-c -*- + * + * ctl.c - staprun control channel + * + * 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. + * + * Copyright (C) 2007 Red Hat Inc. + */ + +#include "staprun.h" + +int init_ctl_channel(void) +{ + char buf[128]; + struct statfs st; + + if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) + sprintf (buf, "/sys/kernel/debug/systemtap_%d/cmd", getpid()); + else + sprintf (buf, "/proc/systemtap_%d/cmd", getpid()); + + dbug("Opening %s\n", buf); + control_channel = open(buf, O_RDWR); + if (control_channel < 0) { + fprintf(stderr, "ERROR: couldn't open control channel %s: errcode = %s\n", buf, strerror(errno)); + return -1; + } + return 0; +} + +void close_ctl_channel(void) +{ + if (control_channel > 0) { + close(control_channel); + control_channel = 0; + } +} diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c new file mode 100644 index 00000000..7ef2efd0 --- /dev/null +++ b/runtime/staprun/mainloop.c @@ -0,0 +1,374 @@ +/* -*- linux-c -*- + * + * mainloop - staprun main loop + * + * 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. + * + * Copyright (C) 2005-2007 Red Hat Inc. + */ + +#include "staprun.h" + +/* globals */ +int control_channel = 0; +int ncpus; + +/** + * send_request - send request to kernel over control channel + * @type: the relay-app command id + * @data: pointer to the data to be sent + * @len: length of the data to be sent + * + * Returns 0 on success, negative otherwise. + */ +int send_request(int type, void *data, int len) +{ + char buf[1024]; + memcpy(buf, &type, 4); + memcpy(&buf[4],data,len); + return write(control_channel, buf, len+4); +} + +/* + * start_cmd forks the command given on the command line + * with the "-c" option. It will not exec that command + * until it received signal SIGUSR1. We do it this way because + * we must have the pid of the forked command so it can be set to + * the module and made available internally as _stp_target. + * SIGUSR1 is sent from stp_main_loop() below when it receives + * STP_START from the module. + */ +void start_cmd(void) +{ + pid_t pid; + sigset_t usrset; + + sigemptyset(&usrset); + sigaddset(&usrset, SIGUSR1); + sigprocmask(SIG_BLOCK, &usrset, NULL); + + dbug ("execing target_cmd %s\n", target_cmd); + if ((pid = fork()) < 0) { + perror ("fork"); + exit(-1); + } else if (pid == 0) { + int signum; + + if (setregid(cmd_gid, cmd_gid) < 0) { + perror("setregid"); + } + if (setreuid(cmd_uid, cmd_uid) < 0) { + perror("setreuid"); + } + /* wait here until signaled */ + sigwait(&usrset, &signum); + + if (execl("/bin/sh", "sh", "-c", target_cmd, NULL) < 0) + perror(target_cmd); + _exit(-1); + } + target_pid = pid; +} + +/** + * system_cmd() executes system commands in response + * to an STP_SYSTEM message from the module. These + * messages are sent by the system() systemtap function. + * uid and gid are set because staprun is running as root and + * it is best to run commands as the real user. + */ +void system_cmd(char *cmd) +{ + pid_t pid; + + dbug ("system %s\n", cmd); + if ((pid = fork()) < 0) { + perror ("fork"); + } else if (pid == 0) { + if (setregid(cmd_gid, cmd_gid) < 0) { + perror("setregid"); + } + if (setreuid(cmd_uid, cmd_uid) < 0) { + perror("setreuid"); + } + if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0) + perror(cmd); + _exit(-1); + } +} + + +/* stp_check script */ +#ifdef PKGLIBDIR +char *stp_check=PKGLIBDIR "/stp_check"; +#else +char *stp_check="stp_check"; +#endif + +static int run_stp_check (void) +{ + pid_t pid; + int wstat; + + /* run the _stp_check script */ + dbug("stp_check\n"); + if ((pid = fork()) < 0) { + perror (stp_check); + fprintf(stderr, "Fork of %s failed.\n", stp_check); + return -1; + } else if (pid == 0) { + if (execlp(stp_check, stp_check, NULL) < 0) + _exit (-1); + } + if (waitpid(pid, &wstat, 0) < 0) { + perror("waitpid"); + return -1; + } + if (WIFEXITED(wstat) && WEXITSTATUS(wstat)) { + perror (stp_check); + fprintf(stderr, "Could not execute %s.\n", stp_check); + return -1; + } + dbug("DONE\n"); + return 0; +} + + +/** + * init_stp - initialize the app + * @print_summary: boolean, print summary or not at end of run + * + * Returns 0 on success, negative otherwise. + */ +int init_staprun(void) +{ + char buf[1024], bufcmd[20]; + pid_t pid; + int rstatus; + + ncpus = sysconf(_SC_NPROCESSORS_ONLN); + if (ncpus < 0) { + fprintf(stderr, "sysconf(_SC_NPROCESSORS_ONLN) failed\n"); + return 1; + } + + /* insert module */ + sprintf(buf, "_stp_pid=%d", (int)getpid()); + sprintf(bufcmd, "_stp_bufsize=%d", buffer_size); + modoptions[0] = "insmod"; + modoptions[1] = modpath; + modoptions[2] = buf; + modoptions[3] = bufcmd; + /* modoptions[4...N] set by command line parser. */ + + if ((pid = fork()) < 0) { + perror ("fork"); + exit(-1); + } else if (pid == 0) { + if (execvp("/sbin/insmod", modoptions) < 0) + _exit(-1); + } + if (waitpid(pid, &rstatus, 0) < 0) { + perror("waitpid"); + exit(-1); + } + if (WIFEXITED(rstatus) && WEXITSTATUS(rstatus)) { + fprintf(stderr, "ERROR, couldn't insmod probe module %s\n", modpath); + return -1; + } + + if (run_stp_check() < 0) + return -1; + + /* create control channel */ + if (init_ctl_channel() < 0) + goto exit1; + + /* fork target_cmd if requested. */ + /* It will not actually exec until signalled. */ + if (target_cmd) + start_cmd(); + + return 0; + +exit1: + snprintf(buf, sizeof(buf), "/sbin/rmmod -w %s", modname); + if (system(buf)) + fprintf(stderr, "ERROR: couldn't rmmod probe module %s.\n", modname); + return -1; +} + + + +void cleanup_and_exit (int closed) +{ + char tmpbuf[128]; + pid_t err; + static int exiting = 0; + + if (exiting) + return; + exiting = 1; + + dbug("CLEANUP AND EXIT closed=%d\n", closed); + + /* what about child processes? we will wait for them here. */ + err = waitpid(-1, NULL, WNOHANG); + if (err >= 0) + fprintf(stderr,"\nWaititing for processes to exit\n"); + while(wait(NULL) > 0) ; + + close_relayfs(); + + dbug("closing control channel\n"); + close_ctl_channel(); + + if (!closed) { + dbug("removing module\n"); + snprintf(tmpbuf, sizeof(tmpbuf), "/sbin/rmmod -w %s", modname); + if (system(tmpbuf)) { + fprintf(stderr, "ERROR: couldn't rmmod probe module %s. No output will be written.\n", + modname); + exit(1); + } + } + exit(0); +} + +static void sigproc(int signum) +{ + dbug("sigproc %d\n", signum); + if (signum == SIGCHLD) { + pid_t pid = waitpid(-1, NULL, WNOHANG); + if (pid != target_pid) + return; + } + send_request(STP_EXIT, NULL, 0); +} + +static void driver_poll (int signum __attribute__((unused))) +{ + /* See if the driver process is still alive. If not, time to exit. */ + if (kill (driver_pid, 0) < 0) { + send_request(STP_EXIT, NULL, 0); + return; + } else { + /* Check again later. Use any reasonable poll interval */ + signal (SIGALRM, driver_poll); + alarm (10); + } +} + + +/** + * stp_main_loop - loop forever reading data + */ +static char recvbuf[8192]; + +int stp_main_loop(void) +{ + int nb; + void *data; + int type; + FILE *ofp = stdout; + + setvbuf(ofp, (char *)NULL, _IOLBF, 0); + + signal(SIGINT, sigproc); + signal(SIGTERM, sigproc); + signal(SIGHUP, sigproc); + signal(SIGCHLD, sigproc); + + if (driver_pid) + driver_poll(0); + + dbug("in main loop\n"); + + while (1) { /* handle messages from control channel */ + nb = read(control_channel, recvbuf, sizeof(recvbuf)); + if (nb <= 0) { + perror("recv"); + fprintf(stderr, "WARNING: unexpected EOF. nb=%d\n", nb); + continue; + } + + type = *(int *)recvbuf; + data = (void *)(recvbuf + sizeof(int)); + + switch (type) { +#ifdef STP_OLD_TRANSPORT + case STP_REALTIME_DATA: + write(out_fd[0], data, nb - sizeof(int)); + break; +#endif + case STP_OOB_DATA: + fputs ((char *)data, stderr); + break; + case STP_EXIT: + { + /* module asks us to unload it and exit */ + int *closed = (int *)data; + dbug("got STP_EXIT, closed=%d\n", *closed); + cleanup_and_exit(*closed); + break; + } + case STP_START: + { + struct _stp_msg_start *t = (struct _stp_msg_start *)data; + dbug("probe_start() returned %d\n", t->res); + if (t->res < 0) { + if (target_cmd) + kill (target_pid, SIGKILL); + cleanup_and_exit(0); + } else if (target_cmd) + kill (target_pid, SIGUSR1); + break; + } + case STP_SYSTEM: + { + struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data; + system_cmd(c->cmd); + break; + } + case STP_TRANSPORT: + { + struct _stp_msg_start ts; + if (init_relayfs((struct _stp_msg_trans *)data) < 0) + cleanup_and_exit(0); + else { + ts.target = target_pid; + send_request(STP_START, &ts, sizeof(ts)); + } + break; + } + case STP_MODULE: + { + do_module(data); + break; + } + case STP_SYMBOLS: + { + struct _stp_msg_symbol *req = (struct _stp_msg_symbol *)data; + dbug("STP_SYMBOLS request received\n"); + if (req->endian != 0x1234) { + fprintf(stderr,"ERROR: staprun is compiled with different endianess than the kernel!\n"); + cleanup_and_exit(0); + } + if (req->ptr_size != sizeof(char *)) { + fprintf(stderr,"ERROR: staprun is compiled with %d-bit pointers and the kernel uses %d-bit.\n", + 8*(int)sizeof(char *), 8*req->ptr_size); + cleanup_and_exit(0); + } + do_kernel_symbols(); + break; + } + default: + fprintf(stderr, "WARNING: ignored message of type %d\n", (type)); + } + } + fclose(ofp); + return 0; +} diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c new file mode 100644 index 00000000..98f064b6 --- /dev/null +++ b/runtime/staprun/relay.c @@ -0,0 +1,189 @@ +/* -*- linux-c -*- + * + * relay.c - staprun relayfs functions + * + * 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. + * + * Copyright (C) 2007 Red Hat Inc. + */ + +#include "staprun.h" + +#ifndef STP_OLD_TRANSPORT + +int out_fd[NR_CPUS]; +static pthread_t reader[NR_CPUS]; +static int relay_fd[NR_CPUS]; +static int stop_threads = 0; +static int bulkmode = 0; + +/** + * reader_thread - per-cpu channel buffer reader + */ + +static void *reader_thread(void *data) +{ + char buf[131072]; + int rc, cpu = (int)(long)data; + struct pollfd pollfd; + int max_rd = 0; + + if (bulkmode) { + cpu_set_t cpu_mask; + CPU_ZERO(&cpu_mask); + CPU_SET(cpu, &cpu_mask); + if( sched_setaffinity( 0, sizeof(cpu_mask), &cpu_mask ) < 0 ) { + perror("sched_setaffinity"); + } + } + + pollfd.fd = relay_fd[cpu]; + pollfd.events = POLLIN; + + do { + rc = poll(&pollfd, 1, 10); + if (rc < 0) { + if (errno != EINTR) { + fprintf(stderr, "poll error: %s\n",strerror(errno)); + pthread_exit(NULL); + } + fprintf(stderr, "poll warning: %s\n",strerror(errno)); + } + rc = read(relay_fd[cpu], buf, sizeof(buf)); + if (!rc) { + continue; + } + if (rc < 0) { + if (errno == EAGAIN) + continue; + fprintf(stderr, "error reading fd %d on cpu %d: %s\n", relay_fd[cpu], cpu, strerror(errno)); + continue; + } + + if (rc > max_rd) + max_rd = rc; + + if (write(out_fd[cpu], buf, rc) < 0) { + fprintf(stderr, "Couldn't write to output fd %d for cpu %d, exiting: errcode = %d: %s\n", + out_fd[cpu], cpu, errno, strerror(errno)); + pthread_exit(NULL); + } + + } while (!stop_threads); + pthread_exit((void *)(long)max_rd); +} + +/** + * init_relayfs - create files and threads for relayfs processing + * + * Returns 0 if successful, negative otherwise + */ +int init_relayfs(struct _stp_msg_trans *t) +{ + int i; + struct statfs st; + char buf[128], relay_filebase[128]; + + bulkmode = t->bulk_mode; + dbug("initializing relayfs. bulkmode = %d\n", bulkmode); + + reader[0] = (pthread_t)0; + relay_fd[0] = 0; + out_fd[0] = 0; + + if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) + sprintf(relay_filebase, "/sys/kernel/debug/systemtap_%d", getpid()); + else { + fprintf(stderr,"Cannot find relayfs or debugfs mount point.\n"); + return -1; + } + + if (bulkmode) { + for (i = 0; i < ncpus; i++) { + sprintf(buf, "%s/trace%d", relay_filebase, i); + dbug("opening %s\n", buf); + relay_fd[i] = open(buf, O_RDONLY | O_NONBLOCK); + if (relay_fd[i] < 0) { + fprintf(stderr, "ERROR: couldn't open relayfs file %s.\n", buf); + return -1; + } + + if (outfile_name) { + /* special case: for testing we sometimes want to write to /dev/null */ + if (strcmp(outfile_name, "/dev/null") == 0) + strcpy(buf, outfile_name); + else + sprintf(buf, "%s_%d", outfile_name, i); + } else + sprintf(buf, "stpd_cpu%d", i); + + out_fd[i] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666); + dbug("out_fd[%d] = %d\n", i, out_fd[i]); + if (out_fd[i] < 0) { + fprintf(stderr, "ERROR: couldn't open output file %s.\n", buf); + return -1; + } + } + + } else { + /* stream mode */ + ncpus = 1; + sprintf(buf, "%s/trace0", relay_filebase); + dbug("opening %s\n", buf); + relay_fd[0] = open(buf, O_RDONLY | O_NONBLOCK); + dbug("got fd=%d\n", relay_fd[0]); + if (relay_fd[0] < 0) { + fprintf(stderr, "ERROR: couldn't open relayfs file %s.\n", buf); + return -1; + } + + if (outfile_name) { + out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[0] < 0) { + fprintf(stderr, "ERROR: couldn't open output file %s.\n", outfile_name); + return -1; + } + } else + out_fd[0] = STDOUT_FILENO; + + } + dbug("starting threads\n"); + for (i = 0; i < ncpus; i++) { + if (pthread_create(&reader[i], NULL, reader_thread, (void *)(long)i) < 0) { + fprintf(stderr, "failed to create thread\n"); + perror("Error creating thread"); + return -1; + } + } + + return 0; +} + +void close_relayfs(void) +{ + int i; + void *res; + dbug("closing\n"); + + stop_threads = 1; + + for (i = 0; i < ncpus; i++) { + if (reader[i]) + pthread_join(reader[i], &res); + else + break; + } + + for (i = 0; i < ncpus; i++) { + if (relay_fd[i] >= 0) + close(relay_fd[i]); + else + break; + } + dbug("closed files\n"); +} + +#endif /* !STP_OLD_TRANSPORT */ diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c new file mode 100644 index 00000000..e4ab5fe6 --- /dev/null +++ b/runtime/staprun/relay_old.c @@ -0,0 +1,277 @@ +/* -*- linux-c -*- + * + * relay_old.c - staprun relayfs functions for kernels with + * old relayfs implementations. + * + * 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. + * + * Copyright (C) 2005-2007 Red Hat Inc. + */ + +#include "staprun.h" +#ifdef STP_OLD_TRANSPORT + +int out_fd[NR_CPUS]; +/* temporary per-cpu output written here for relayfs, filebase0...N */ +static char *percpu_tmpfilebase = "stpd_cpu"; +static int relay_fd[NR_CPUS]; +static int proc_fd[NR_CPUS]; +static FILE *percpu_tmpfile[NR_CPUS]; +static char *relay_buffer[NR_CPUS]; +static pthread_t reader[NR_CPUS]; +static int bulkmode = 0; +static unsigned subbuf_size = 0; +static unsigned n_subbufs = 0; + +/* per-cpu buffer info */ +static struct buf_status +{ + struct _stp_buf_info info; + unsigned max_backlog; /* max # sub-buffers ready at one time */ +} status[NR_CPUS]; + + +/** + * close_relayfs_files - close and munmap buffer and open output file + */ +static void close_relayfs_files(int cpu) +{ + size_t total_bufsize = subbuf_size * n_subbufs; + dbug("%d %d %d\n", cpu,(int) total_bufsize, relay_fd[cpu]); + if (relay_fd[cpu]) { + munmap(relay_buffer[cpu], total_bufsize); + close(relay_fd[cpu]); + close(proc_fd[cpu]); + relay_fd[cpu] = 0; + fclose(percpu_tmpfile[cpu]); + } +} + +/** + * close_all_relayfs_files - close and munmap buffers and output files + */ +void close_relayfs(void) +{ + int i; + + if (!bulkmode) + return; + + dbug("close_relayfs: %d\n", ncpus); + for (i = 0; i < ncpus; i++) + if (reader[i]) pthread_join(reader[i], NULL); + + for (i = 0; i < ncpus; i++) + close_relayfs_files(i); +} + +/** + * open_relayfs_files - open and mmap buffer and open output file + */ +static int open_relayfs_files(int cpu, const char *relay_filebase, const char *proc_filebase) +{ + size_t total_bufsize; + char tmp[PATH_MAX]; + + memset(&status[cpu], 0, sizeof(struct buf_status)); + status[cpu].info.cpu = cpu; + + sprintf(tmp, "%s%d", relay_filebase, cpu); + relay_fd[cpu] = open(tmp, O_RDONLY | O_NONBLOCK); + if (relay_fd[cpu] < 0) { + fprintf(stderr, "ERROR: couldn't open relayfs file %s: errcode = %s\n", tmp, strerror(errno)); + goto err0; + } + + sprintf(tmp, "%s%d", proc_filebase, cpu); + dbug("Opening %s.\n", tmp); + proc_fd[cpu] = open(tmp, O_RDWR | O_NONBLOCK); + if (proc_fd[cpu] < 0) { + fprintf(stderr, "ERROR: couldn't open proc file %s: errcode = %s\n", tmp, strerror(errno)); + goto err1; + } + + sprintf(tmp, "%s%d", percpu_tmpfilebase, cpu); + if((percpu_tmpfile[cpu] = fopen(tmp, "w+")) == NULL) { + fprintf(stderr, "ERROR: Couldn't open output file %s: errcode = %s\n", tmp, strerror(errno)); + goto err2; + } + + total_bufsize = subbuf_size * n_subbufs; + relay_buffer[cpu] = mmap(NULL, total_bufsize, PROT_READ, + MAP_PRIVATE | MAP_POPULATE, relay_fd[cpu], + 0); + if(relay_buffer[cpu] == MAP_FAILED) + { + fprintf(stderr, "ERROR: couldn't mmap relay file, total_bufsize (%d) = subbuf_size (%d) * n_subbufs(%d), error = %s \n", (int)total_bufsize, (int)subbuf_size, (int)n_subbufs, strerror(errno)); + goto err3; + } + + return 0; + +err3: + fclose(percpu_tmpfile[cpu]); +err2: + close (proc_fd[cpu]); +err1: + close (relay_fd[cpu]); +err0: + relay_fd[cpu] = 0; + return -1; + +} + +/** + * process_subbufs - write ready subbufs to disk + */ +static int process_subbufs(struct _stp_buf_info *info) +{ + unsigned subbufs_ready, start_subbuf, end_subbuf, subbuf_idx, i; + int len, cpu = info->cpu; + char *subbuf_ptr; + int subbufs_consumed = 0; + unsigned padding; + + subbufs_ready = info->produced - info->consumed; + start_subbuf = info->consumed % n_subbufs; + end_subbuf = start_subbuf + subbufs_ready; + + for (i = start_subbuf; i < end_subbuf; i++) { + subbuf_idx = i % n_subbufs; + subbuf_ptr = relay_buffer[cpu] + subbuf_idx * subbuf_size; + padding = *((unsigned *)subbuf_ptr); + subbuf_ptr += sizeof(padding); + len = (subbuf_size - sizeof(padding)) - padding; + if (len) { + if (fwrite_unlocked (subbuf_ptr, len, 1, percpu_tmpfile[cpu]) != 1) { + fprintf(stderr, "ERROR: couldn't write to output file for cpu %d, exiting: errcode = %d: %s\n", cpu, errno, strerror(errno)); + exit(1); + } + } + subbufs_consumed++; + } + + return subbufs_consumed; +} + +/** + * reader_thread - per-cpu channel buffer reader + */ +static void *reader_thread(void *data) +{ + int rc; + int cpu = (long)data; + struct pollfd pollfd; + struct _stp_consumed_info consumed_info; + unsigned subbufs_consumed; + cpu_set_t cpu_mask; + + CPU_ZERO(&cpu_mask); + CPU_SET(cpu, &cpu_mask); + if( sched_setaffinity( 0, sizeof(cpu_mask), &cpu_mask ) < 0 ) { + perror("sched_setaffinity"); + } + + pollfd.fd = relay_fd[cpu]; + pollfd.events = POLLIN; + + do { + rc = poll(&pollfd, 1, -1); + if (rc < 0) { + if (errno != EINTR) { + fprintf(stderr, "ERROR: poll error: %s\n", + strerror(errno)); + exit(1); + } + fprintf(stderr, "WARNING: poll warning: %s\n", + strerror(errno)); + rc = 0; + } + + rc = read(proc_fd[cpu], &status[cpu].info, sizeof(struct _stp_buf_info)); + subbufs_consumed = process_subbufs(&status[cpu].info); + if (subbufs_consumed) { + if (subbufs_consumed > status[cpu].max_backlog) + status[cpu].max_backlog = subbufs_consumed; + status[cpu].info.consumed += subbufs_consumed; + consumed_info.cpu = cpu; + consumed_info.consumed = subbufs_consumed; + if (write (proc_fd[cpu], &consumed_info, sizeof(struct _stp_consumed_info)) < 0) + fprintf(stderr,"WARNING: writing consumed info failed.\n"); + } + if (status[cpu].info.flushing) + pthread_exit(NULL); + } while (1); +} + +/** + * init_relayfs - create files and threads for relayfs processing + * + * Returns 0 if successful, negative otherwise + */ +int init_relayfs(struct _stp_msg_trans *t) +{ + int i, j; + struct statfs st; + char relay_filebase[128], proc_filebase[128]; + + for (i = 0; i < ncpus; i++){ + reader[i] = (pthread_t)0; + relay_fd[i] = 0; + } + + bulkmode = t->bulk_mode; + if (!bulkmode) { + if (outfile_name) { + out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (out_fd[0] < 0) { + fprintf(stderr, "ERROR: couldn't open output file %s.\n", outfile_name); + return -1; + } + } else + out_fd[0] = STDOUT_FILENO; + return 0; + } + + n_subbufs = t->n_subbufs; + subbuf_size = t->subbuf_size; + dbug("initializing relayfs. n_subbufs=%d subbuf_size=%d\n",n_subbufs, subbuf_size); + + if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) { + sprintf(relay_filebase, "/sys/kernel/debug/systemtap_%d/trace", getpid()); + sprintf(proc_filebase, "/sys/kernel/debug/systemtap_%d/", getpid()); + } else if (statfs("/mnt/relay", &st) == 0 && (int) st.f_type == (int) RELAYFS_MAGIC) { + sprintf(relay_filebase, "/mnt/relay/systemtap_%d/trace", getpid()); + sprintf(proc_filebase, "/proc/systemtap_%d/", getpid()); + } else { + fprintf(stderr,"Cannot find relayfs or debugfs mount point.\n"); + return -1; + } + + for (i = 0; i < ncpus; i++) { + if (open_relayfs_files(i, relay_filebase, proc_filebase) < 0) { + fprintf(stderr, "ERROR: couldn't open relayfs files, cpu = %d\n", i); + goto err; + } + /* create a thread for each per-cpu buffer */ + if (pthread_create(&reader[i], NULL, reader_thread, (void *)(long)i) < 0) { + close_relayfs_files(i); + fprintf(stderr, "ERROR: Couldn't create reader thread, cpu = %d\n", i); + goto err; + } + } + return 0; +err: + for (j = 0; j < i; j++) + close_relayfs_files(j); + + for (j = 0; j < i; j++) + if (reader[j]) pthread_cancel(reader[j]); + + return -1; +} + +#endif /* STP_OLD_TRANSPORT */ diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c new file mode 100644 index 00000000..4f781666 --- /dev/null +++ b/runtime/staprun/staprun.c @@ -0,0 +1,158 @@ +/* -*- linux-c -*- + * + * staprun.c - SystemTap module loader + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2005-2007 Red Hat, Inc. + * + */ + +#include "staprun.h" +#include <pwd.h> + +extern char *optarg; +extern int optopt; +extern int optind; + +int verbose = 0; +int target_pid = 0; +int driver_pid = 0; +unsigned int buffer_size = 0; +char *modname = NULL; +char *modpath = NULL; +#define MAXMODOPTIONS 64 +char *modoptions[MAXMODOPTIONS]; +char *target_cmd = NULL; +char *outfile_name = NULL; +char *username = NULL; +uid_t cmd_uid; +gid_t cmd_gid; + +static void usage(char *prog) +{ + fprintf(stderr, "\n%s [-v] [-c cmd ] [-x pid] [-u user]\n" + "\t[-b bufsize] [-o FILE] kmod-name [kmod-options]\n", prog); + fprintf(stderr, "-v Verbose.\n"); + fprintf(stderr, "-c cmd. Command \'cmd\' will be run and staprun will exit when it does.\n"); + fprintf(stderr, " _stp_target will contain the pid for the command.\n"); + fprintf(stderr, "-x pid. Sets _stp_target to pid.\n"); + fprintf(stderr, "-o FILE. Send output to FILE.\n"); + fprintf(stderr, "-u username. Run commands as username.\n"); + fprintf(stderr, "-b buffer size. The systemtap module will specify a buffer size.\n"); + fprintf(stderr, " Setting one here will override that value. The value should be\n"); + fprintf(stderr, " an integer between 1 and 64 which be assumed to be the\n"); + fprintf(stderr, " buffer size in MB. That value will be per-cpu in bulk mode.\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + + while ((c = getopt(argc, argv, "vb:t:d:c:o:u:x:")) != EOF) { + switch (c) { + case 'v': + verbose = 1; + break; + case 'b': + { + int size = (unsigned)atoi(optarg); + if (!size) + usage(argv[0]); + if (size > 64) { + fprintf(stderr, "Maximum buffer size is 64 (MB)\n"); + exit(1); + } + buffer_size = size; + break; + } + case 't': + case 'x': + target_pid = atoi(optarg); + break; + case 'd': + /* internal option used by stap */ + driver_pid = atoi(optarg); + break; + case 'c': + target_cmd = optarg; + break; + case 'o': + outfile_name = optarg; + break; + case 'u': + username = optarg; + break; + default: + usage(argv[0]); + } + } + + if (verbose) { + if (buffer_size) + printf ("Using a buffer of %u bytes.\n", buffer_size); + } + + if (optind < argc) { + /* Collect both full path and just the trailing module name. */ + modpath = argv[optind++]; + modname = rindex (modpath, '/'); + if (modname == NULL) + modname = modpath; + else + modname++; /* skip over / */ + } + + if (optind < argc) { + unsigned start_idx = 4; /* reserve four slots in modoptions[] */ + while (optind < argc && start_idx+1 < MAXMODOPTIONS) + modoptions[start_idx++] = argv[optind++]; + modoptions[start_idx] = NULL; + } + + if (!modname) { + fprintf (stderr, "Need a module to load.\n"); + usage(argv[0]); + } + + if (username) { + struct passwd *pw = getpwnam(username); + if (!pw) { + fprintf(stderr, "Cannot find user \"%s\".\n", username); + exit(1); + } + cmd_uid = pw->pw_uid; + cmd_gid = pw->pw_gid; + } else { + cmd_uid = getuid(); + cmd_gid = getgid(); + } + + /* now bump the priority */ + setpriority (PRIO_PROCESS, 0, -10); + + if (init_staprun()) { + fprintf(stderr, "Couldn't initialize staprun. Exiting.\n"); + exit(1); + } + + if (stp_main_loop()) { + fprintf(stderr,"Couldn't enter main loop. Exiting.\n"); + exit(1); + } + + return 0; +} diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h new file mode 100644 index 00000000..d8664802 --- /dev/null +++ b/runtime/staprun/staprun.h @@ -0,0 +1,91 @@ +/* -*- linux-c -*- + * + * staprun.h - include file for staprun + * + * 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. + * + * Copyright (C) 2005-2007 Red Hat Inc. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdint.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <linux/fd.h> +#include <sys/mman.h> +#include <sys/poll.h> +#include <pthread.h> +#include <sys/socket.h> +#include <linux/types.h> +#include <linux/limits.h> +#include <sys/wait.h> +#include <sys/statfs.h> +#include <linux/version.h> + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) +#define STP_OLD_TRANSPORT +#endif +#include "../transport/transport_msgs.h" + + +#define RELAYFS_MAGIC 0xF0B4A981 +#define DEBUGFS_MAGIC 0x64626720 + +#ifdef DEBUG +#define dbug(args...) {fprintf(stderr,"%s:%d ",__FUNCTION__, __LINE__); fprintf(stderr,args); } +#else +#define dbug(args...) ; +#endif /* DEBUG */ + +/* + * function prototypes + */ +int init_staprun(void); +int stp_main_loop(void); +int send_request(int type, void *data, int len); +void cleanup_and_exit (int); +int do_module(void *); +void do_kernel_symbols(void); +int init_ctl_channel(void); +int init_relayfs(struct _stp_msg_trans *); +void close_relayfs(void); +void close_ctl_channel(void); + +/* + * variables + */ +extern int control_channel; +extern int ncpus; + +/* flags */ +extern int verbose; +extern unsigned int buffer_size; +extern char *modname; +extern char *modpath; +extern char *modoptions[]; +extern int target_pid; +extern int driver_pid; +extern char *target_cmd; +extern char *outfile_name; + +/* uid/gid to use when execing external programs */ +extern uid_t cmd_uid; +extern gid_t cmd_gid; + +/* maximum number of CPUs we can handle */ +#define NR_CPUS 256 + +/* output fd's (percpu) */ +extern int out_fd[NR_CPUS]; diff --git a/runtime/staprun/stp_merge.c b/runtime/staprun/stp_merge.c new file mode 100644 index 00000000..225d8d79 --- /dev/null +++ b/runtime/staprun/stp_merge.c @@ -0,0 +1,119 @@ +/* + * stap_merge.c - systemtap merge program + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Red Hat Inc, 2005-2007 + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static void usage (char *prog) +{ + fprintf(stderr, "%s [-o output_filename] input_files ...\n", prog); + exit(1); +} + +#define TIMESTAMP_SIZE (sizeof(int)) +#define NR_CPUS 256 + +int main (int argc, char *argv[]) +{ + char *outfile_name = NULL; + char buf[8192]; + int c, i, j, dropped=0; + long count=0, min, num[NR_CPUS]; + FILE *ofp, *fp[NR_CPUS]; + int ncpus, len; + + while ((c = getopt (argc, argv, "o:")) != EOF) { + switch (c) { + case 'o': + outfile_name = optarg; + break; + default: + usage(argv[0]); + } + } + + if (optind == argc) + usage (argv[0]); + + i = 0; + while (optind < argc) { + fp[i] = fopen(argv[optind++], "r"); + if (!fp[i]) { + fprintf(stderr, "error opening file %s.\n", argv[optind - 1]); + return -1; + } + if (fread (buf, TIMESTAMP_SIZE, 1, fp[i])) + num[i] = *((int *)buf); + else + num[i] = 0; + i++; + } + ncpus = i; + + if (!outfile_name) + ofp = stdout; + else { + ofp = fopen(outfile_name, "w"); + if (!ofp) { + fprintf(stderr, "ERROR: couldn't open output file %s: errcode = %s\n", + outfile_name, strerror(errno)); + return -1; + } + } + + do { + min = num[0]; + j = 0; + for (i = 1; i < ncpus; i++) { + if (min == 0 || (num[i] && num[i] < min)) { + min = num[i]; + j = i; + } + } + + if (fread(&len, sizeof(int), 1, fp[j])) { + fread(buf, len, 1, fp[j]); + fwrite(buf, len, 1, ofp); + } + + if (min && ++count != min) { + fprintf(stderr, "got %ld. expected %ld\n", min, count); + dropped += min - count ; + count = min; + } + + if (fread (buf, TIMESTAMP_SIZE, 1, fp[j])) + num[j] = *((int *)buf); + else + num[j] = 0; + } while (min); + + fputs ("\n", ofp); + + for (i = 0; i < ncpus; i++) + fclose (fp[i]); + fclose (ofp); + printf ("sequence had %d drops\n", dropped); + return 0; +} diff --git a/runtime/staprun/stp_merge.c~ b/runtime/staprun/stp_merge.c~ new file mode 100644 index 00000000..b67b4171 --- /dev/null +++ b/runtime/staprun/stp_merge.c~ @@ -0,0 +1,119 @@ +/* + * stp_merge.c - stp merge program + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) Red Hat Inc, 2005 + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static void usage (char *prog) +{ + fprintf(stderr, "%s [-o output_filename] input_files ...\n", prog); + exit(1); +} + +#define TIMESTAMP_SIZE (sizeof(int)) +#define NR_CPUS 256 + +int main (int argc, char *argv[]) +{ + char *outfile_name = NULL; + char buf[8192]; + int c, i, j, dropped=0; + long count=0, min, num[NR_CPUS]; + FILE *ofp, *fp[NR_CPUS]; + int ncpus, len; + + while ((c = getopt (argc, argv, "o:")) != EOF) { + switch (c) { + case 'o': + outfile_name = optarg; + break; + default: + usage(argv[0]); + } + } + + if (optind == argc) + usage (argv[0]); + + i = 0; + while (optind < argc) { + fp[i] = fopen(argv[optind++], "r"); + if (!fp[i]) { + fprintf(stderr, "error opening file %s.\n", argv[optind - 1]); + return -1; + } + if (fread (buf, TIMESTAMP_SIZE, 1, fp[i])) + num[i] = *((int *)buf); + else + num[i] = 0; + i++; + } + ncpus = i; + + if (!outfile_name) + ofp = stdout; + else { + ofp = fopen(outfile_name, "w"); + if (!ofp) { + fprintf(stderr, "ERROR: couldn't open output file %s: errcode = %s\n", + outfile_name, strerror(errno)); + return -1; + } + } + + do { + min = num[0]; + j = 0; + for (i = 1; i < ncpus; i++) { + if (min == 0 || (num[i] && num[i] < min)) { + min = num[i]; + j = i; + } + } + + if (fread(&len, sizeof(int), 1, fp[j])) { + fread(buf, len, 1, fp[j]); + fwrite(buf, len, 1, ofp); + } + + if (min && ++count != min) { + fprintf(stderr, "got %ld. expected %ld\n", min, count); + dropped += min - count ; + count = min; + } + + if (fread (buf, TIMESTAMP_SIZE, 1, fp[j])) + num[j] = *((int *)buf); + else + num[j] = 0; + } while (min); + + fputs ("\n", ofp); + + for (i = 0; i < ncpus; i++) + fclose (fp[i]); + fclose (ofp); + printf ("sequence had %d drops\n", dropped); + return 0; +} diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c new file mode 100644 index 00000000..24d2bc89 --- /dev/null +++ b/runtime/staprun/symbols.c @@ -0,0 +1,226 @@ +/* -*- linux-c -*- + * Symbols and modules functions for staprun. + * + * Copyright (C) 2006, 2007 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. + */ + +#include "staprun.h" +#include "../sym.h" + +static int send_data(void *data, int len) +{ + return write(control_channel, data, len); +} + +/* Get the sections for a module. Put them in the supplied buffer */ +/* in the following order: */ +/* [struct _stp_module][struct _stp_symbol sections ...][string data] */ +/* Return the total length of all the data. */ + +#define SECDIR "/sys/module/%s/sections" +static int get_sections(char *name, char *data_start, int datalen) +{ + char dir[STP_MODULE_NAME_LEN + sizeof(SECDIR)]; + char filename[STP_MODULE_NAME_LEN + 256]; + char buf[32], strdata_start[4096]; + char *strdata=strdata_start, *data=data_start; + int fd, len, res; + struct _stp_module *mod = (struct _stp_module *)data_start; + struct dirent *d; + DIR *secdir; + struct _stp_symbol *sec; + + /* start of data is a struct _stp_module */ + data += sizeof(struct _stp_module); + + res = snprintf(dir, sizeof(dir), SECDIR, name); + if (res >= (int)sizeof(dir)) { + fprintf(stderr, "ERROR: couldn't fit module \"%s\" into dir buffer.\n", name); + fprintf(stderr, "This should never happen. Please file a bug report.\n"); + cleanup_and_exit(0); + } + + if ((secdir = opendir(dir)) == NULL) + return 0; + + memset(mod, 0, sizeof(struct _stp_module)); + strncpy(mod->name, name, STP_MODULE_NAME_LEN); + + while ((d = readdir(secdir))) { + char *secname = d->d_name; + res = snprintf(filename, sizeof(filename), "/sys/module/%s/sections/%s", name, secname); + if (res >= (int)sizeof(filename)) { + fprintf(stderr, "ERROR: couldn't fit secname \"%s\" into filename buffer.\n", secname); + fprintf(stderr, "This should never happen. Please file a bug report.\n"); + closedir(secdir); + cleanup_and_exit(0); + } + if ((fd = open(filename,O_RDONLY)) >= 0) { + if (read(fd, buf, 32) > 0) { + /* filter out some non-useful stuff */ + if (!strncmp(secname,"__",2) + || !strcmp(secname,".module_sig") + || !strcmp(secname,".modinfo") + || !strcmp(secname,".strtab") + || !strcmp(secname,".symtab") ) { + close(fd); + continue; + } + /* create next section */ + sec = (struct _stp_symbol *)data; + data += sizeof(struct _stp_symbol); + sec->addr = strtoul(buf,NULL,16); + sec->symbol = (char *)(strdata - strdata_start); + mod->num_sections++; + + /* now create string data for the section */ + strcpy(strdata, secname); + strdata += strlen(secname) + 1; + + /* These sections are used a lot so keep the values handy */ + if (!strcmp(secname, ".data")) + mod->data = sec->addr; + if (!strcmp(secname, ".text")) + mod->text = sec->addr; + if (!strcmp(secname, ".gnu.linkonce.this_module")) + mod->module = sec->addr; + } + close(fd); + } + } + closedir(secdir); + + /* consolidate buffers */ + len = strdata - strdata_start; + if ((len + data - data_start) > datalen) { + fprintf(stderr, "ERROR: overflowed buffers in get_sections. Size needed = %d\n", + (int)(len + data - data_start)); + cleanup_and_exit(0); + } + strdata = strdata_start; + while (len--) + *data++ = *strdata++; + + return data - data_start; +} +#undef SECDIR + +void send_module (char *mname) +{ + char data[8192]; + int len = get_sections(mname, data, sizeof(data)); + if (len) + send_request(STP_MODULE, data, len); +} + +int do_module (void *data) +{ + struct _stp_module *mod = (struct _stp_module *)data; + + if (mod->name[0] == 0) { + struct dirent *d; + DIR *moddir = opendir("/sys/module"); + if (moddir) { + while ((d = readdir(moddir))) + send_module(d->d_name); + closedir(moddir); + } + return 1; + } + + send_module(mod->name); + return 0; +} + +static int compar(const void *p1, const void *p2) +{ + struct _stp_symbol *s1 = (struct _stp_symbol *)p1; + struct _stp_symbol *s2 = (struct _stp_symbol *)p2; + if (s1->addr == s2->addr) return 0; + if (s1->addr < s2->addr) return -1; + return 1; +} + +#define MAX_SYMBOLS 32768 + +void do_kernel_symbols(void) +{ + FILE *kallsyms; + char *sym_base, *data_base; + char buf[128], *ptr, *name, *data, *dataptr, *datamax, type; + unsigned long addr; + struct _stp_symbol *syms; + int num_syms, i = 0; + + sym_base = malloc(MAX_SYMBOLS*sizeof(struct _stp_symbol)+sizeof(long)); + data_base = malloc(MAX_SYMBOLS*32); + if (data_base == NULL || sym_base == NULL) { + fprintf(stderr,"Failed to allocate memory for symbols\n"); + cleanup_and_exit(0); + } + *(int *)data_base = STP_SYMBOLS; + dataptr = data = data_base + sizeof(long); + datamax = dataptr + MAX_SYMBOLS*32 - sizeof(long); + + *(int *)sym_base = STP_SYMBOLS; + syms = (struct _stp_symbol *)(sym_base + sizeof(long)); + + kallsyms = fopen ("/proc/kallsyms", "r"); + if (!kallsyms) { + perror("Fatal error: Unable to open /proc/kallsyms:"); + cleanup_and_exit(0); + } + + /* put empty string in data */ + *dataptr++ = 0; + + while (fgets_unlocked(buf, 128, kallsyms) && dataptr < datamax) { + addr = strtoul(buf, &ptr, 16); + while (isspace(*ptr)) ptr++; + type = *ptr++; + if (type == 't' || type == 'T' || type == 'A') { + while (isspace(*ptr)) ptr++; + name = ptr++; + while (!isspace(*ptr)) ptr++; + *ptr++ = 0; + while (*ptr && *ptr != '[') ptr++; + if (*ptr) + continue; /* it was a module */ + syms[i].addr = addr; + syms[i].symbol = (char *)(dataptr - data); + while (*name) *dataptr++ = *name++; + *dataptr++ = 0; + i++; + if (dataptr > datamax - 1000) + break; + } + } + num_syms = i; + qsort(syms, num_syms, sizeof(struct _stp_symbol), compar); + + /* send header */ + *(int *)buf = STP_SYMBOLS; + *(int *)(buf+sizeof(long)) = num_syms; + *(int *)(buf+sizeof(long)+sizeof(int)) = (unsigned)(dataptr - data); + send_data(buf, 2*sizeof(int)+sizeof(long)); + + /* send syms */ + send_data(sym_base, num_syms*sizeof(struct _stp_symbol)+sizeof(long)); + + /* send data */ + send_data(data_base, dataptr-data+sizeof(long)); + + free(data_base); + free(sym_base); + fclose(kallsyms); + + if (dataptr >= datamax) { + fprintf(stderr,"Error: overflowed symbol data area.\n"); + cleanup_and_exit(0); + } +} |