2 * This file is based on a patch submitted by Mark Wielaard <mjw@redhat.com>
4 * https://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=dfefa9f057857735a073ea655f5cb34351032c8e
6 * It was re-licensed for strace by the original author:
7 * https://lists.strace.io/pipermail/strace-devel/2018-March/008063.html
9 * Copyright (c) 2014-2018 Mark Wielaard <mjw@redhat.com>
10 * Copyright (c) 2018 Masatake YAMATO <yamato@redhat.com>
11 * Copyright (c) 2018 The strace developers.
12 * All rights reserved.
14 * SPDX-License-Identifier: LGPL-2.1-or-later
19 #include "mmap_notify.h"
20 #include <elfutils/libdwfl.h>
24 unsigned int last_proc_updating;
27 static unsigned int mapping_generation;
30 update_mapping_generation(struct tcb *tcp, void *unused)
38 mmap_notify_register_client(update_mapping_generation, NULL);
42 tcb_init(struct tcb *tcp)
44 static const Dwfl_Callbacks proc_callbacks = {
45 .find_elf = dwfl_linux_proc_find_elf,
46 .find_debuginfo = dwfl_standard_find_debuginfo
49 Dwfl *dwfl = dwfl_begin(&proc_callbacks);
51 error_msg("dwfl_begin: %s", dwfl_errmsg(-1));
55 int r = dwfl_linux_proc_attach(dwfl, tcp->pid, true);
57 const char *msg = NULL;
60 msg = dwfl_errmsg(-1);
64 error_msg("dwfl_linux_proc_attach returned an error"
65 " for process %d: %s", tcp->pid, msg);
70 struct ctx *ctx = xmalloc(sizeof(*ctx));
72 ctx->last_proc_updating = 0;
77 tcb_fin(struct tcb *tcp)
79 struct ctx *ctx = tcp->unwind_ctx;
87 flush_cache_maybe(struct tcb *tcp)
89 struct ctx *ctx = tcp->unwind_ctx;
93 if (ctx->last_proc_updating == mapping_generation)
96 int r = dwfl_linux_proc_report(ctx->dwfl, tcp->pid);
99 error_msg("dwfl_linux_proc_report returned an error"
100 " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
102 error_msg("dwfl_linux_proc_report returned an error"
103 " for pid %d", tcp->pid);
104 else if (dwfl_report_end(ctx->dwfl, NULL, NULL) != 0)
105 error_msg("dwfl_report_end returned an error"
106 " for pid %d: %s", tcp->pid, dwfl_errmsg(-1));
108 ctx->last_proc_updating = mapping_generation;
111 struct frame_user_data {
112 unwind_call_action_fn call_action;
113 unwind_error_action_fn error_action;
119 frame_callback(Dwfl_Frame *state, void *arg)
121 struct frame_user_data *user_data = arg;
125 if (!dwfl_frame_pc(state, &pc, &isactivation)) {
126 /* Propagate the error to the caller. */
133 Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
134 Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
138 const char *modname = NULL;
139 const char *symname = NULL;
141 Dwarf_Addr true_offset = pc;
143 modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
145 symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
147 dwfl_module_relocate_address(mod, &true_offset);
148 user_data->call_action(user_data->data, modname, symname,
151 /* Max number of frames to print reached? */
152 if (user_data->stack_depth-- == 0)
153 return DWARF_CB_ABORT;
159 tcb_walk(struct tcb *tcp,
160 unwind_call_action_fn call_action,
161 unwind_error_action_fn error_action,
164 struct ctx *ctx = tcp->unwind_ctx;
168 struct frame_user_data user_data = {
169 .call_action = call_action,
170 .error_action = error_action,
175 flush_cache_maybe(tcp);
177 int r = dwfl_getthread_frames(ctx->dwfl, tcp->pid, frame_callback,
181 r < 0 ? dwfl_errmsg(-1) : "too many stack frames",
185 const struct unwind_unwinder_t unwinder = {
188 .tcb_init = tcb_init,
190 .tcb_walk = tcb_walk,