+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+static void usage(FILE *out)
+{
+ fprintf(out, "usage: pstack [-h] PID\n");
+}
+
+static int dumpstack(pid_t pid)
+{
+ int rv, s;
+ unw_addr_space_t rps;
+ unw_cursor_t uw;
+ unw_word_t reg, pcoff;
+ void *ptd;
+ char pnm[64];
+
+ rps = unw_create_addr_space(&_UPT_accessors, 0);
+ ptd = _UPT_create(pid);
+ rv = 0;
+ if((s = unw_init_remote(&uw, rps, ptd)) != 0) {
+ fprintf(stderr, "pstack: init_remote: %i\n", s);
+ rv = 1;
+ goto out;
+ }
+ do {
+ if(!(s = unw_get_proc_name(&uw, pnm, sizeof(pnm), &pcoff)) || (s == -UNW_ENOMEM)) {
+ pnm[sizeof(pnm) - 1] = 0;
+ printf("%s+%jx\n", pnm, (intmax_t)pcoff);
+ } else {
+ unw_get_reg(&uw, UNW_REG_IP, ®);
+ printf("%jx\n", (intmax_t)reg);
+ }
+ } while((s = unw_step(&uw)) > 0);
+ if(s < 0) {
+ fprintf(stderr, "pstack: step: %i\n", s);
+ }
+out:
+ _UPT_destroy(ptd);
+ unw_destroy_addr_space(rps);
+ return(rv);
+}
+
+int main(int argc, char **argv)
+{
+ int c, s;
+ pid_t pid;
+
+ while((c = getopt(argc, argv, "h")) != -1) {
+ switch(c) {
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+ if(argc - optind < 1) {
+ usage(stderr);
+ exit(1);
+ }
+ pid = atoi(argv[optind]);
+ if(ptrace(PTRACE_ATTACH, pid, NULL, NULL)) {
+ fprintf(stderr, "pstack: attach %i: %s\n", pid, strerror(errno));
+ exit(1);
+ }
+ while(1) {
+ if(waitpid(pid, &s, 0) < 0) {
+ fprintf(stderr, "pstack: wait: %s\n", strerror(errno));
+ exit(1);
+ }
+ if(WIFSTOPPED(s))
+ break;
+ }
+ dumpstack(pid);
+ if(ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
+ fprintf(stderr, "pstack: detach: %s\n", strerror(errno));
+ }
+ return(0);
+}