diff options
author | Eric Wong <e@80x24.org> | 2022-12-16 14:39:33 +0000 |
---|---|---|
committer | Eric Wong <mwrap-perl@80x24.org> | 2022-12-16 20:54:01 +0000 |
commit | fc26dc8b7f3c95cc362439893c791d8654a8acbf (patch) | |
tree | 1e9462c3a2397a3a0e6a1452b0068006f649f664 | |
parent | 0e7427bb42160552b5e37424b89970a20d93fcfd (diff) | |
download | mwrap-fc26dc8b7f3c95cc362439893c791d8654a8acbf.tar.gz |
mwrap_httpd will have online help :>
-rw-r--r-- | httpd.h | 29 | ||||
-rw-r--r-- | script/mwrap-perl | 78 | ||||
-rw-r--r-- | script/mwrap-rproxy | 84 |
3 files changed, 180 insertions, 11 deletions
@@ -483,7 +483,7 @@ static off_t write_loc_name(FILE *fp, const struct src_loc *l) if (!s) return -1; if (l->f) fputc('\n', fp); - /* omit local " [$ADDRESS]" if doing deep backtraces */ + /* omit local " [RETURN_ADDRESS]" if doing deep backtraces */ for (uint32_t i = 0; i < l->bt_len; ++i) { char *c = memrchr(s[i], '[', strlen(s[i])); if (c && c > (s[i] + 2) && c[-1] == ' ') @@ -723,12 +723,29 @@ static enum mw_qev pid_root(struct mw_h1 *h1, struct mw_h1req *h1r) if (!fp) return h1_close(h1); #define default_min "2000" - FPUTS("<html><head><title>mwrap demo</title></head><body>" - "<p>mwrap demo", fp); + int pid = (int)getpid(); + fprintf(fp, "<html><head><title>mwrap PID:%d</title></head><body>" + "<pre>mwrap PID:%d", pid, pid); show_stats(fp); - FPUTS("<p><a\nhref=\"each/" default_min "\">allocations >" - default_min " bytes</a>" - "<p><a\nhref=\"" URL "\">" URL "</a></body></html>", fp); + FPUTS("\n\n<a\nhref=\"each/" default_min "\">allocations >" + default_min " bytes</a>""</pre><pre\nid=help>" +"To get source file and line info for native backtraces, consult your\n" +"distro for -dbg, -dbgsym, or -debug packages.\n" +"And/or rebuild your code with debug flags (e.g. `-ggdb3' if using gcc)\n" +"and don't strip the resulting binaries.\n" +"You should see locations from the backtrace_symbols(3) function\n" +"in the form of FILENAME(+OFFSET) or FILENAME(SYMBOL+OFFSET)\n" +"(e.g. /usr/lib/foo.so(+0xdead) or /usr/lib/foo.so(func+(0xbeef))\n" +"\n" +"Any version of addr2line should decode FILENAME(+OFFSET) locations:\n" +"\n" +" addr2line -e FILENAME OFFSET\n" +"\n" +"SYMBOL+OFFSET requires addr2line from GNU binutils 2.39+ (Aug 2022):\n" +"\n" +" addr2line -e FILENAME SYMBOL+OFFSET\n", fp); + + FPUTS("\n<a\nhref=\"" URL "\">" URL "</a></pre></body></html>", fp); return h1_200(h1, &html, TYPE_HTML); #undef default_min } diff --git a/script/mwrap-perl b/script/mwrap-perl index 78e71e3..53eaa10 100644 --- a/script/mwrap-perl +++ b/script/mwrap-perl @@ -6,6 +6,10 @@ use Devel::Mwrap; my ($so) = grep(m!/Mwrap\.so\z!, @DynaLoader::dl_shared_objects); defined($so) or die 'Mwrap.so not loaded'; my $cur = $ENV{LD_PRELOAD}; +if (!@ARGV || ($ARGV[0] // '') =~ /\A(?:-h|--help)\z/) { + require Pod::Usage; + Pod::Usage::pod2usage(@ARGV ? 0 : 1); +} if (defined $cur) { my @cur = split(/[: \t]+/, $cur); if (!grep(/\A\Q$so\E\z/, @cur)) { @@ -17,3 +21,77 @@ if (defined $cur) { $ENV{LD_PRELOAD} = $so; } exec @ARGV; +__END__ +=head1 NAME + +mwrap-perl - run any command under mwrap + +=head1 SYNOPSIS + + # to trace a long-running program and access it via $DIRECTORY/$PID.sock: + MWRAP=socket_dir:$DIRECTORY mwrap-perl COMMAND + + # to trace a short-lived command and dump its output to a log: + MWRAP=dump_path:$FILENAME mwrap-perl COMMAND + +=head1 DESCRIPTION + +mwrap-perl is a command-line to automatically add Mwrap.so as an +LD_PRELOAD for any command. It will resolve malloc-family calls +to a Perl file and line number, and it can also provide a backtrace +of native (C/C++) functions for non-Perl programs. + +=head1 ENVIRONMENT + +C<MWRAP> is the only environment variable read. It contains multiple +options delimited by C<,> with names and values delimited by C<:> + +=item socket_dir:$DIRECTORY + +This launches an embedded HTTP server in each process and binds it +to C<$DIRECTORY/$PID.sock>. C<curl --unix-socket $DIRECTORY/$PID.sock> +or L<mwrap-rproxy(1p)> may be used to access various endpoints in +the HTTP server. + +=item: bt:$DEPTH + +The backtrace depth for L<backtrace(3)> in addition to the Perl +file and line number where C<$DEPTH> is a non-negative number. + +The maximum allowed value is 32, though values of 5 or less are +typically useful. Increasing this to even 2 or 3 can significantly +increase the amount of memory mwrap (and liburcu) itself uses. + +This is only useful in conjunction with C<socket_dir> + +Default: 0 + +=item dump_path:$FILENAME + +Dumps the output + + total_bytes call_count location + +In the future, dumping to a self-describing CSV will be supported + +=back + +=head1 CONTACT + +Feedback welcome via plain-text mail to L<mailto:mwrap-perl@80x24.org> + +Mail archives are hosted at L<https://80x24.org/mwrap-perl/> + +=head1 COPYRIGHT + +Copyright all contributors L<mailto:mwrap-perl@80x24.org> + +License: GPL-2.0+ L<https://www.gnu.org/licenses/gpl-2.0.txt> + +Source code is at L<https://80x24.org/mwrap-perl.git/> + +=head1 SEE ALSO + +L<mwrap-rproxy(1)>, L<Devel::Mwrap(3pm)> + +=cut diff --git a/script/mwrap-rproxy b/script/mwrap-rproxy index 97cca8e..da5379a 100644 --- a/script/mwrap-rproxy +++ b/script/mwrap-rproxy @@ -4,14 +4,17 @@ # thin wrapper for Devel::Mwrap::Rproxy use v5.12; # strict eval { require Plack::Runner } or die "Plack not installed: $@\n"; -require Devel::Mwrap::Rproxy; use Getopt::Long qw(:config no_ignore_case no_auto_abbrev pass_through); my $usage = "$0 --socket-dir=/path/to/socket-dir [PLACKUP_OPTIONS]\n"; -my $socket_dir; -my $gz = 1; -GetOptions('socket-dir=s' => \$socket_dir, 'deflate!' => \$gz) or die $usage; +my %opt = (deflate => 1); +GetOptions(\%opt, 'socket-dir=s', 'deflate!', 'help|h') or do { + require Pod::Usage; Pod::Usage::pod2usage(1); +}; +if ($opt{help}) { require Pod::Usage; Pod::Usage::pod2usage(0) } +my $socket_dir = delete $opt{'socket-dir'}; $socket_dir //= ($ENV{MWRAP} // '') =~ m!\bsocket_dir:([^,]+)! ? $1 : undef; $socket_dir // die $usage; +require Devel::Mwrap::Rproxy; my $rproxy = Devel::Mwrap::Rproxy->new($socket_dir); my $app = sub { $rproxy->call(@_) }; my $runner = Plack::Runner->new; @@ -28,7 +31,78 @@ Inherited socket (fd=3) is non-blocking, making it blocking. $runner->set_options(listen_sock => $s); } } -if ($gz && eval { require Plack::Middleware::Deflater } and !$@) { +if ($opt{deflate} && eval { require Plack::Middleware::Deflater } and !$@) { $app = Plack::Middleware::Deflater->wrap($app); } $runner->run($app); +__END__ +=head1 NAME + +mwrap-rproxy - reverse proxy for embedded per-process mwrap httpd + +=head1 SYNOPSIS + + # start the long-running COMMAND you wish to trace: + MWRAP=socket_dir:$DIRECTORY mwrap-perl COMMAND + + # in a different terminal, point mwrap-proxy to the mwrap-perl socket_dir + mwrap-rproxy --socket-dir=$DIRECTORY -l 127.0.0.1:8080 + + # open http://127.0.0.1:8080/ in your favorite web browser: + w3m http://127.0.0.1:8080/ + +=head1 DESCRIPTION + +B<mwrap-rproxy> is a PSGI reverse proxy to provide access +via TCP to the native, Unix-socket-only httpd embedded inside +mwrap core. It provides a listing of process IDs of each process +traced via mwrap. + +B<mwrap-rproxy> does not have a hard dependency on mwrap-perl itself, +it exists to provide a convenient interface to programs being +traced by mwrap-perl. + +=head1 OPTIONS + +=over 4 + +=item --socket-dir=DIRECTORY + +If unset, it will attempt to parse C<socket_dir:> from the C<MWRAP> +environment (see L<mwrap-perl(1p)>). + +=item --no-deflate + +L<Plack::Middleware::Deflater(3pm)> is loaded by default if available. +Using C<--no-deflate> will save CPU cycles at the expe + +=back + +Additionally, all options in L<plackup(1p)> are supported. Notably, +C<-l>/C<--listen> and C<--path=/prefix> may be useful. + +=head1 ENVIRONMENT + +mwrap-rproxy supports systemd (and compatible) socket activation via +C<LISTEN_PID> and C<LISTEN_FDS> variables. See L<systemd.socket(5)> +and L<sd_listen_fds(3)>. + +=head1 CONTACT + +Feedback welcome via plain-text mail to L<mailto:mwrap-perl@80x24.org> + +Mail archives are hosted at L<https://80x24.org/mwrap-perl/> + +=head1 COPYRIGHT + +Copyright all contributors L<mailto:mwrap-perl@80x24.org> + +License: GPL-2.0+ L<https://www.gnu.org/licenses/gpl-2.0.txt> + +Source code is at L<https://80x24.org/mwrap-perl.git/> + +=head1 SEE ALSO + +L<mwrap-perl(1p)> + +=cut |