Add Perl support for ucalls / uflow / ustat (#1959)

Sort language entries while at it.
diff --git a/man/man8/ucalls.8 b/man/man8/ucalls.8
index 3917af5..cadb3e0 100644
--- a/man/man8/ucalls.8
+++ b/man/man8/ucalls.8
@@ -1,27 +1,29 @@
 .TH ucalls 8  "2016-11-07" "USER COMMANDS"
 .SH NAME
-ucalls, javacalls, pythoncalls, rubycalls, phpcalls \- Summarize method calls
+ucalls, javacalls, perlcalls, phpcalls, pythoncalls, rubycalls \- Summarize method calls
 from high-level languages and Linux syscalls.
 .SH SYNOPSIS
 .B javacalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
 .br
+.B perlcalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
+.br
+.B phpcalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
+.br
 .B pythoncalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
 .br
 .B rubycalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
 .br
-.B phpcalls [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
-.br
-.B ucalls [-l {java,python,ruby,php}] [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
+.B ucalls [-l {java,perl,php,python,ruby}] [-h] [-T TOP] [-L] [-S] [-v] [-m] pid [interval]
 .SH DESCRIPTION
-This tool summarizes method calls from high-level languages such as Python, 
-Java, Ruby, and PHP. It can also trace Linux system calls. Whenever a method is 
-invoked, ucalls records the call count and optionally the method's execution
+This tool summarizes method calls from high-level languages such as Java, Perl,
+PHP, Python, and Ruby. It can also trace Linux system calls. Whenever a method
+is invoked, ucalls records the call count and optionally the method's execution
 time (latency) and displays a summary.
 
 This uses in-kernel eBPF maps to store per process summaries for efficiency.
 
 This tool relies on USDT probes embedded in many high-level languages, such as
-Java, Python, Ruby, and PHP. It requires a runtime instrumented with these 
+Java, Perl, PHP, Python, and Ruby. It requires a runtime instrumented with these
 probes, which in some cases requires building from source with a USDT-specific
 flag, such as "--enable-dtrace" or "--with-dtrace". For Java, method probes are
 not enabled by default, and can be turned on by running the Java process with
@@ -33,7 +35,7 @@
 CONFIG_BPF and bcc.
 .SH OPTIONS
 .TP
-\-l {java,python,ruby,php}
+\-l {java,perl,php,python,ruby}
 The language to trace. If not provided, only syscalls are traced (when the \-S
 option is used).
 .TP
@@ -73,9 +75,9 @@
 .B ucalls -S 788 10
 .SH OVERHEAD
 Tracing individual method calls will produce a considerable overhead in all
-high-level languages. For languages with just-in-time compilation, such as 
-Java, the overhead can be more considerable than for interpreted languages. 
-On the other hand, syscall tracing will typically be tolerable for most 
+high-level languages. For languages with just-in-time compilation, such as
+Java, the overhead can be more considerable than for interpreted languages.
+On the other hand, syscall tracing will typically be tolerable for most
 processes, unless they have a very unusual rate of system calls.
 .SH SOURCE
 This is from bcc.
diff --git a/man/man8/uflow.8 b/man/man8/uflow.8
index 63b7c75..b6d160e 100644
--- a/man/man8/uflow.8
+++ b/man/man8/uflow.8
@@ -1,23 +1,25 @@
 .TH uflow 8  "2016-11-07" "USER COMMANDS"
 .SH NAME
-uflow, javaflow, pythonflow, rubyflow, phpflow \- Print a flow graph of method
+uflow, javaflow, perlflow, phpflow, pythonflow, rubyflow \- Print a flow graph of method
 calls in high-level languages.
 .SH SYNOPSIS
 .B javaflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
 .br
+.B perlflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
+.br
+.B phpflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
+.br
 .B pythonflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
 .br
 .B rubyflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
 .br
-.B phpflow [-h] [-M METHOD] [-C CLAZZ] [-v] pid
-.br
-.B uflow [-h] [-M METHOD] [-C CLAZZ] [-v] [-l {java,python,ruby,php}] pid
+.B uflow [-h] [-M METHOD] [-C CLAZZ] [-v] [-l {java,perl,php,python,ruby}] pid
 .SH DESCRIPTION
 uflow traces method calls and prints them in a flow graph that can facilitate
 debugging and diagnostics by following the program's execution (method flow).
 
 This tool relies on USDT probes embedded in many high-level languages, such as
-Java, Python, Ruby, and PHP. It requires a runtime instrumented with these 
+Java, Perl, PHP, Python, and Ruby. It requires a runtime instrumented with these
 probes, which in some cases requires building from source with a USDT-specific
 flag, such as "--enable-dtrace" or "--with-dtrace". For Java processes, the
 startup flag "-XX:+ExtendedDTraceProbes" is required. For PHP processes, the
@@ -39,7 +41,7 @@
 \-v
 Print the resulting BPF program, for debugging purposes.
 .TP
-{java,python,ruby,php}
+{java,perl,php,python,ruby}
 The language to trace.
 .TP
 pid
diff --git a/man/man8/ustat.8 b/man/man8/ustat.8
index 8eb231e..6dd6f12 100644
--- a/man/man8/ustat.8
+++ b/man/man8/ustat.8
@@ -1,34 +1,37 @@
 .TH ustat 8  "2016-11-07" "USER COMMANDS"
 .SH NAME
-ustat, javastat, pythonstat, rubystat, nodestat, phpstat \- Activity stats from
+ustat, javastat, nodestat, perlstat, phpstat, pythonstat, rubystat \- Activity stats from
 high-level languages.
 .SH SYNOPSIS
 .B javastat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
 .br
+.B nodestat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
+.br
+.B perlstat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
+.br
+.B phpstat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
+.br
 .B pythonstat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
 .br
 .B rubystat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
 .br
-.B nodestat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
-.br
-.B phpstat [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
-.br
-.B ustat [-l {java,python,ruby,node,php}] [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
+.B ustat [-l {java,perl,python,ruby,node,php}] [-C] [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d] [interval [count]]
 .SH DESCRIPTION
 This is "top" for high-level language events, such as garbage collections,
 exceptions, thread creations, object allocations, method calls, and more. The
 events are aggregated for each process and printed in a top-like table, which
-can be sorted by various fields.
+can be sorted by various fields. Not all language runtimes provide the same
+set of details.
 
 This uses in-kernel eBPF maps to store per process summaries for efficiency.
 
 This tool relies on USDT probes embedded in many high-level languages, such as
-Node, Java, Python, Ruby, and PHP. It requires a runtime instrumented with these 
-probes, which in some cases requires building from source with a USDT-specific
-flag, such as "--enable-dtrace" or "--with-dtrace". For Java, some probes are
-not enabled by default, and can be turned on by running the Java process with
-the "-XX:+ExtendedDTraceProbes" flag. For PHP processes, the environment
-variable USE_ZEND_DTRACE must be set to 1.
+Java, Node, Perl, PHP, Python, and Ruby. It requires a runtime instrumented with
+these probes, which in some cases requires building from source with a
+USDT-specific flag, such as "--enable-dtrace" or "--with-dtrace". For Java,
+some probes are not enabled by default, and can be turned on by running the Java
+process with the "-XX:+ExtendedDTraceProbes" flag. For PHP processes, the
+environment variable USE_ZEND_DTRACE must be set to 1.
 
 Newly-created processes will only be traced at the next interval. If you run
 this tool with a short interval (say, 1-5 seconds), this should be virtually
@@ -40,7 +43,7 @@
 CONFIG_BPF and bcc.
 .SH OPTIONS
 .TP
-\-l {java,python,ruby,node,php}
+\-l {java,node,perl,php,python,ruby}
 The language to trace. By default, all languages are traced.
 .TP
 \-C
diff --git a/snapcraft/snapcraft.yaml b/snapcraft/snapcraft.yaml
index d2b65dd..e4acdb2 100644
--- a/snapcraft/snapcraft.yaml
+++ b/snapcraft/snapcraft.yaml
@@ -180,6 +180,15 @@
     opensnoop:
         command: wrapper opensnoop
         aliases: [opensnoop]
+    perlcalls:
+        command: wrapper perlcalls
+        aliases: [perlcalls]
+    perlflow:
+        command: wrapper perlflow
+        aliases: [perlflow]
+    perlstat:
+        command: wrapper perlstat
+        aliases: [perlstat]
     phpcalls:
         command: wrapper phpcalls
         aliases: [phpcalls]
diff --git a/src/cc/bcc_proc.c b/src/cc/bcc_proc.c
index 6fe11a0..d694eb9 100644
--- a/src/cc/bcc_proc.c
+++ b/src/cc/bcc_proc.c
@@ -406,9 +406,9 @@
 }
 
 /* Detects the following languages + C. */
-const char *languages[] = {"java", "python", "ruby", "php", "node"};
+const char *languages[] = {"java", "node", "perl", "php", "python", "ruby"};
 const char *language_c = "c";
-const int nb_languages = 5;
+const int nb_languages = 6;
 
 const char *bcc_procutils_language(int pid) {
   char procfilename[24], line[4096], pathname[32], *str;
diff --git a/tests/python/test_utils.py b/tests/python/test_utils.py
index 69dddf6..54b97cf 100755
--- a/tests/python/test_utils.py
+++ b/tests/python/test_utils.py
@@ -15,7 +15,7 @@
         self.assertEqual(len(online_cpus), num_cores)
 
     def test_detect_language(self):
-        candidates = ["java", "ruby", "php", "node", "c", "python"]
+        candidates = ["c", "java", "perl", "php", "node", "ruby", "python"]
         language = detect_language(candidates, os.getpid())
         self.assertEqual(language, "python")
 
diff --git a/tools/lib/ucalls.py b/tools/lib/ucalls.py
index 97d60f2..b2d165c 100755
--- a/tools/lib/ucalls.py
+++ b/tools/lib/ucalls.py
@@ -4,7 +4,7 @@
 # ucalls  Summarize method calls in high-level languages and/or system calls.
 #         For Linux, uses BCC, eBPF.
 #
-# USAGE: ucalls [-l {java,python,ruby,php}] [-h] [-T TOP] [-L] [-S] [-v] [-m]
+# USAGE: ucalls [-l {java,perl,php,python,ruby}] [-h] [-T TOP] [-L] [-S] [-v] [-m]
 #        pid [interval]
 #
 # Copyright 2016 Sasha Goldshtein
@@ -18,7 +18,7 @@
 from time import sleep
 import os
 
-languages = ["java", "python", "ruby", "php"]
+languages = ["java", "perl", "php", "python", "ruby"]
 
 examples = """examples:
     ./ucalls -l java 185        # trace Java calls and print statistics on ^C
@@ -69,6 +69,18 @@
     read_method = "bpf_usdt_readarg(4, ctx, &method);"
     extra_message = ("If you do not see any results, make sure you ran java"
                      " with option -XX:+ExtendedDTraceProbes")
+elif language == "perl":
+    entry_probe = "sub__entry"
+    return_probe = "sub__return"
+    read_class = "bpf_usdt_readarg(2, ctx, &clazz);"    # filename really
+    read_method = "bpf_usdt_readarg(1, ctx, &method);"
+elif language == "php":
+    entry_probe = "function__entry"
+    return_probe = "function__return"
+    read_class = "bpf_usdt_readarg(4, ctx, &clazz);"
+    read_method = "bpf_usdt_readarg(1, ctx, &method);"
+    extra_message = ("If you do not see any results, make sure the environment"
+                     " variable USE_ZEND_DTRACE is set to 1")
 elif language == "python":
     entry_probe = "function__entry"
     return_probe = "function__return"
@@ -80,13 +92,6 @@
     return_probe = "method__return"
     read_class = "bpf_usdt_readarg(1, ctx, &clazz);"
     read_method = "bpf_usdt_readarg(2, ctx, &method);"
-elif language == "php":
-    entry_probe = "function__entry"
-    return_probe = "function__return"
-    read_class = "bpf_usdt_readarg(4, ctx, &clazz);"
-    read_method = "bpf_usdt_readarg(1, ctx, &method);"
-    extra_message = ("If you do not see any results, make sure the environment"
-                     " variable USE_ZEND_DTRACE is set to 1")
 elif not language or language == "none":
     if not args.syscalls:
         print("Nothing to do; use -S to trace syscalls.")
diff --git a/tools/lib/ucalls_example.txt b/tools/lib/ucalls_example.txt
index fffc76f..69d401a 100644
--- a/tools/lib/ucalls_example.txt
+++ b/tools/lib/ucalls_example.txt
@@ -2,8 +2,9 @@
 
 
 ucalls summarizes method calls in various high-level languages, including Java,
-Python, Ruby, PHP, and Linux system calls. It displays statistics on the most 
-frequently called methods, as well as the latency (duration) of these methods.
+Perl, PHP, Python, Ruby, and Linux system calls. It displays statistics on the
+most frequently called methods, as well as the latency (duration) of these
+methods.
 
 Through the syscalls support, ucalls can provide basic information on a 
 process' interaction with the system including syscall counts and latencies. 
@@ -60,7 +61,7 @@
 USAGE message:
 
 # ./ucalls.py -h
-usage: ucalls.py [-h] [-l {java,python,ruby,php,none}] [-T TOP] [-L] [-S] [-v]
+usage: ucalls.py [-h] [-l {java,perl,php,python,ruby,none}] [-T TOP] [-L] [-S] [-v]
                  [-m]
                  pid [interval]
 
@@ -72,7 +73,7 @@
 
 optional arguments:
   -h, --help            show this help message and exit
-  -l {java,python,ruby,php,none}, --language {java,python,ruby,php,none}
+  -l {java,perl,php,python,ruby,none}, --language {java,perl,php,python,ruby,none}
                         language to trace (if none, trace syscalls only)
   -T TOP, --top TOP     number of most frequent/slow calls to print
   -L, --latency         record method latency from enter to exit (except
diff --git a/tools/lib/uflow.py b/tools/lib/uflow.py
index 025a193..8419c88 100755
--- a/tools/lib/uflow.py
+++ b/tools/lib/uflow.py
@@ -4,7 +4,7 @@
 # uflow  Trace method execution flow in high-level languages.
 #        For Linux, uses BCC, eBPF.
 #
-# USAGE: uflow [-C CLASS] [-M METHOD] [-v] {java,python,ruby,php} pid
+# USAGE: uflow [-C CLASS] [-M METHOD] [-v] {java,perl,php,python,ruby} pid
 #
 # Copyright 2016 Sasha Goldshtein
 # Licensed under the Apache License, Version 2.0 (the "License")
@@ -18,7 +18,7 @@
 import time
 import os
 
-languages = ["java", "python", "ruby", "php"]
+languages = ["java", "perl", "php", "python", "ruby"]
 
 examples = """examples:
     ./uflow -l java 185                # trace Java method calls in process 185
@@ -127,6 +127,20 @@
     enable_probe("method__return", "java_return",
                  "bpf_usdt_readarg(2, ctx, &clazz);",
                  "bpf_usdt_readarg(4, ctx, &method);", is_return=True)
+elif language == "perl":
+    enable_probe("sub__entry", "perl_entry",
+                 "bpf_usdt_readarg(2, ctx, &clazz);",
+                 "bpf_usdt_readarg(1, ctx, &method);", is_return=False)
+    enable_probe("sub__return", "perl_return",
+                 "bpf_usdt_readarg(2, ctx, &clazz);",
+                 "bpf_usdt_readarg(1, ctx, &method);", is_return=True)
+elif language == "php":
+    enable_probe("function__entry", "php_entry",
+                 "bpf_usdt_readarg(4, ctx, &clazz);",
+                 "bpf_usdt_readarg(1, ctx, &method);", is_return=False)
+    enable_probe("function__return", "php_return",
+                 "bpf_usdt_readarg(4, ctx, &clazz);",
+                 "bpf_usdt_readarg(1, ctx, &method);", is_return=True)
 elif language == "python":
     enable_probe("function__entry", "python_entry",
                  "bpf_usdt_readarg(1, ctx, &clazz);",   # filename really
@@ -147,13 +161,6 @@
     enable_probe("cmethod__return", "ruby_creturn",
                  "bpf_usdt_readarg(1, ctx, &clazz);",
                  "bpf_usdt_readarg(2, ctx, &method);", is_return=True)
-elif language == "php":
-    enable_probe("function__entry", "php_entry",
-                 "bpf_usdt_readarg(4, ctx, &clazz);",
-                 "bpf_usdt_readarg(1, ctx, &method);", is_return=False)
-    enable_probe("function__return", "php_return",
-                 "bpf_usdt_readarg(4, ctx, &clazz);",
-                 "bpf_usdt_readarg(1, ctx, &method);", is_return=True)
 else:
     print("No language detected; use -l to trace a language.")
     exit(1)
diff --git a/tools/lib/uflow_example.txt b/tools/lib/uflow_example.txt
index 557d972..fae52f3 100644
--- a/tools/lib/uflow_example.txt
+++ b/tools/lib/uflow_example.txt
@@ -4,8 +4,8 @@
 uflow traces method entry and exit events and prints a visual flow graph that
 shows how methods are entered and exited, similar to a tracing debugger with
 breakpoints. This can be useful for understanding program flow in high-level
-languages such as Java, Python, Ruby, and PHP, which provide USDT probes for
-method invocations.
+languages such as Java, Perl, PHP, Python, and Ruby, which provide USDT
+probes for method invocations.
 
 
 For example, trace all Ruby method calls in a specific process:
@@ -88,7 +88,7 @@
 USAGE message:
 
 # ./uflow -h
-usage: uflow.py [-h] [-l {java,python,ruby,php}] [-M METHOD] [-C CLAZZ] [-v]
+usage: uflow.py [-h] [-l {java,perl,php,python,ruby}] [-M METHOD] [-C CLAZZ] [-v]
                 pid
 
 Trace method execution flow in high-level languages.
@@ -98,7 +98,7 @@
 
 optional arguments:
   -h, --help            show this help message and exit
-  -l {java,python,ruby,php}, --language {java,python,ruby,php}
+  -l {java,perl,php,python,ruby}, --language {java,perl,php,python,ruby}
                         language to trace
   -M METHOD, --method METHOD
                         trace only calls to methods starting with this prefix
diff --git a/tools/lib/ustat.py b/tools/lib/ustat.py
index 34cc019..8b2f80f 100755
--- a/tools/lib/ustat.py
+++ b/tools/lib/ustat.py
@@ -5,7 +5,7 @@
 #        method calls, class loads, garbage collections, and more.
 #        For Linux, uses BCC, eBPF.
 #
-# USAGE: ustat [-l {java,python,ruby,node,php}] [-C]
+# USAGE: ustat [-l {java,node,perl,php,python,ruby}] [-C]
 #        [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d]
 #        [interval [count]]
 #
@@ -132,7 +132,7 @@
             formatter_class=argparse.RawDescriptionHelpFormatter,
             epilog=examples)
         parser.add_argument("-l", "--language",
-            choices=["java", "python", "ruby", "node", "php"],
+            choices=["java", "node", "perl", "php", "python", "ruby"],
             help="language to trace (default: all languages)")
         parser.add_argument("-C", "--noclear", action="store_true",
             help="don't clear the screen")
@@ -151,18 +151,30 @@
 
     def _create_probes(self):
         probes_by_lang = {
+                "java": Probe("java", ["java"], {
+                    "gc__begin": Category.GC,
+                    "mem__pool__gc__begin": Category.GC,
+                    "thread__start": Category.THREAD,
+                    "class__loaded": Category.CLOAD,
+                    "object__alloc": Category.OBJNEW,
+                    "method__entry": Category.METHOD,
+                    "ExceptionOccurred__entry": Category.EXCP
+                    }),
                 "node": Probe("node", ["node"], {
                     "gc__start": Category.GC
                     }),
-                "python": Probe("python", ["python"], {
-                    "function__entry": Category.METHOD,
-                    "gc__start": Category.GC
+                "perl": Probe("perl", ["perl"], {
+                    "sub__entry": Category.METHOD
                     }),
                 "php": Probe("php", ["php"], {
                     "function__entry": Category.METHOD,
                     "compile__file__entry": Category.CLOAD,
                     "exception__thrown": Category.EXCP
                     }),
+                "python": Probe("python", ["python"], {
+                    "function__entry": Category.METHOD,
+                    "gc__start": Category.GC
+                    }),
                 "ruby": Probe("ruby", ["ruby", "irb"], {
                     "method__entry": Category.METHOD,
                     "cmethod__entry": Category.METHOD,
@@ -176,15 +188,6 @@
                     "load__entry": Category.CLOAD,
                     "raise": Category.EXCP
                     }),
-                "java": Probe("java", ["java"], {
-                    "gc__begin": Category.GC,
-                    "mem__pool__gc__begin": Category.GC,
-                    "thread__start": Category.THREAD,
-                    "class__loaded": Category.CLOAD,
-                    "object__alloc": Category.OBJNEW,
-                    "method__entry": Category.METHOD,
-                    "ExceptionOccurred__entry": Category.EXCP
-                    })
                 }
 
         if self.args.language:
diff --git a/tools/lib/ustat_example.txt b/tools/lib/ustat_example.txt
index 79f67fd..8a9ee87 100644
--- a/tools/lib/ustat_example.txt
+++ b/tools/lib/ustat_example.txt
@@ -4,7 +4,7 @@
 ustat is a "top"-like tool for monitoring events in high-level languages. It 
 prints statistics about garbage collections, method calls, object allocations,
 and various other events for every process that it recognizes with a Java,
-Python, Ruby, Node, or PHP runtime.
+Node, Perl, PHP, Python, and Ruby runtime.
 
 For example:
 
@@ -48,7 +48,7 @@
 USAGE message:
 
 # ./ustat.py -h
-usage: ustat.py [-h] [-l {java,python,ruby,node,php}] [-C]
+usage: ustat.py [-h] [-l {java,node,perl,php,python,ruby}] [-C]
                 [-S {cload,excp,gc,method,objnew,thread}] [-r MAXROWS] [-d]
                 [interval] [count]
 
@@ -60,7 +60,7 @@
 
 optional arguments:
   -h, --help            show this help message and exit
-  -l {java,python,ruby,node,php}, --language {java,python,ruby,node,php}
+  -l {{java,node,perl,php,python,ruby}}, --language {java,node,perl,php,python,ruby}
                         language to trace (default: all languages)
   -C, --noclear         don't clear the screen
   -S {cload,excp,gc,method,objnew,thread}, --sort {cload,excp,gc,method,objnew,thread}
diff --git a/tools/perlcalls.sh b/tools/perlcalls.sh
new file mode 100755
index 0000000..74c6b03
--- /dev/null
+++ b/tools/perlcalls.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+lib=$(dirname $0)/lib
+$lib/ucalls.py -l perl "$@"
diff --git a/tools/perlcalls_example.txt b/tools/perlcalls_example.txt
new file mode 120000
index 0000000..22b0fb3
--- /dev/null
+++ b/tools/perlcalls_example.txt
@@ -0,0 +1 @@
+lib/ucalls_example.txt
\ No newline at end of file
diff --git a/tools/perlflow.sh b/tools/perlflow.sh
new file mode 100755
index 0000000..4fd2397
--- /dev/null
+++ b/tools/perlflow.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+lib=$(dirname $0)/lib
+$lib/uflow.py -l perl "$@"
diff --git a/tools/perlflow_example.txt b/tools/perlflow_example.txt
new file mode 120000
index 0000000..bc71efc
--- /dev/null
+++ b/tools/perlflow_example.txt
@@ -0,0 +1 @@
+lib/uflow_example.txt
\ No newline at end of file
diff --git a/tools/perlstat.sh b/tools/perlstat.sh
new file mode 100755
index 0000000..4bb417f
--- /dev/null
+++ b/tools/perlstat.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+lib=$(dirname $0)/lib
+$lib/ustat.py -l perl "$@"
diff --git a/tools/perlstat_example.txt b/tools/perlstat_example.txt
new file mode 120000
index 0000000..544e5ad
--- /dev/null
+++ b/tools/perlstat_example.txt
@@ -0,0 +1 @@
+lib/ustat_example.txt
\ No newline at end of file