[ltrace: 1/2] Add upstream patches for initial breakpoint insertion
Petr Machata
pmachata at fedoraproject.org
Wed Feb 8 15:46:06 UTC 2012
commit 6e5a20e2b8b7045cafef5a2752f3b1a87d47525a
Author: Petr Machata <pmachata at redhat.com>
Date: Wed Feb 8 00:18:26 2012 +0100
Add upstream patches for initial breakpoint insertion
ltrace-0.6.0-process-start.patch | 1053 ++++++++++++++++++++++++++++++++++++++
ltrace.spec | 9 +-
2 files changed, 1061 insertions(+), 1 deletions(-)
---
diff --git a/ltrace-0.6.0-process-start.patch b/ltrace-0.6.0-process-start.patch
new file mode 100644
index 0000000..1a95e25
--- /dev/null
+++ b/ltrace-0.6.0-process-start.patch
@@ -0,0 +1,1053 @@
+diff --git a/breakpoint.h b/breakpoint.h
+new file mode 100644
+index 0000000..ce6f501
+--- /dev/null
++++ b/breakpoint.h
+@@ -0,0 +1,106 @@
++/*
++ * This file is part of ltrace.
++ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2009 Juan Cespedes
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef BREAKPOINT_H
++#define BREAKPOINT_H
++
++/* XXX This is currently a very weak abstraction. We would like to
++ * much expand this to allow things like breakpoints on SDT probes and
++ * such.
++ *
++ * In particular, we would like to add a tracepoint abstraction.
++ * Tracepoint is a traceable feature--e.g. an exact address, a DWARF
++ * symbol, an ELF symbol, a PLT entry, or an SDT probe. Tracepoints
++ * are named and the user can configure which of them he wants to
++ * enable. Realized tracepoints enable breakpoints, which are a
++ * low-level realization of high-level tracepoint.
++ *
++ * Tracepoints are provided by the main binary as well as by any
++ * opened libraries: every time an ELF file is mapped into the address
++ * space, a new set of tracepoints is extracted, and filtered
++ * according to user settings. Those tracepoints that are left are
++ * then realized, and the tracing starts.
++ *
++ * A scheme like this would take care of gradually introducing
++ * breakpoints when the library is mapped, and therefore ready, and
++ * would avoid certain hacks. For example on PPC64, we don't actually
++ * add breakpoints to PLT. Instead, we read the PLT (which contains
++ * addresses, not code), to figure out where to put the breakpoints.
++ * In prelinked code, that address is non-zero, and points to an
++ * address that's not yet mapped. ptrace then fails when we try to
++ * add the breakpoint.
++ *
++ * Ideally, return breakpoints would be just a special kind of
++ * tracepoint that has attached some magic. Or a feature of a
++ * tracepoint. Service breakpoints like the handling of dlopen would
++ * be a low-level breakpoint, likely without tracepoint attached.
++ *
++ * So that's for sometimes.
++ */
++
++#include "arch.h"
++
++struct Process;
++struct breakpoint;
++
++struct bp_callbacks {
++ void (*on_hit) (struct breakpoint *bp, struct Process *proc);
++ void (*on_destroy) (struct breakpoint *bp);
++};
++
++struct breakpoint {
++ struct bp_callbacks *cbs;
++ void *addr;
++ unsigned char orig_value[BREAKPOINT_LENGTH];
++ int enabled;
++ struct library_symbol *libsym;
++#ifdef __arm__
++ int thumb_mode;
++#endif
++};
++
++/* Call on-hit handler of BP, if any is set. */
++void breakpoint_on_hit(struct breakpoint *bp, struct Process *proc);
++
++/* Call on-destroy handler of BP, if any is set. */
++void breakpoint_on_destroy(struct breakpoint *bp);
++
++/* This is actually three functions rolled in one:
++ * - breakpoint_init
++ * - proc_insert_breakpoint
++ * - breakpoint_enable
++ * XXX I think it should be broken up somehow. */
++struct breakpoint *insert_breakpoint(struct Process *proc, void *addr,
++ struct library_symbol *libsym, int enable);
++
++/* */
++void delete_breakpoint(struct Process *proc, void *addr);
++
++/* XXX some of the following belongs to proc.h/proc.c. */
++struct breakpoint *address2bpstruct(struct Process *proc, void *addr);
++void enable_all_breakpoints(struct Process *proc);
++void disable_all_breakpoints(struct Process *proc);
++int breakpoints_init(struct Process *proc, int enable);
++
++void reinitialize_breakpoints(struct Process *proc);
++
++
++#endif /* BREAKPOINT_H */
+diff --git a/breakpoints.c b/breakpoints.c
+index 387b2a5..5713fe4 100644
+--- a/breakpoints.c
++++ b/breakpoints.c
+@@ -8,12 +8,30 @@
+ #include <sys/ptrace.h>
+ #endif
+
++#include "breakpoint.h"
+ #include "common.h"
+
++void
++breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
++{
++ assert(bp != NULL);
++ if (bp->cbs != NULL && bp->cbs->on_hit != NULL)
++ (bp->cbs->on_hit) (bp, proc);
++}
++
++void
++breakpoint_on_destroy(struct breakpoint *bp)
++{
++ assert(bp != NULL);
++ if (bp->cbs != NULL && bp->cbs->on_destroy != NULL)
++ (bp->cbs->on_destroy) (bp);
++}
++
+ /*****************************************************************************/
+
+-Breakpoint *
+-address2bpstruct(Process *proc, void *addr) {
++struct breakpoint *
++address2bpstruct(Process *proc, void *addr)
++{
+ assert(proc != NULL);
+ assert(proc->breakpoints != NULL);
+ assert(proc->leader == proc);
+@@ -21,10 +39,11 @@ address2bpstruct(Process *proc, void *addr) {
+ return dict_find_entry(proc->breakpoints, addr);
+ }
+
+-void
++struct breakpoint *
+ insert_breakpoint(Process *proc, void *addr,
+- struct library_symbol *libsym, int enable) {
+- Breakpoint *sbp;
++ struct library_symbol *libsym, int enable)
++{
++ struct breakpoint *sbp;
+
+ Process * leader = proc->leader;
+
+@@ -43,16 +62,16 @@ insert_breakpoint(Process *proc, void *addr,
+ debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr);
+
+ if (!addr)
+- return;
++ return NULL;
+
+ if (libsym)
+ libsym->needs_init = 0;
+
+ sbp = dict_find_entry(leader->breakpoints, addr);
+- if (!sbp) {
+- sbp = calloc(1, sizeof(Breakpoint));
+- if (!sbp) {
+- return; /* TODO FIXME XXX: error_mem */
++ if (sbp == NULL) {
++ sbp = calloc(1, sizeof(*sbp));
++ if (sbp == NULL) {
++ return NULL; /* TODO FIXME XXX: error_mem */
+ }
+ dict_enter(leader->breakpoints, addr, sbp);
+ sbp->addr = addr;
+@@ -67,11 +86,14 @@ insert_breakpoint(Process *proc, void *addr,
+ assert(proc->pid != 0);
+ enable_breakpoint(proc, sbp);
+ }
++
++ return sbp;
+ }
+
+ void
+-delete_breakpoint(Process *proc, void *addr) {
+- Breakpoint *sbp;
++delete_breakpoint(Process *proc, void *addr)
++{
++ struct breakpoint *sbp;
+
+ debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);
+
+@@ -91,89 +113,67 @@ delete_breakpoint(Process *proc, void *addr) {
+ }
+
+ static void
+-enable_bp_cb(void *addr, void *sbp, void *proc) {
++enable_bp_cb(void *addr, void *sbp, void *proc)
++{
+ debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid);
+- if (((Breakpoint *)sbp)->enabled) {
++ if (((struct breakpoint *)sbp)->enabled)
+ enable_breakpoint(proc, sbp);
+- }
+ }
+
+ void
+-enable_all_breakpoints(Process *proc) {
++enable_all_breakpoints(Process *proc)
++{
+ debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
+- if (proc->breakpoints_enabled <= 0) {
+-#ifdef __powerpc__
+- unsigned long a;
+
++ debug(1, "Enabling breakpoints for pid %u...", proc->pid);
++ if (proc->breakpoints) {
++ dict_apply_to_all(proc->breakpoints, enable_bp_cb,
++ proc);
++ }
++#ifdef __mips__
++ {
+ /*
+- * PPC HACK! (XXX FIXME TODO)
+- * If the dynamic linker hasn't populated the PLT then
+- * dont enable the breakpoints
++ * I'm sure there is a nicer way to do this. We need to
++ * insert breakpoints _after_ the child has been started.
+ */
+- if (options.libcalls) {
+- a = ptrace(PTRACE_PEEKTEXT, proc->pid,
+- sym2addr(proc, proc->list_of_symbols),
+- 0);
+- if (a == 0x0)
+- return;
+- }
+-#endif
+-
+- debug(1, "Enabling breakpoints for pid %u...", proc->pid);
+- if (proc->breakpoints) {
+- dict_apply_to_all(proc->breakpoints, enable_bp_cb,
+- proc);
+- }
+-#ifdef __mips__
+- {
+- /*
+- * I'm sure there is a nicer way to do this. We need to
+- * insert breakpoints _after_ the child has been started.
+- */
+- struct library_symbol *sym;
+- struct library_symbol *new_sym;
+- sym=proc->list_of_symbols;
+- while(sym){
+- void *addr= sym2addr(proc,sym);
+- if(!addr){
+- sym=sym->next;
+- continue;
+- }
+- if(dict_find_entry(proc->breakpoints,addr)){
+- sym=sym->next;
+- continue;
+- }
+- debug(2,"inserting bp %p %s",addr,sym->name);
+- new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
+- memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
+- new_sym->next=proc->list_of_symbols;
+- proc->list_of_symbols=new_sym;
+- insert_breakpoint(proc, addr, new_sym);
++ struct library_symbol *sym;
++ struct library_symbol *new_sym;
++ sym=proc->list_of_symbols;
++ while(sym){
++ void *addr= sym2addr(proc,sym);
++ if(!addr){
+ sym=sym->next;
++ continue;
+ }
++ if(dict_find_entry(proc->breakpoints,addr)){
++ sym=sym->next;
++ continue;
++ }
++ debug(2,"inserting bp %p %s",addr,sym->name);
++ new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
++ memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
++ new_sym->next=proc->list_of_symbols;
++ proc->list_of_symbols=new_sym;
++ insert_breakpoint(proc, addr, new_sym);
++ sym=sym->next;
+ }
+-#endif
+ }
+- proc->breakpoints_enabled = 1;
++#endif
+ }
+
+ static void
+-disable_bp_cb(void *addr, void *sbp, void *proc) {
++disable_bp_cb(void *addr, void *sbp, void *proc)
++{
+ debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid);
+- if (((Breakpoint *)sbp)->enabled) {
++ if (((struct breakpoint *)sbp)->enabled)
+ disable_breakpoint(proc, sbp);
+- }
+ }
+
+ void
+ disable_all_breakpoints(Process *proc) {
+ debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid);
+ assert(proc->leader == proc);
+- if (proc->breakpoints_enabled) {
+- debug(1, "Disabling breakpoints for pid %u...", proc->pid);
+- dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
+- }
+- proc->breakpoints_enabled = 0;
++ dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
+ }
+
+ static void
+@@ -183,11 +183,18 @@ free_bp_cb(void *addr, void *sbp, void *data) {
+ free(sbp);
+ }
+
++static void
++entry_callback_hit(struct breakpoint *bp, struct Process *proc)
++{
++ if (proc == NULL || proc->leader == NULL)
++ return;
++ delete_breakpoint(proc, bp->addr); // xxx
++ reinitialize_breakpoints(proc->leader);
++}
++
+ int
+ breakpoints_init(Process *proc, int enable)
+ {
+- struct library_symbol *sym;
+-
+ debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
+ if (proc->breakpoints) { /* let's remove that struct */
+ dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
+@@ -206,9 +213,11 @@ breakpoints_init(Process *proc, int enable)
+ destroy_library_symbol_chain(proc->list_of_symbols);
+ proc->list_of_symbols = NULL;
+
++ GElf_Addr entry;
+ if (options.libcalls && proc->filename) {
+- proc->list_of_symbols = read_elf(proc);
++ proc->list_of_symbols = read_elf(proc, &entry);
+ if (proc->list_of_symbols == NULL) {
++ fail:
+ /* XXX leak breakpoints */
+ return -1;
+ }
+@@ -235,11 +244,19 @@ breakpoints_init(Process *proc, int enable)
+ }
+ }
+
+- for (sym = proc->list_of_symbols; sym; sym = sym->next)
+- insert_breakpoint(proc, sym2addr(proc, sym), sym, enable);
++ struct breakpoint *entry_bp
++ = insert_breakpoint(proc, (void *)(uintptr_t)entry, NULL, 1);
++ if (entry_bp == NULL) {
++ fprintf(stderr, "fail!\n");
++ goto fail;
++ }
++
++ static struct bp_callbacks entry_callbacks = {
++ .on_hit = entry_callback_hit,
++ };
++ entry_bp->cbs = &entry_callbacks;
+
+ proc->callstack_depth = 0;
+- proc->breakpoints_enabled = -1;
+ return 0;
+ }
+
+diff --git a/common.h b/common.h
+index 715898d..a47cd89 100644
+--- a/common.h
++++ b/common.h
+@@ -26,17 +26,6 @@ extern char * command;
+
+ extern int exiting; /* =1 if we have to exit ASAP */
+
+-typedef struct Breakpoint Breakpoint;
+-struct Breakpoint {
+- void * addr;
+- unsigned char orig_value[BREAKPOINT_LENGTH];
+- int enabled;
+- struct library_symbol * libsym;
+-#ifdef __arm__
+- int thumb_mode;
+-#endif
+-};
+-
+ enum arg_type {
+ ARGTYPE_UNKNOWN = -1,
+ ARGTYPE_VOID,
+@@ -187,11 +176,10 @@ struct Process {
+ pid_t pid;
+
+ /* Dictionary of breakpoints (which is a mapping
+- * address->Breakpoint). This is NULL for non-leader
++ * address->breakpoint). This is NULL for non-leader
+ * processes. */
+ Dict * breakpoints;
+
+- int breakpoints_enabled; /* -1:not enabled yet, 0:disabled, 1:enabled */
+ int mask_32bit; /* 1 if 64-bit ltrace is tracing 32-bit process */
+ unsigned int personality;
+ int tracesysgood; /* signal indicating a PTRACE_SYSCALL trap */
+@@ -296,14 +284,7 @@ extern void destroy_event_handler(Process * proc);
+
+ extern pid_t execute_program(const char * command, char ** argv);
+ extern int display_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info);
+-extern Breakpoint * address2bpstruct(Process * proc, void * addr);
+-extern int breakpoints_init(Process * proc, int enable);
+-extern void insert_breakpoint(Process * proc, void * addr,
+- struct library_symbol * libsym, int enable);
+-extern void delete_breakpoint(Process * proc, void * addr);
+-extern void enable_all_breakpoints(Process * proc);
+ extern void disable_all_breakpoints(Process * proc);
+-extern void reinitialize_breakpoints(Process *);
+
+ extern Process * open_program(char * filename, pid_t pid, int init_breakpoints);
+ extern void open_pid(pid_t pid);
+@@ -322,6 +303,8 @@ extern struct library_symbol * clone_library_symbol(struct library_symbol * s);
+ extern void destroy_library_symbol(struct library_symbol * s);
+ extern void destroy_library_symbol_chain(struct library_symbol * chain);
+
++struct breakpoint;
++
+ /* Arch-dependent stuff: */
+ extern char * pid2name(pid_t pid);
+ extern pid_t process_leader(pid_t pid);
+@@ -329,6 +312,7 @@ extern int process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n);
+ extern int process_stopped(pid_t pid);
+ extern enum process_status process_status(pid_t pid);
+ extern void trace_set_options(Process * proc, pid_t pid);
++extern void wait_for_proc(pid_t pid);
+ extern void trace_me(void);
+ extern int trace_pid(pid_t pid);
+ extern void untrace_pid(pid_t pid);
+@@ -338,13 +322,13 @@ extern void set_instruction_pointer(Process * proc, void * addr);
+ extern void * get_stack_pointer(Process * proc);
+ extern void * get_return_addr(Process * proc, void * stack_pointer);
+ extern void set_return_addr(Process * proc, void * addr);
+-extern void enable_breakpoint(Process * proc, Breakpoint * sbp);
+-extern void disable_breakpoint(Process * proc, Breakpoint * sbp);
++extern void enable_breakpoint(Process * proc, struct breakpoint *sbp);
++extern void disable_breakpoint(Process * proc, struct breakpoint *sbp);
+ extern int syscall_p(Process * proc, int status, int * sysnum);
+ extern void continue_process(pid_t pid);
+ extern void continue_after_signal(pid_t pid, int signum);
+ extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
+-extern void continue_after_breakpoint(Process * proc, Breakpoint * sbp);
++extern void continue_after_breakpoint(Process * proc, struct breakpoint *sbp);
+ extern void continue_after_vfork(Process * proc);
+ extern void ltrace_exiting(void);
+ extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info);
+diff --git a/execute_program.c b/execute_program.c
+index 47f514d..859f32c 100644
+--- a/execute_program.c
++++ b/execute_program.c
+@@ -89,6 +89,8 @@ execute_program(const char * command, char **argv)
+ _exit(1);
+ }
+
++ wait_for_proc(pid);
++
+ debug(1, "PID=%d", pid);
+
+ return pid;
+diff --git a/handle_event.c b/handle_event.c
+index 203459c..c146eb9 100644
+--- a/handle_event.c
++++ b/handle_event.c
+@@ -1,6 +1,6 @@
++#define _GNU_SOURCE
+ #include "config.h"
+
+-#define _GNU_SOURCE
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -9,12 +9,13 @@
+ #include <sys/time.h>
+ #include <errno.h>
+
+-#include "common.h"
+-
+ #ifdef __powerpc__
+ #include <sys/ptrace.h>
+ #endif
+
++#include "common.h"
++#include "breakpoint.h"
++
+ static void handle_signal(Event *event);
+ static void handle_exit(Event *event);
+ static void handle_exit_signal(Event *event);
+@@ -155,19 +156,18 @@ address_clone(void * addr, void * data)
+ }
+
+ static void *
+-breakpoint_clone(void * bp, void * data)
++breakpoint_clone(void *bp, void *data)
+ {
+- Breakpoint * b;
+- Dict * map = data;
++ Dict *map = data;
+ debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
+- b = malloc(sizeof(Breakpoint));
++ struct breakpoint *b = malloc(sizeof(*b));
+ if (!b) {
+ perror("malloc()");
+ exit(1);
+ }
+- memcpy(b, bp, sizeof(Breakpoint));
++ memcpy(b, bp, sizeof(*b));
+ if (b->libsym != NULL) {
+- struct library_symbol * sym = dict_find_entry(map, b->libsym);
++ struct library_symbol *sym = dict_find_entry(map, b->libsym);
+ if (b->libsym == NULL) {
+ fprintf(stderr, "Can't find cloned symbol %s.\n",
+ b->libsym->name);
+@@ -452,9 +452,6 @@ handle_syscall(Event *event) {
+ output_left(LT_TOF_SYSCALL, event->proc,
+ sysname(event->proc, event->e_un.sysnum));
+ }
+- if (event->proc->breakpoints_enabled == 0) {
+- enable_all_breakpoints(event->proc);
+- }
+ }
+ continue_after_syscall(event->proc, event->e_un.sysnum, 0);
+ }
+@@ -462,7 +459,6 @@ handle_syscall(Event *event) {
+ static void
+ handle_exec(Event * event) {
+ Process * proc = event->proc;
+- pid_t saved_pid;
+
+ debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid);
+ if (proc->state == STATE_IGNORED) {
+@@ -476,10 +472,7 @@ handle_exec(Event * event) {
+ proc->arch_ptr = NULL;
+ free(proc->filename);
+ proc->filename = pid2name(proc->pid);
+- saved_pid = proc->pid;
+- proc->pid = 0;
+ breakpoints_init(proc, 0);
+- proc->pid = saved_pid;
+ proc->callstack_depth = 0;
+ continue_process(proc->pid);
+ }
+@@ -493,9 +486,6 @@ handle_arch_syscall(Event *event) {
+ output_left(LT_TOF_SYSCALL, event->proc,
+ arch_sysname(event->proc, event->e_un.sysnum));
+ }
+- if (event->proc->breakpoints_enabled == 0) {
+- enable_all_breakpoints(event->proc);
+- }
+ }
+ continue_process(event->proc->pid);
+ }
+@@ -559,14 +549,11 @@ handle_arch_sysret(Event *event) {
+ continue_process(event->proc->pid);
+ }
+
+-#ifdef __powerpc__
+-void *get_count_register (Process *proc);
+-#endif
+-
+ static void
+-handle_breakpoint(Event *event) {
++handle_breakpoint(Event *event)
++{
+ int i, j;
+- Breakpoint *sbp;
++ struct breakpoint *sbp;
+ Process *leader = event->proc->leader;
+
+ /* The leader has terminated. */
+@@ -578,28 +565,6 @@ handle_breakpoint(Event *event) {
+ debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
+ debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
+
+-#ifdef __powerpc__
+- /* Need to skip following NOP's to prevent a fake function from being stacked. */
+- long stub_addr = (long) get_count_register(event->proc);
+- Breakpoint *stub_bp = NULL;
+- char nop_instruction[] = PPC_NOP;
+-
+- stub_bp = address2bpstruct(leader, event->e_un.brk_addr);
+-
+- if (stub_bp) {
+- unsigned char *bp_instruction = stub_bp->orig_value;
+-
+- if (memcmp(bp_instruction, nop_instruction,
+- PPC_NOP_LENGTH) == 0) {
+- if (stub_addr != (long) event->e_un.brk_addr) {
+- set_instruction_pointer (event->proc, event->e_un.brk_addr + 4);
+- continue_process(event->proc->pid);
+- return;
+- }
+- }
+- }
+-#endif
+-
+ for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
+ if (event->e_un.brk_addr ==
+ event->proc->callstack[i].return_addr) {
+@@ -679,6 +644,8 @@ handle_breakpoint(Event *event) {
+ }
+
+ if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
++ breakpoint_on_hit(sbp, event->proc);
++
+ if (sbp->libsym == NULL) {
+ continue_after_breakpoint(event->proc, sbp);
+ return;
+@@ -696,12 +663,6 @@ handle_breakpoint(Event *event) {
+ callstack_push_symfunc(event->proc, sbp->libsym);
+ output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
+ }
+-#ifdef PLT_REINITALISATION_BP
+- if (event->proc->need_to_reinitialize_breakpoints
+- && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) ==
+- 0))
+- reinitialize_breakpoints(leader);
+-#endif
+
+ continue_after_breakpoint(event->proc, sbp);
+ return;
+diff --git a/ltrace-elf.c b/ltrace-elf.c
+index 8dbc298..f7fc239 100644
+--- a/ltrace-elf.c
++++ b/ltrace-elf.c
+@@ -662,7 +662,8 @@ opd2addr(struct ltelf *lte, GElf_Addr addr) {
+ }
+
+ struct library_symbol *
+-read_elf(Process *proc) {
++read_elf(Process *proc, GElf_Addr *entryp)
++{
+ struct ltelf lte[MAX_LIBRARIES + 1];
+ size_t i;
+ struct opt_x_t *xptr;
+@@ -700,7 +701,6 @@ read_elf(Process *proc) {
+ #ifdef __mips__
+ // MIPS doesn't use the PLT and the GOT entries get changed
+ // on startup.
+- proc->need_to_reinitialize_breakpoints = 1;
+ for(i=lte->mips_gotsym; i<lte->dynsym_count;i++){
+ GElf_Sym sym;
+ const char *name;
+@@ -745,11 +745,6 @@ read_elf(Process *proc) {
+ "Couldn't get relocation from \"%s\"",
+ proc->filename);
+
+-#ifdef PLT_REINITALISATION_BP
+- if (!sym.st_value && PLTs_initialized_by_here)
+- proc->need_to_reinitialize_breakpoints = 1;
+-#endif
+-
+ name = lte->dynstr + sym.st_name;
+ count = library_num ? library_num+1 : 0;
+
+@@ -772,30 +767,6 @@ read_elf(Process *proc) {
+ }
+ }
+ #endif // !__mips__
+-#ifdef PLT_REINITALISATION_BP
+- struct opt_x_t *main_cheat;
+-
+- if (proc->need_to_reinitialize_breakpoints) {
+- /* Add "PLTs_initialized_by_here" to opt_x list, if not
+- already there. */
+- main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
+- if (main_cheat == NULL)
+- error(EXIT_FAILURE, 0, "Couldn't allocate memory");
+- main_cheat->next = opt_x_loc;
+- main_cheat->found = 0;
+- main_cheat->name = PLTs_initialized_by_here;
+-
+- for (xptr = opt_x_loc; xptr; xptr = xptr->next)
+- if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
+- && main_cheat) {
+- free(main_cheat);
+- main_cheat = NULL;
+- break;
+- }
+- if (main_cheat)
+- opt_x_loc = main_cheat;
+- }
+-#endif
+ } else {
+ lib_tail = &library_symbols;
+ }
+@@ -850,16 +821,17 @@ read_elf(Process *proc) {
+ }
+ }
+
++ if (lte->ehdr.e_entry != 0) {
++ *entryp = opd2addr(lte, lte->ehdr.e_entry);
++ } else {
++ }
++
+ for (xptr = opt_x_loc; xptr; xptr = xptr->next)
+ if ( ! xptr->found) {
+ char *badthing = "WARNING";
+ #ifdef PLT_REINITALISATION_BP
+ if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
+ if (lte->ehdr.e_entry) {
+- add_library_symbol (
+- opd2addr (lte, lte->ehdr.e_entry),
+- PLTs_initialized_by_here,
+- lib_tail, 1, 0);
+ fprintf (stderr, "WARNING: Using e_ent"
+ "ry from elf header (%p) for "
+ "address of \"%s\"\n", (void*)
+diff --git a/ltrace-elf.h b/ltrace-elf.h
+index 3b675c5..4da8a0a 100644
+--- a/ltrace-elf.h
++++ b/ltrace-elf.h
+@@ -45,7 +45,7 @@ extern size_t library_num;
+ extern char *library[MAX_LIBRARIES];
+
+ extern int open_elf(struct ltelf *lte, const char *filename);
+-extern struct library_symbol *read_elf(Process *);
++extern struct library_symbol *read_elf(Process *proc, GElf_Addr *entryp);
+
+ extern GElf_Addr arch_plt_sym_val(struct ltelf *, size_t, GElf_Rela *);
+
+diff --git a/proc.c b/proc.c
+index f4d3396..5febc3f 100644
+--- a/proc.c
++++ b/proc.c
+@@ -14,6 +14,7 @@
+ #include <error.h>
+
+ #include "common.h"
++#include "breakpoint.h"
+
+ Process *
+ open_program(char *filename, pid_t pid, int enable) {
+@@ -26,7 +27,6 @@ open_program(char *filename, pid_t pid, int enable) {
+ }
+
+ proc->filename = strdup(filename);
+- proc->breakpoints_enabled = -1;
+ proc->pid = pid;
+ #if defined(HAVE_LIBUNWIND)
+ proc->unwind_priv = _UPT_create(pid);
+@@ -39,13 +39,15 @@ open_program(char *filename, pid_t pid, int enable) {
+ return NULL;
+ }
+
+- if (proc->leader == proc)
++ if (proc->leader == proc) {
++ trace_set_options(proc, proc->pid);
+ if (breakpoints_init(proc, enable)) {
+ fprintf(stderr, "failed to init breakpoints %d\n",
+ proc->pid);
+ remove_process(proc);
+ return NULL;
+ }
++ }
+
+ return proc;
+ }
+@@ -73,11 +75,10 @@ open_one_pid(pid_t pid)
+ return 0;
+ }
+
+-enum pcb_status
++static enum pcb_status
+ start_one_pid(Process * proc, void * data)
+ {
+ continue_process(proc->pid);
+- proc->breakpoints_enabled = 1;
+ return pcb_cont;
+ }
+
+@@ -116,7 +117,7 @@ open_pid(pid_t pid)
+ if (process_tasks(pid, &tasks, &ntasks) < 0) {
+ fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n",
+ pid, strerror(errno));
+- goto start;
++ break;
+ }
+
+ have_all = 1;
+@@ -135,7 +136,6 @@ open_pid(pid_t pid)
+ /* Done. Now initialize breakpoints and then continue
+ * everyone. */
+ Process * leader;
+-start:
+ leader = pid2proc(pid)->leader;
+ enable_all_breakpoints(leader);
+
+diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
+index 4e17940..493f973 100644
+--- a/sysdeps/linux-gnu/arm/breakpoint.c
++++ b/sysdeps/linux-gnu/arm/breakpoint.c
+@@ -27,7 +27,8 @@
+ #include "common.h"
+
+ void
+-arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) {
++arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
++{
+ unsigned int i, j;
+ const unsigned char break_insn[] = BREAKPOINT_VALUE;
+ const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE;
+@@ -59,7 +60,8 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) {
+ }
+
+ void
+-arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) {
++arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
++{
+ unsigned int i, j;
+
+ debug(1, "arch_disable_breakpoint(%d,%p)", pid, sbp->addr);
+diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c
+index 5a49e9d..b98374b 100644
+--- a/sysdeps/linux-gnu/breakpoint.c
++++ b/sysdeps/linux-gnu/breakpoint.c
+@@ -5,12 +5,13 @@
+
+ #include "common.h"
+ #include "arch.h"
++#include "breakpoint.h"
+
+ #ifdef ARCH_HAVE_ENABLE_BREAKPOINT
+-extern void arch_enable_breakpoint(pid_t, Breakpoint *);
++extern void arch_enable_breakpoint(pid_t, struct breakpoint *);
+ #else /* ARCH_HAVE_ENABLE_BREAKPOINT */
+ void
+-arch_enable_breakpoint(pid_t pid, Breakpoint *sbp)
++arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
+ {
+ static unsigned char break_insn[] = BREAKPOINT_VALUE;
+ unsigned int i, j;
+@@ -38,7 +39,8 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp)
+ #endif /* ARCH_HAVE_ENABLE_BREAKPOINT */
+
+ void
+-enable_breakpoint(Process * proc, Breakpoint *sbp) {
++enable_breakpoint(Process *proc, struct breakpoint *sbp)
++{
+ if (sbp->libsym) {
+ debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", proc->pid, sbp->addr, sbp->libsym->name);
+ } else {
+@@ -48,10 +50,10 @@ enable_breakpoint(Process * proc, Breakpoint *sbp) {
+ }
+
+ #ifdef ARCH_HAVE_DISABLE_BREAKPOINT
+-extern void arch_disable_breakpoint(pid_t, const Breakpoint *sbp);
++extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp);
+ #else /* ARCH_HAVE_DISABLE_BREAKPOINT */
+ void
+-arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp)
++arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
+ {
+ unsigned int i, j;
+
+@@ -78,7 +80,8 @@ arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp)
+ #endif /* ARCH_HAVE_DISABLE_BREAKPOINT */
+
+ void
+-disable_breakpoint(Process * proc, Breakpoint *sbp) {
++disable_breakpoint(Process *proc, struct breakpoint *sbp)
++{
+ if (sbp->libsym) {
+ debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", proc->pid, sbp->addr, sbp->libsym->name);
+ } else {
+diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
+index 021192f..3174c1a 100644
+--- a/sysdeps/linux-gnu/events.c
++++ b/sysdeps/linux-gnu/events.c
+@@ -12,6 +12,7 @@
+ #include <unistd.h>
+
+ #include "common.h"
++#include "breakpoint.h"
+
+ static Event event;
+
+@@ -166,19 +167,9 @@ next_event(void)
+ }
+ get_arch_dep(event.proc);
+ debug(3, "event from pid %u", pid);
+- if (event.proc->breakpoints_enabled == -1)
+- trace_set_options(event.proc, event.proc->pid);
+ Process *leader = event.proc->leader;
+ if (leader == event.proc) {
+- if (event.proc->breakpoints_enabled == -1) {
+- event.type = EVENT_NONE;
+- enable_all_breakpoints(event.proc);
+- continue_process(event.proc->pid);
+- debug(DEBUG_EVENT,
+- "event: NONE: pid=%d (enabling breakpoints)",
+- pid);
+- return &event;
+- } else if (!event.proc->libdl_hooked) {
++ if (!event.proc->libdl_hooked) {
+ /* debug struct may not have been written yet.. */
+ if (linkmap_init(event.proc, &main_lte) == 0) {
+ event.proc->libdl_hooked = 1;
+diff --git a/sysdeps/linux-gnu/ia64/breakpoint.c b/sysdeps/linux-gnu/ia64/breakpoint.c
+index 45ee11e..a0bfaf9 100644
+--- a/sysdeps/linux-gnu/ia64/breakpoint.c
++++ b/sysdeps/linux-gnu/ia64/breakpoint.c
+@@ -150,7 +150,8 @@ union bundle_t {
+ };
+
+ void
+-arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) {
++arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
++{
+
+ unsigned long addr = (unsigned long)sbp->addr;
+ union bundle_t bundle;
+@@ -187,7 +188,8 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) {
+ }
+
+ void
+-arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) {
++arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
++{
+
+ unsigned long addr = (unsigned long)sbp->addr;
+ int slotnum = (int)(addr & 0x0f) & 0x3;
+diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
+index a99593c..3350117 100644
+--- a/sysdeps/linux-gnu/proc.c
++++ b/sysdeps/linux-gnu/proc.c
+@@ -1,6 +1,5 @@
+ #define _GNU_SOURCE /* For getline. */
+ #include "config.h"
+-#include "common.h"
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+@@ -17,6 +16,8 @@
+ #include <sys/syscall.h>
+ #include <error.h>
+
++#include "common.h"
++#include "breakpoint.h"
+
+ /* /proc/pid doesn't exist just after the fork, and sometimes `ltrace'
+ * couldn't open it to find the executable. So it may be necessary to
+diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
+index db18df0..b4d8fd1 100644
+--- a/sysdeps/linux-gnu/trace.c
++++ b/sysdeps/linux-gnu/trace.c
+@@ -11,6 +11,7 @@
+
+ #include "common.h"
+ #include "config.h"
++#include "breakpoint.h"
+
+ /* If the system headers did not provide the constants, hard-code the normal
+ values. */
+@@ -77,6 +78,29 @@ trace_me(void) {
+ }
+ }
+
++/* There's a (hopefully) brief period of time after the child process
++ * exec's when we can't trace it yet. Here we wait for kernel to
++ * prepare the process. */
++void
++wait_for_proc(pid_t pid)
++{
++ size_t i;
++ for (i = 0; i < 100; ++i) {
++ /* We read from memory address 0, but that shouldn't
++ * be a problem: the reading will just fail. We are
++ * looking for a particular reason of failure. */
++ if (ptrace(PTRACE_PEEKTEXT, pid, 0, 0) != -1
++ || errno != ESRCH)
++ return;
++
++ usleep(1000);
++ }
++
++ fprintf(stderr, "\
++I consistently fail to read a word from the freshly launched process.\n\
++I'll now try to proceed with tracing, but this shouldn't be happening.\n");
++}
++
+ int
+ trace_pid(pid_t pid) {
+ debug(DEBUG_PROCESS, "trace_pid: pid=%d", pid);
+@@ -193,7 +217,7 @@ struct process_stopping_handler
+ Process * task_enabling_breakpoint;
+
+ /* The pointer being re-enabled. */
+- Breakpoint * breakpoint_being_enabled;
++ struct breakpoint *breakpoint_being_enabled;
+
+ enum {
+ /* We are waiting for everyone to land in t/T. */
+@@ -364,7 +388,7 @@ static void
+ ugly_workaround(Process * proc)
+ {
+ void * ip = get_instruction_pointer(proc);
+- Breakpoint * sbp = dict_find_entry(proc->leader->breakpoints, ip);
++ struct breakpoint *sbp = dict_find_entry(proc->leader->breakpoints, ip);
+ if (sbp != NULL)
+ enable_breakpoint(proc, sbp);
+ else
+@@ -578,7 +602,7 @@ process_stopping_on_event(Event_Handler * super, Event * event)
+ struct process_stopping_handler * self = (void *)super;
+ Process * task = event->proc;
+ Process * leader = task->leader;
+- Breakpoint * sbp = self->breakpoint_being_enabled;
++ struct breakpoint *sbp = self->breakpoint_being_enabled;
+ Process * teb = self->task_enabling_breakpoint;
+
+ debug(DEBUG_PROCESS,
+@@ -687,7 +711,7 @@ process_stopping_destroy(Event_Handler * super)
+ }
+
+ void
+-continue_after_breakpoint(Process *proc, Breakpoint *sbp)
++continue_after_breakpoint(Process *proc, struct breakpoint *sbp)
+ {
+ set_instruction_pointer(proc, sbp->addr);
+ if (sbp->enabled == 0) {
+@@ -851,7 +875,7 @@ static Event *
+ process_vfork_on_event(Event_Handler * super, Event * event)
+ {
+ struct process_vfork_handler * self = (void *)super;
+- Breakpoint * sbp;
++ struct breakpoint *sbp;
+ assert(self != NULL);
+
+ switch (event->type) {
diff --git a/ltrace.spec b/ltrace.spec
index e3bfaf5..c0840e5 100644
--- a/ltrace.spec
+++ b/ltrace.spec
@@ -1,7 +1,7 @@
Summary: Tracks runtime library calls from dynamically linked executables
Name: ltrace
Version: 0.6.0
-Release: 3%{?dist}
+Release: 4%{?dist}
URL: http://ltrace.alioth.debian.org/
License: GPLv2+
Group: Development/Debuggers
@@ -27,6 +27,7 @@ Patch9: ltrace-0.6.0-ppc-args.patch
Patch10: ltrace-0.6.0-ppc-shift.patch
Patch11: ltrace-0.6.0-vfork.patch
Patch12: ltrace-0.6.0-thread-races.patch
+Patch13: ltrace-0.6.0-process-start.patch
%description
Ltrace is a debugging program which runs a specified command until the
@@ -52,6 +53,7 @@ execution of processes.
%patch10 -p1
%patch11 -p1
%patch12 -p1
+%patch13 -p1
sed -i -e 's/-o root -g root//' Makefile.in
%build
@@ -84,6 +86,11 @@ rm -rf $RPM_BUILD_ROOT
%config(noreplace) %{_sysconfdir}/ltrace.conf
%changelog
+* Tue Feb 7 2012 Petr Machata <pmachata at redhat.com> - 0.6.0-4
+- Add upstream patches for initial breakpoint insertion. This mostly
+ fixes tracing on PPC.
+- Resolves: #773050
+
* Fri Nov 25 2011 Petr Machata <pmachata at redhat.com> - 0.6.0-3
- Add several upstream patches that fix various races in tracing
multi-threaded processes
More information about the scm-commits
mailing list