summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c518
1 files changed, 334 insertions, 184 deletions
diff --git a/proc.c b/proc.c
index 3b4bfdb..bf2a172 100644
--- a/proc.c
+++ b/proc.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2011,2012,2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 2010 Joe Damato
* Copyright (C) 1998,2009 Juan Cespedes
*
@@ -29,63 +29,63 @@
#include <stdlib.h>
#include <string.h>
-#if defined(HAVE_LIBUNWIND)
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-#endif /* defined(HAVE_LIBUNWIND) */
-
#include "backend.h"
#include "breakpoint.h"
#include "debug.h"
#include "fetch.h"
+#include "options.h"
#include "proc.h"
#include "value_dict.h"
-#ifndef ARCH_HAVE_PROCESS_DATA
+#if defined(HAVE_LIBDW)
+# include "dwarf_prototypes.h"
+#endif /* defined(HAVE_LIBDW) */
+
+#ifndef OS_HAVE_PROCESS_DATA
int
-arch_process_init(struct Process *proc)
+os_process_init(struct process *proc)
{
return 0;
}
void
-arch_process_destroy(struct Process *proc)
+os_process_destroy(struct process *proc)
{
}
int
-arch_process_clone(struct Process *retp, struct Process *proc)
+os_process_clone(struct process *retp, struct process *proc)
{
return 0;
}
int
-arch_process_exec(struct Process *proc)
+os_process_exec(struct process *proc)
{
return 0;
}
#endif
-#ifndef OS_HAVE_PROCESS_DATA
+#ifndef ARCH_HAVE_PROCESS_DATA
int
-os_process_init(struct Process *proc)
+arch_process_init(struct process *proc)
{
return 0;
}
void
-os_process_destroy(struct Process *proc)
+arch_process_destroy(struct process *proc)
{
}
int
-os_process_clone(struct Process *retp, struct Process *proc)
+arch_process_clone(struct process *retp, struct process *proc)
{
return 0;
}
int
-os_process_exec(struct Process *proc)
+arch_process_exec(struct process *proc)
{
return 0;
}
@@ -93,25 +93,32 @@ os_process_exec(struct Process *proc)
#ifndef ARCH_HAVE_DYNLINK_DONE
void
-arch_dynlink_done(struct Process *proc)
+arch_dynlink_done(struct process *proc)
{
}
#endif
-static void add_process(struct Process *proc, int was_exec);
-static void unlist_process(struct Process *proc);
+static int add_process(struct process *proc, int was_exec);
+static void unlist_process(struct process *proc);
static void
-destroy_unwind(struct Process *proc)
+destroy_unwind(struct process *proc)
{
#if defined(HAVE_LIBUNWIND)
- _UPT_destroy(proc->unwind_priv);
- unw_destroy_addr_space(proc->unwind_as);
+ if (proc->unwind_priv != NULL)
+ _UPT_destroy(proc->unwind_priv);
+ if (proc->unwind_as != NULL)
+ unw_destroy_addr_space(proc->unwind_as);
#endif /* defined(HAVE_LIBUNWIND) */
+
+#if defined(HAVE_LIBDW)
+ if (proc->dwfl != NULL)
+ dwfl_end(proc->dwfl);
+#endif /* defined(HAVE_LIBDW) */
}
static int
-process_bare_init(struct Process *proc, const char *filename,
+process_bare_init(struct process *proc, const char *filename,
pid_t pid, int was_exec)
{
if (!was_exec) {
@@ -121,39 +128,67 @@ process_bare_init(struct Process *proc, const char *filename,
if (proc->filename == NULL) {
fail:
free(proc->filename);
- if (proc->breakpoints != NULL)
- dict_clear(proc->breakpoints);
+ if (proc->breakpoints != NULL) {
+ dict_destroy(proc->breakpoints,
+ NULL, NULL, NULL);
+ free(proc->breakpoints);
+ proc->breakpoints = NULL;
+ }
return -1;
}
}
/* Add process so that we know who the leader is. */
proc->pid = pid;
- add_process(proc, was_exec);
- if (proc->leader == NULL)
+ if (add_process(proc, was_exec) < 0)
+ goto fail;
+ if (proc->leader == NULL) {
+ unlist_and_fail:
+ if (!was_exec)
+ unlist_process(proc);
goto fail;
+ }
if (proc->leader == proc) {
- proc->breakpoints = dict_init(target_address_hash,
- target_address_cmp);
+ proc->breakpoints = malloc(sizeof(*proc->breakpoints));
if (proc->breakpoints == NULL)
- goto fail;
+ goto unlist_and_fail;
+ DICT_INIT(proc->breakpoints,
+ arch_addr_t, struct breakpoint *,
+ arch_addr_hash, arch_addr_eq, NULL);
} else {
proc->breakpoints = NULL;
}
#if defined(HAVE_LIBUNWIND)
- proc->unwind_priv = _UPT_create(pid);
- proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
+ if (options.bt_depth > 0) {
+ proc->unwind_priv = _UPT_create(pid);
+ proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0);
+
+ if (proc->unwind_priv == NULL || proc->unwind_as == NULL) {
+ fprintf(stderr,
+ "Couldn't initialize unwinding "
+ "for process %d\n", proc->pid);
+ destroy_unwind(proc);
+ proc->unwind_priv = NULL;
+ proc->unwind_as = NULL;
+ }
+ }
#endif /* defined(HAVE_LIBUNWIND) */
+#if defined(HAVE_LIBDW)
+ proc->dwfl = NULL; /* Initialize for leader only on first library. */
+ proc->should_attach_dwfl = 1; /* should try to attach the DWFL data */
+#endif /* defined(HAVE_LIBDW) */
+
return 0;
}
static void
-process_bare_destroy(struct Process *proc, int was_exec)
+process_bare_destroy(struct process *proc, int was_exec)
{
- dict_clear(proc->breakpoints);
+ dict_destroy(proc->breakpoints, NULL, NULL, NULL);
+ free(proc->breakpoints);
if (!was_exec) {
free(proc->filename);
unlist_process(proc);
@@ -162,7 +197,7 @@ process_bare_destroy(struct Process *proc, int was_exec)
}
static int
-process_init_main(struct Process *proc)
+process_init_main(struct process *proc)
{
if (breakpoints_init(proc) < 0) {
fprintf(stderr, "failed to init breakpoints %d\n",
@@ -174,7 +209,7 @@ process_init_main(struct Process *proc)
}
int
-process_init(struct Process *proc, const char *filename, pid_t pid)
+process_init(struct process *proc, const char *filename, pid_t pid)
{
if (process_bare_init(proc, filename, pid, 0) < 0) {
fail:
@@ -194,9 +229,11 @@ process_init(struct Process *proc, const char *filename, pid_t pid)
goto fail;
}
- if (proc->leader != proc)
- return 0;
- if (process_init_main(proc) < 0) {
+ if (proc->leader != proc) {
+ proc->e_machine = proc->leader->e_machine;
+ proc->e_class = proc->leader->e_class;
+ get_arch_dep(proc);
+ } else if (process_init_main(proc) < 0) {
process_bare_destroy(proc, 0);
goto fail;
}
@@ -204,7 +241,7 @@ process_init(struct Process *proc, const char *filename, pid_t pid)
}
static enum callback_status
-destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
+destroy_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
{
breakpoint_destroy(bp);
free(bp);
@@ -212,10 +249,10 @@ destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
}
// XXX see comment in handle_event.c
-void callstack_pop(struct Process *proc);
+void callstack_pop(struct process *proc);
static void
-private_process_destroy(struct Process *proc, int was_exec)
+private_process_destroy(struct process *proc, int was_exec)
{
/* Pop remaining stack elements. */
while (proc->callstack_depth > 0) {
@@ -249,7 +286,8 @@ private_process_destroy(struct Process *proc, int was_exec)
/* Breakpoints. */
if (proc->breakpoints != NULL) {
proc_each_breakpoint(proc, NULL, destroy_breakpoint_cb, NULL);
- dict_clear(proc->breakpoints);
+ dict_destroy(proc->breakpoints, NULL, NULL, NULL);
+ free(proc->breakpoints);
proc->breakpoints = NULL;
}
@@ -257,7 +295,7 @@ private_process_destroy(struct Process *proc, int was_exec)
}
void
-process_destroy(struct Process *proc)
+process_destroy(struct process *proc)
{
arch_process_destroy(proc);
os_process_destroy(proc);
@@ -265,7 +303,7 @@ process_destroy(struct Process *proc)
}
int
-process_exec(struct Process *proc)
+process_exec(struct process *proc)
{
/* Call exec handlers first, before we destroy the main
* state. */
@@ -284,11 +322,11 @@ process_exec(struct Process *proc)
return 0;
}
-struct Process *
+struct process *
open_program(const char *filename, pid_t pid)
{
assert(pid != 0);
- struct Process *proc = malloc(sizeof(*proc));
+ struct process *proc = malloc(sizeof(*proc));
if (proc == NULL || process_init(proc, filename, pid) < 0) {
free(proc);
return NULL;
@@ -297,41 +335,36 @@ open_program(const char *filename, pid_t pid)
}
struct clone_single_bp_data {
- struct Process *old_proc;
- struct Process *new_proc;
- int error;
+ struct process *old_proc;
+ struct process *new_proc;
};
-static void
-clone_single_bp(void *key, void *value, void *u)
+static enum callback_status
+clone_single_bp(arch_addr_t *key, struct breakpoint **bpp, void *u)
{
- struct breakpoint *bp = value;
+ struct breakpoint *bp = *bpp;
struct clone_single_bp_data *data = u;
- /* Don't bother if there were errors anyway. */
- if (data->error != 0)
- return;
-
struct breakpoint *clone = malloc(sizeof(*clone));
if (clone == NULL
- || breakpoint_clone(clone, data->new_proc,
- bp, data->old_proc) < 0) {
+ || breakpoint_clone(clone, data->new_proc, bp) < 0) {
fail:
free(clone);
- data->error = -1;
+ return CBS_STOP;
}
if (proc_add_breakpoint(data->new_proc->leader, clone) < 0) {
breakpoint_destroy(clone);
goto fail;
}
+ return CBS_CONT;
}
int
-process_clone(struct Process *retp, struct Process *proc, pid_t pid)
+process_clone(struct process *retp, struct process *proc, pid_t pid)
{
if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
fail1:
- fprintf(stderr, "failed to clone process %d->%d : %s\n",
+ fprintf(stderr, "Failed to clone process %d to %d: %s\n",
proc->pid, pid, strerror(errno));
return -1;
}
@@ -350,8 +383,12 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
struct library **nlibp = &retp->libraries;
for (lib = proc->leader->libraries; lib != NULL; lib = lib->next) {
*nlibp = malloc(sizeof(**nlibp));
+
if (*nlibp == NULL
|| library_clone(*nlibp, lib) < 0) {
+ free(*nlibp);
+ *nlibp = NULL;
+
fail2:
process_bare_destroy(retp, 0);
@@ -373,10 +410,10 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
struct clone_single_bp_data data = {
.old_proc = proc,
.new_proc = retp,
- .error = 0,
};
- dict_apply_to_all(proc->leader->breakpoints, &clone_single_bp, &data);
- if (data.error < 0)
+ if (DICT_EACH(proc->leader->breakpoints,
+ arch_addr_t, struct breakpoint *, NULL,
+ clone_single_bp, &data) != NULL)
goto fail2;
/* And finally the call stack. */
@@ -396,7 +433,7 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
size_t j;
fail3:
for (j = 0; j < i; ++j) {
- nctx = elem->fetch_context;
+ nctx = retp->callstack[j].fetch_context;
fetch_arg_done(nctx);
elem->fetch_context = NULL;
}
@@ -405,14 +442,13 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
elem->fetch_context = nctx;
}
- struct value_dict *args = elem->arguments;
- if (args != NULL) {
+ if (elem->arguments != NULL) {
struct value_dict *nargs = malloc(sizeof(*nargs));
if (nargs == NULL
- || val_dict_clone(nargs, args) < 0) {
+ || val_dict_clone(nargs, elem->arguments) < 0) {
size_t j;
for (j = 0; j < i; ++j) {
- nargs = elem->arguments;
+ nargs = retp->callstack[j].arguments;
val_dict_destroy(nargs);
free(nargs);
elem->arguments = NULL;
@@ -456,20 +492,18 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
static int
open_one_pid(pid_t pid)
{
- Process *proc;
- char *filename;
debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
/* Get the filename first. Should the trace_pid fail, we can
* easily free it, untracing is more work. */
- if ((filename = pid2name(pid)) == NULL
- || trace_pid(pid) < 0) {
+ char *filename = pid2name(pid);
+ if (filename == NULL || trace_pid(pid) < 0) {
fail:
free(filename);
return -1;
}
- proc = open_program(filename, pid);
+ struct process *proc = open_program(filename, pid);
if (proc == NULL)
goto fail;
free(filename);
@@ -479,12 +513,31 @@ open_one_pid(pid_t pid)
}
static enum callback_status
-start_one_pid(Process * proc, void * data)
+start_one_pid(struct process *proc, void *data)
{
continue_process(proc->pid);
return CBS_CONT;
}
+static enum callback_status
+is_main(struct process *proc, struct library *lib, void *data)
+{
+ return CBS_STOP_IF(lib->type == LT_LIBTYPE_MAIN);
+}
+
+void
+process_hit_start(struct process *proc)
+{
+ struct process *leader = proc->leader;
+ assert(leader != NULL);
+
+ struct library *mainlib
+ = proc_each_library(leader, NULL, is_main, NULL);
+ assert(mainlib != NULL);
+ linkmap_init(leader, mainlib->dyn_addr);
+ arch_dynlink_done(leader);
+}
+
void
open_pid(pid_t pid)
{
@@ -495,7 +548,7 @@ open_pid(pid_t pid)
return;
/* First, see if we can attach the requested PID itself. */
- if (open_one_pid(pid)) {
+ if (open_one_pid(pid) < 0) {
fprintf(stderr, "Cannot attach to pid %u: %s\n",
pid, strerror(errno));
trace_fail_warning(pid);
@@ -527,7 +580,7 @@ open_pid(pid_t pid)
have_all = 1;
for (i = 0; i < ntasks; ++i)
if (pid2proc(tasks[i]) == NULL
- && open_one_pid(tasks[i]))
+ && open_one_pid(tasks[i]) < 0)
have_all = 0;
free(tasks);
@@ -537,40 +590,39 @@ open_pid(pid_t pid)
old_ntasks = ntasks;
}
- struct Process *leader = pid2proc(pid)->leader;
+ struct process *leader = pid2proc(pid)->leader;
/* XXX Is there a way to figure out whether _start has
* actually already been hit? */
- arch_dynlink_done(leader);
+ process_hit_start(leader);
/* Done. Continue everyone. */
each_task(leader, NULL, start_one_pid, NULL);
}
static enum callback_status
-find_proc(Process * proc, void * data)
+find_proc(struct process *proc, void *data)
{
- pid_t pid = (pid_t)(uintptr_t)data;
- return proc->pid == pid ? CBS_STOP : CBS_CONT;
+ return CBS_STOP_IF(proc->pid == (pid_t)(uintptr_t)data);
}
-Process *
-pid2proc(pid_t pid) {
+struct process *
+pid2proc(pid_t pid)
+{
return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
}
-static Process * list_of_processes = NULL;
+static struct process *list_of_processes = NULL;
static void
-unlist_process(Process * proc)
+unlist_process(struct process *proc)
{
- Process *tmp;
-
if (list_of_processes == proc) {
list_of_processes = list_of_processes->next;
return;
}
+ struct process *tmp;
for (tmp = list_of_processes; ; tmp = tmp->next) {
/* If the following assert fails, the process wasn't
* in the list. */
@@ -583,17 +635,17 @@ unlist_process(Process * proc)
}
}
-struct Process *
-each_process(struct Process *start_after,
- enum callback_status(*cb)(struct Process *proc, void *data),
+struct process *
+each_process(struct process *start_after,
+ enum callback_status(*cb)(struct process *proc, void *data),
void *data)
{
- struct Process *it = start_after == NULL ? list_of_processes
+ struct process *it = start_after == NULL ? list_of_processes
: start_after->next;
while (it != NULL) {
/* Callback might call remove_process. */
- struct Process *next = it->next;
+ struct process *next = it->next;
switch ((*cb)(it, data)) {
case CBS_FAIL:
/* XXX handle me */
@@ -607,20 +659,20 @@ each_process(struct Process *start_after,
return NULL;
}
-Process *
-each_task(struct Process *proc, struct Process *start_after,
- enum callback_status(*cb)(struct Process *proc, void *data),
+struct process *
+each_task(struct process *proc, struct process *start_after,
+ enum callback_status(*cb)(struct process *proc, void *data),
void *data)
{
assert(proc != NULL);
- struct Process *it = start_after == NULL ? proc->leader
+ struct process *it = start_after == NULL ? proc->leader
: start_after->next;
if (it != NULL) {
- struct Process *leader = it->leader;
+ struct process *leader = it->leader;
while (it != NULL && it->leader == leader) {
/* Callback might call remove_process. */
- struct Process *next = it->next;
+ struct process *next = it->next;
switch ((*cb)(it, data)) {
case CBS_FAIL:
/* XXX handle me */
@@ -635,20 +687,20 @@ each_task(struct Process *proc, struct Process *start_after,
return NULL;
}
-static void
-add_process(struct Process *proc, int was_exec)
+static int
+add_process(struct process *proc, int was_exec)
{
- Process ** leaderp = &list_of_processes;
+ struct process **leaderp = &list_of_processes;
if (proc->pid) {
pid_t tgid = process_leader(proc->pid);
if (tgid == 0)
/* Must have been terminated before we managed
* to fully attach. */
- return;
- if (tgid == proc->pid)
+ return -1;
+ if (tgid == proc->pid) {
proc->leader = proc;
- else {
- Process * leader = pid2proc(tgid);
+ } else {
+ struct process *leader = pid2proc(tgid);
proc->leader = leader;
if (leader != NULL)
leaderp = &leader->next;
@@ -659,12 +711,13 @@ add_process(struct Process *proc, int was_exec)
proc->next = *leaderp;
*leaderp = proc;
}
+ return 0;
}
void
-change_process_leader(Process * proc, Process * leader)
+change_process_leader(struct process *proc, struct process *leader)
{
- Process ** leaderp = &list_of_processes;
+ struct process **leaderp = &list_of_processes;
if (proc->leader == leader)
return;
@@ -679,7 +732,7 @@ change_process_leader(Process * proc, Process * leader)
}
static enum callback_status
-clear_leader(struct Process *proc, void *data)
+clear_leader(struct process *proc, void *data)
{
debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
proc->pid, proc->leader->pid);
@@ -688,7 +741,7 @@ clear_leader(struct Process *proc, void *data)
}
void
-remove_process(Process *proc)
+remove_process(struct process *proc)
{
debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
@@ -702,7 +755,7 @@ remove_process(Process *proc)
}
void
-install_event_handler(Process *proc, struct event_handler *handler)
+install_event_handler(struct process *proc, struct event_handler *handler)
{
debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler);
assert(proc->event_handler == NULL);
@@ -710,7 +763,7 @@ install_event_handler(Process *proc, struct event_handler *handler)
}
void
-destroy_event_handler(Process * proc)
+destroy_event_handler(struct process *proc)
{
struct event_handler *handler = proc->event_handler;
debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler);
@@ -722,7 +775,7 @@ destroy_event_handler(Process * proc)
}
static int
-breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
+breakpoint_for_symbol(struct library_symbol *libsym, struct process *proc)
{
arch_addr_t bp_addr;
assert(proc->leader == proc);
@@ -749,9 +802,8 @@ breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
* be also custom-allocated, and we would really need to swap
* the two: delete the one now in the dictionary, swap values
* around, and put the new breakpoint back in. */
- struct breakpoint *bp = dict_find_entry(proc->breakpoints,
- bp_addr);
- if (bp != NULL) {
+ struct breakpoint *bp;
+ if (DICT_FIND_VAL(proc->breakpoints, &bp_addr, &bp) == 0) {
/* MIPS backend makes duplicate requests. This is
* likely a bug in the backend. Currently there's no
* point assigning more than one symbol to a
@@ -795,11 +847,11 @@ breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
static enum callback_status
cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
{
- return breakpoint_for_symbol(libsym, data) < 0 ? CBS_FAIL : CBS_CONT;
+ return CBS_STOP_IF(breakpoint_for_symbol(libsym, data) < 0);
}
static int
-proc_activate_latent_symbol(struct Process *proc,
+proc_activate_latent_symbol(struct process *proc,
struct library_symbol *libsym)
{
assert(libsym->latent);
@@ -809,7 +861,7 @@ proc_activate_latent_symbol(struct Process *proc,
}
int
-proc_activate_delayed_symbol(struct Process *proc,
+proc_activate_delayed_symbol(struct process *proc,
struct library_symbol *libsym)
{
assert(libsym->delayed);
@@ -818,25 +870,48 @@ proc_activate_delayed_symbol(struct Process *proc,
return breakpoint_for_symbol(libsym, proc);
}
+
+struct activate_latent_in_context
+{
+ struct process *proc;
+ struct library_exported_names *exported_names;
+};
static enum callback_status
-activate_latent_in(struct Process *proc, struct library *lib, void *data)
+activate_latent_in_cb(struct library_symbol *libsym, void *data)
{
- struct library_exported_name *exported;
- for (exported = data; exported != NULL; exported = exported->next) {
- struct library_symbol *libsym = NULL;
- while ((libsym = library_each_symbol(lib, libsym,
- library_symbol_named_cb,
- (void *)exported->name))
- != NULL)
- if (libsym->latent
- && proc_activate_latent_symbol(proc, libsym) < 0)
- return CBS_FAIL;
- }
+ struct activate_latent_in_context *ctx =
+ (struct activate_latent_in_context*)data;
+
+ if (libsym->latent &&
+ library_exported_names_contains(ctx->exported_names,
+ libsym->name) != 0)
+ proc_activate_latent_symbol(ctx->proc, libsym);
+
+ return CBS_CONT;
+}
+
+static enum callback_status
+activate_latent_in(struct process *proc, struct library *lib, void *data)
+{
+ struct library_symbol *libsym = NULL;
+
+ struct library_exported_names *exported_names =
+ (struct library_exported_names*)data;
+
+ struct activate_latent_in_context ctx =
+ {.proc = proc,
+ .exported_names = exported_names};
+
+ if (library_each_symbol(lib, libsym,
+ activate_latent_in_cb,
+ &ctx) != NULL)
+ return CBS_FAIL;
+
return CBS_CONT;
}
void
-proc_add_library(struct Process *proc, struct library *lib)
+proc_add_library(struct process *proc, struct library *lib)
{
assert(lib->next == NULL);
lib->next = proc->libraries;
@@ -844,27 +919,94 @@ proc_add_library(struct Process *proc, struct library *lib)
debug(DEBUG_PROCESS, "added library %s@%p (%s) to %d",
lib->soname, lib->base, lib->pathname, proc->pid);
+#if defined(HAVE_LIBDW)
+ Dwfl *dwfl = NULL;
+ Dwfl_Module *dwfl_module = NULL;
+
+ /* Setup module tracking for libdwfl unwinding. */
+ struct process *leader = proc->leader;
+ dwfl = leader->dwfl;
+ if (dwfl == NULL) {
+ static const Dwfl_Callbacks proc_callbacks = {
+ .find_elf = dwfl_linux_proc_find_elf,
+ .find_debuginfo = dwfl_standard_find_debuginfo
+ };
+ dwfl = dwfl_begin(&proc_callbacks);
+ if (dwfl == NULL)
+ fprintf(stderr,
+ "Couldn't initialize libdwfl unwinding "
+ "for process %d: %s\n", leader->pid,
+ dwfl_errmsg (-1));
+ }
+
+ if (dwfl != NULL) {
+ dwfl_report_begin_add(dwfl);
+ dwfl_module =
+ dwfl_report_elf(dwfl, lib->soname,
+ lib->pathname, -1,
+ (GElf_Addr) lib->base,
+ false);
+ if (dwfl_module == NULL)
+ fprintf(stderr,
+ "dwfl_report_elf %s@%p (%s) %d: %s\n",
+ lib->soname, lib->base, lib->pathname,
+ proc->pid, dwfl_errmsg (-1));
+
+ dwfl_report_end(dwfl, NULL, NULL);
+
+ if (options.bt_depth > 0) {
+ if (proc->should_attach_dwfl) {
+ int r = dwfl_linux_proc_attach(dwfl,
+ leader->pid,
+ true);
+ proc->should_attach_dwfl = 0;
+ if (r != 0) {
+ const char *msg;
+ dwfl_end(dwfl);
+ if (r < 0)
+ msg = dwfl_errmsg(-1);
+ else
+ msg = strerror(r);
+ fprintf(stderr, "Couldn't initialize "
+ "libdwfl (unwinding, prototype "
+ "import) for process %d: %s\n",
+ leader->pid, msg);
+ }
+ }
+ }
+ }
+
+ lib->dwfl_module = dwfl_module;
+ leader->dwfl = dwfl;
+
+#endif /* defined(HAVE_LIBDW) */
+
/* Insert breakpoints for all active (non-latent) symbols. */
struct library_symbol *libsym = NULL;
while ((libsym = library_each_symbol(lib, libsym,
cb_breakpoint_for_symbol,
proc)) != NULL)
- fprintf(stderr, "Couldn't insert breakpoint for %s to %d: %s.",
- libsym->name, proc->pid, strerror(errno));
-
- /* Look through export list of the new library and compare it
- * with latent symbols of all libraries (including this
- * library itself). */
- struct library *lib2 = NULL;
- while ((lib2 = proc_each_library(proc, lib2, activate_latent_in,
- lib->exported_names)) != NULL)
fprintf(stderr,
- "Couldn't activate latent symbols for %s in %d: %s.",
+ "Couldn't insert breakpoint for %s to %d: %s.\n",
libsym->name, proc->pid, strerror(errno));
+
+ if (lib->should_activate_latent != 0) {
+ /* Look through export list of the new library and compare it
+ * with latent symbols of all libraries (including this
+ * library itself). */
+ struct library *lib2 = NULL;
+
+ while ((lib2 = proc_each_library(proc, lib2, activate_latent_in,
+ &lib->exported_names)) != NULL)
+ fprintf(stderr,
+ "Couldn't activate latent symbols "
+ "for %s in %d: %s.\n",
+ lib2->soname, proc->pid, strerror(errno));
+ }
}
int
-proc_remove_library(struct Process *proc, struct library *lib)
+proc_remove_library(struct process *proc, struct library *lib)
{
struct library **libp;
for (libp = &proc->libraries; *libp != NULL; libp = &(*libp)->next)
@@ -876,13 +1018,15 @@ proc_remove_library(struct Process *proc, struct library *lib)
}
struct library *
-proc_each_library(struct Process *proc, struct library *it,
- enum callback_status (*cb)(struct Process *proc,
+proc_each_library(struct process *proc, struct library *it,
+ enum callback_status (*cb)(struct process *proc,
struct library *lib, void *data),
void *data)
{
if (it == NULL)
it = proc->libraries;
+ else
+ it = it->next;
while (it != NULL) {
struct library *next = it->next;
@@ -903,7 +1047,7 @@ proc_each_library(struct Process *proc, struct library *it,
}
static void
-check_leader(struct Process *proc)
+check_leader(struct process *proc)
{
/* Only the group leader should be getting the breakpoints and
* thus have ->breakpoint initialized. */
@@ -913,7 +1057,7 @@ check_leader(struct Process *proc)
}
int
-proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
+proc_add_breakpoint(struct process *proc, struct breakpoint *bp)
{
debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)",
proc->pid, breakpoint_name(bp), bp->addr);
@@ -922,9 +1066,9 @@ proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
/* XXX We might merge bp->libsym instead of the following
* assert, but that's not necessary right now. Read the
* comment in breakpoint_for_symbol. */
- assert(dict_find_entry(proc->breakpoints, bp->addr) == NULL);
+ assert(dict_find(proc->breakpoints, &bp->addr) == NULL);
- if (dict_enter(proc->breakpoints, bp->addr, bp) < 0) {
+ if (DICT_INSERT(proc->breakpoints, &bp->addr, &bp) < 0) {
fprintf(stderr,
"couldn't enter breakpoint %s@%p to dictionary: %s\n",
breakpoint_name(bp), bp->addr, strerror(errno));
@@ -935,67 +1079,50 @@ proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
}
void
-proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp)
+proc_remove_breakpoint(struct process *proc, struct breakpoint *bp)
{
debug(DEBUG_FUNCTION, "proc_remove_breakpoint(pid=%d, %s@%p)",
proc->pid, breakpoint_name(bp), bp->addr);
check_leader(proc);
- struct breakpoint *removed = dict_remove(proc->breakpoints, bp->addr);
- assert(removed == bp);
+ int rc = DICT_ERASE(proc->breakpoints, &bp->addr, struct breakpoint *,
+ NULL, NULL, NULL);
+ assert(rc == 0);
}
-/* Dict doesn't support iteration restarts, so here's this contraption
- * for now. XXX add restarts to dict. */
struct each_breakpoint_data
{
- void *start;
- void *end;
- struct Process *proc;
- enum callback_status (*cb)(struct Process *proc,
+ struct process *proc;
+ enum callback_status (*cb)(struct process *proc,
struct breakpoint *bp,
void *data);
void *cb_data;
};
-static void
-each_breakpoint_cb(void *key, void *value, void *d)
+static enum callback_status
+each_breakpoint_cb(arch_addr_t *key, struct breakpoint **bpp, void *d)
{
struct each_breakpoint_data *data = d;
- if (data->end != NULL)
- return;
- if (data->start == key)
- data->start = NULL;
-
- if (data->start == NULL) {
- switch (data->cb(data->proc, value, data->cb_data)) {
- case CBS_FAIL:
- /* XXX handle me */
- case CBS_STOP:
- data->end = key;
- case CBS_CONT:
- return;
- }
- }
+ return data->cb(data->proc, *bpp, data->cb_data);
}
-void *
-proc_each_breakpoint(struct Process *proc, void *start,
- enum callback_status (*cb)(struct Process *proc,
+arch_addr_t *
+proc_each_breakpoint(struct process *proc, arch_addr_t *start,
+ enum callback_status (*cb)(struct process *proc,
struct breakpoint *bp,
void *data), void *data)
{
struct each_breakpoint_data dd = {
- .start = start,
.proc = proc,
.cb = cb,
.cb_data = data,
};
- dict_apply_to_all(proc->breakpoints, &each_breakpoint_cb, &dd);
- return dd.end;
+ return DICT_EACH(proc->breakpoints,
+ arch_addr_t, struct breakpoint *, start,
+ &each_breakpoint_cb, &dd);
}
int
-proc_find_symbol(struct Process *proc, struct library_symbol *sym,
+proc_find_symbol(struct process *proc, struct library_symbol *sym,
struct library **retlib, struct library_symbol **retsym)
{
struct library *lib = sym->lib;
@@ -1021,7 +1148,7 @@ proc_find_symbol(struct Process *proc, struct library_symbol *sym,
}
struct library_symbol *
-proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
+proc_each_symbol(struct process *proc, struct library_symbol *start_after,
enum callback_status (*cb)(struct library_symbol *, void *),
void *data)
{
@@ -1035,3 +1162,26 @@ proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
return NULL;
}
+
+#define DEF_READER(NAME, SIZE) \
+ int \
+ NAME(struct process *proc, arch_addr_t addr, \
+ uint##SIZE##_t *lp) \
+ { \
+ union { \
+ uint##SIZE##_t dst; \
+ char buf[0]; \
+ } u; \
+ if (umovebytes(proc, addr, &u.buf, sizeof(u.dst)) \
+ != sizeof(u.dst)) \
+ return -1; \
+ *lp = u.dst; \
+ return 0; \
+ }
+
+DEF_READER(proc_read_8, 8)
+DEF_READER(proc_read_16, 16)
+DEF_READER(proc_read_32, 32)
+DEF_READER(proc_read_64, 64)
+
+#undef DEF_READER