From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 45197 invoked by alias); 9 Mar 2016 21:49:04 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 45149 invoked by uid 89); 9 Mar 2016 21:49:04 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.1 required=5.0 tests=AWL,BAYES_20,FREEMAIL_FROM,FROM_LOCAL_NOVOWEL,HK_RANDOM_ENVFROM,HK_RANDOM_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=no version=3.3.2 spammy=20160310, 2016-03-10, INFO, cap X-HELO: mail-lb0-f175.google.com Received: from mail-lb0-f175.google.com (HELO mail-lb0-f175.google.com) (209.85.217.175) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 09 Mar 2016 21:48:48 +0000 Received: by mail-lb0-f175.google.com with SMTP id bc4so85214188lbc.2 for ; Wed, 09 Mar 2016 13:48:47 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xTnOkqZbpK6lzviiS6HzKYNpueYGR0tLLMtzS7PA/7I=; b=R2uqqoJVvm63b5AH1W15PqaMNLOejF+UJznZIfTcK59ltDJgKuGG7Haqs26kVNkj/0 cLNYNl/4orioJukA+ooI9SGGPacgmxxKkHTJ+LU1OVlIFZSTn9S9WsvxnagaBAsKRLzJ Qg706ozoechH8/X7623Ul8juPutbomIG8XVzNLO5QVeAaBHILbVaKc24AJgU982yK+AP 1tB3vR05XEZCjeAStq3XmmVvjGUdQLH7FYdtfCJA/YdZBaMJWlRwDs78wVVZu5eP/8Jz v6iBjem3kYFf73Zl+8lVIKBqOMWMLmTKnAC5MEF/C2t5V9Tvui5FYNrFgdENJ3LGw9qr rzEw== X-Gm-Message-State: AD7BkJIGchBwf/0kj1GyK4JQMKkiNwzRoV46aNfK8h63Iwpw3LOa68GJmrwkTB9amJADsw== X-Received: by 10.25.218.1 with SMTP id r1mr125870lfg.63.1457560125082; Wed, 09 Mar 2016 13:48:45 -0800 (PST) Received: from octofox.metropolis ([5.19.183.212]) by smtp.gmail.com with ESMTPSA id mt7sm79530lbb.25.2016.03.09.13.48.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 Mar 2016 13:48:44 -0800 (PST) From: Max Filippov To: gdb-patches@sourceware.org Cc: Maxim Grigoriev , Woody LaRue , Marc Gauthier , linux-xtensa@linux-xtensa.org, Max Filippov Subject: [PATCH 2/2] gdb: xtensa: support hardware breakpoints/watchpoints Date: Wed, 09 Mar 2016 21:49:00 -0000 Message-Id: <1457560106-5830-3-git-send-email-jcmvbkbc@gmail.com> In-Reply-To: <1457560106-5830-1-git-send-email-jcmvbkbc@gmail.com> References: <1457560106-5830-1-git-send-email-jcmvbkbc@gmail.com> X-SW-Source: 2016-03/txt/msg00159.txt.bz2 2016-03-10 Max Filippov gdb/ * xtensa-linux-nat.c (PTRACE_GETHBPREGS, PTRACE_SETHBPREGS, XTENSA_MAX_WP_LENGTH, MAX_BPTS, MAX_WPTS, DBREAKC_LOAD_MASK, DBREAKC_STOR_MASK): New definitions. (xtensa_linux_hwbp_cap, xtensa_linux_hw_point, xtensa_linux_process_info, arch_lwp_info, update_registers_data): New structures. (xtensa_linux_process_list): New static variable. (xtensa_linux_find_process_pid, xtensa_linux_add_process, xtensa_linux_process_info_get, xtensa_linux_forget_process, xtensa_linux_get_hwbp_cap, xtensa_linux_get_hw_breakpoint_count, xtensa_linux_get_hw_watchpoint_count, xtensa_linux_can_use_hw_breakpoint, xtensa_linux_hw_breakpoint_initialize, xtensa_linux_hw_watchpoint_initialize, update_registers_callback, xtensa_linux_insert_process_hw_point, xtensa_linux_remove_process_hw_point, xtensa_linux_insert_hw_breakpoint, xtensa_linux_remove_hw_breakpoint, xtensa_linux_region_ok_for_hw_watchpoint, xtensa_linux_insert_watchpoint, xtensa_linux_remove_watchpoint, xtensa_linux_stopped_data_address, xtensa_linux_stopped_by_watchpoint, xtensa_linux_watchpoint_addr_within_range, xtensa_linux_new_thread, xtensa_linux_set_hw_point, xtensa_linux_prepare_to_resume, xtensa_linux_new_fork): New functions. (_initialize_xtensa_linux_nat): Register thr following target callbacks: to_can_use_hw_breakpoint, to_insert_hw_breakpoint, to_remove_hw_breakpoint, to_region_ok_for_hw_watchpoint, to_insert_watchpoint, to_remove_watchpoint, to_stopped_by_watchpoint, to_stopped_data_address, to_watchpoint_addr_within_range. Register handlers for thread and process creation and exit. --- gdb/xtensa-linux-nat.c | 601 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 601 insertions(+) diff --git a/gdb/xtensa-linux-nat.c b/gdb/xtensa-linux-nat.c index 4247f70..1e9a2ca 100644 --- a/gdb/xtensa-linux-nat.c +++ b/gdb/xtensa-linux-nat.c @@ -290,6 +290,586 @@ xtensa_linux_store_inferior_registers (struct target_ops *ops, store_xtregs (regcache, regnum); } +#ifndef PTRACE_GETHBPREGS +#define PTRACE_GETHBPREGS 20 +#endif +#ifndef PTRACE_SETHBPREGS +#define PTRACE_SETHBPREGS 21 +#endif + +#define XTENSA_MAX_WP_LENGTH 64 +#define MAX_BPTS 2 +#define MAX_WPTS 2 + +#define DBREAKC_LOAD_MASK 0x40000000 +#define DBREAKC_STOR_MASK 0x80000000 + +/* Information describing the hardware breakpoint capabilities. */ +struct xtensa_linux_hwbp_cap +{ + gdb_byte wp_count; + gdb_byte bp_count; +}; + +struct xtensa_linux_hw_point +{ + uint32_t addr; + uint32_t type; +}; + +/* Per-process arch-specific data we want to keep. */ +struct xtensa_linux_process_info +{ + /* Linked list. */ + struct xtensa_linux_process_info *next; + /* The process identifier. */ + pid_t pid; + /* Hardware breakpoints state information. */ + struct xtensa_linux_hw_point bpt[MAX_BPTS]; + /* Hardware watchpoints state information. */ + struct xtensa_linux_hw_point wpt[MAX_WPTS]; +}; + +/* Per-thread arch-specific data we want to keep. */ +struct arch_lwp_info +{ + /* Non-zero if our copy differs from what's recorded in the thread. */ + char bpts_changed[MAX_BPTS]; + char wpts_changed[MAX_WPTS]; +}; + +static struct xtensa_linux_process_info *xtensa_linux_process_list = NULL; + +/* Find process data for process PID. */ + +static struct xtensa_linux_process_info * +xtensa_linux_find_process_pid (pid_t pid) +{ + struct xtensa_linux_process_info *proc; + + for (proc = xtensa_linux_process_list; proc; proc = proc->next) + if (proc->pid == pid) + return proc; + + return NULL; +} + +/* Add process data for process PID. Returns newly allocated info + object. */ + +static struct xtensa_linux_process_info * +xtensa_linux_add_process (pid_t pid) +{ + struct xtensa_linux_process_info *proc; + + proc = xcalloc (1, sizeof (*proc)); + proc->pid = pid; + + proc->next = xtensa_linux_process_list; + xtensa_linux_process_list = proc; + + return proc; +} + +/* Get data specific info for process PID, creating it if necessary. + Never returns NULL. */ + +static struct xtensa_linux_process_info * +xtensa_linux_process_info_get (pid_t pid) +{ + struct xtensa_linux_process_info *proc; + + proc = xtensa_linux_find_process_pid (pid); + if (proc == NULL) + proc = xtensa_linux_add_process (pid); + + return proc; +} + +/* Called whenever GDB is no longer debugging process PID. It deletes + data structures that keep track of debug register state. */ + +static void +xtensa_linux_forget_process (pid_t pid) +{ + struct xtensa_linux_process_info *proc, **proc_link; + + proc = xtensa_linux_process_list; + proc_link = &xtensa_linux_process_list; + + while (proc != NULL) + { + if (proc->pid == pid) + { + *proc_link = proc->next; + + xfree (proc); + return; + } + + proc_link = &proc->next; + proc = *proc_link; + } +} + +/* Get hold of the Hardware Breakpoint information for the target we are + attached to. Returns NULL if the kernel doesn't support Hardware + breakpoints at all, or a pointer to the information structure. */ +static const struct xtensa_linux_hwbp_cap * +xtensa_linux_get_hwbp_cap (void) +{ + /* The info structure we return. */ + static struct xtensa_linux_hwbp_cap info; + + /* Is INFO in a good state? 0 means that no attempt has been made to + initialize INFO; 1 means INFO is in an initialized state. */ + static int available; + + if (!available) + { + int i; + int tid; + uint32_t v[2]; + + tid = GET_THREAD_ID (inferior_ptid); + for (i = 0; i < MAX_WPTS; ++i) + { + if (ptrace (PTRACE_GETHBPREGS, tid, i << 1 | 1, v) < 0) + break; + } + info.wp_count = i; + + for (i = 0; i < MAX_BPTS; ++i) + { + if (ptrace (PTRACE_GETHBPREGS, tid, i << 1, v) < 0) + break; + } + info.bp_count = i; + + available = 1; + } + + return &info; +} + +static int +xtensa_linux_get_hw_breakpoint_count (void) +{ + const struct xtensa_linux_hwbp_cap *cap = xtensa_linux_get_hwbp_cap (); + return cap != NULL ? cap->bp_count : 0; +} + +static int +xtensa_linux_get_hw_watchpoint_count (void) +{ + const struct xtensa_linux_hwbp_cap *cap = xtensa_linux_get_hwbp_cap (); + return cap != NULL ? cap->wp_count : 0; +} + +/* Have we got a free break-/watch-point available for use? Returns -1 if + there is not an appropriate resource available, otherwise returns 1. */ +static int +xtensa_linux_can_use_hw_breakpoint (struct target_ops *self, int type, + int cnt, int ot) +{ + if (type == bp_hardware_watchpoint || type == bp_read_watchpoint + || type == bp_access_watchpoint || type == bp_watchpoint) + { + int count = xtensa_linux_get_hw_watchpoint_count (); + + if (count == 0) + return 0; + else if (cnt > count) + return -1; + } + else if (type == bp_hardware_breakpoint) + { + int count = xtensa_linux_get_hw_breakpoint_count (); + + if (count == 0) + return 0; + else if (cnt > count) + return -1; + } + else + gdb_assert (FALSE); + + return 1; +} + +/* Initialise the hardware breakpoint structure P. The breakpoint will be + enabled, and will point to the placed address of BP_TGT. */ +static void +xtensa_linux_hw_point_initialize (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt, + struct xtensa_linux_hw_point *p) +{ + CORE_ADDR address = bp_tgt->placed_address = bp_tgt->reqstd_address; + + p->addr = (unsigned int) address; + p->type = 1; +} + +/* Initialize the hardware breakpoint structure P for a watchpoint at ADDR + to LEN. The type of watchpoint is given in RW. */ +static void +xtensa_linux_hw_watchpoint_initialize (CORE_ADDR addr, int len, int rw, + struct xtensa_linux_hw_point *p) +{ + p->addr = (unsigned int) addr; + p->type = len; + if (rw == hw_read) + p->type |= DBREAKC_LOAD_MASK; + else if (rw == hw_write) + p->type |= DBREAKC_STOR_MASK; + else + p->type |= DBREAKC_LOAD_MASK | DBREAKC_STOR_MASK; +} + +/* Callback to mark a watch-/breakpoint to be updated in all threads of + the current process. */ + +struct update_registers_data +{ + int watch; + int index; +}; + +static int +update_registers_callback (struct lwp_info *lwp, void *arg) +{ + struct update_registers_data *data = (struct update_registers_data *) arg; + + if (lwp->arch_private == NULL) + lwp->arch_private = XCNEW (struct arch_lwp_info); + + /* The actual update is done later just before resuming the lwp, + we just mark that the registers need updating. */ + if (data->watch) + lwp->arch_private->wpts_changed[data->index] = 1; + else + lwp->arch_private->bpts_changed[data->index] = 1; + + /* If the lwp isn't stopped, force it to momentarily pause, so + we can update its breakpoint registers. */ + if (!lwp->stopped) + linux_stop_lwp (lwp); + + return 0; +} + +/* Insert the hardware breakpoint (WATCHPOINT = 0) or watchpoint (WATCHPOINT + =1) BPT for the process. */ +static int +xtensa_linux_insert_process_hw_point (const struct xtensa_linux_hw_point *bpt, + int watchpoint) +{ + int pid; + ptid_t pid_ptid; + struct xtensa_linux_hw_point *pt; + int max_slot_count; + int slot; + + pid = ptid_get_pid (inferior_ptid); + pid_ptid = pid_to_ptid (pid); + + if (watchpoint) + { + max_slot_count = xtensa_linux_get_hw_watchpoint_count(); + pt = xtensa_linux_process_info_get (pid)->wpt; + } + else + { + max_slot_count = xtensa_linux_get_hw_breakpoint_count(); + pt = xtensa_linux_process_info_get (pid)->bpt; + } + + for (slot = 0; slot < max_slot_count; ++slot) + if (pt[slot].type == 0) + { + struct update_registers_data data = + { + .watch = watchpoint, + .index = slot, + }; + pt[slot] = *bpt; + iterate_over_lwps (pid_ptid, update_registers_callback, &data); + return 0; + } + return -1; +} + +/* Remove the hardware breakpoint (WATCHPOINT = 0) or watchpoint + (WATCHPOINT = 1) BPT for the process. */ +static int +xtensa_linux_remove_process_hw_point (const struct xtensa_linux_hw_point *bpt, + int watchpoint) +{ + int pid; + ptid_t pid_ptid; + struct xtensa_linux_hw_point *pt; + int max_slot_count; + int slot; + + pid = ptid_get_pid (inferior_ptid); + pid_ptid = pid_to_ptid (pid); + + if (watchpoint) + { + max_slot_count = xtensa_linux_get_hw_watchpoint_count(); + pt = xtensa_linux_process_info_get (pid)->wpt; + } + else + { + max_slot_count = xtensa_linux_get_hw_breakpoint_count(); + pt = xtensa_linux_process_info_get (pid)->bpt; + } + + for (slot = 0; slot < max_slot_count; ++slot) + if (pt[slot].addr == bpt->addr && + pt[slot].type == bpt->type) + { + struct update_registers_data data = + { + .watch = watchpoint, + .index = slot, + }; + pt[slot].type = 0; + iterate_over_lwps (pid_ptid, update_registers_callback, &data); + return 0; + } + return -1; +} + +/* Insert a Hardware breakpoint. */ +static int +xtensa_linux_insert_hw_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + struct xtensa_linux_hw_point p; + + if (xtensa_linux_get_hw_breakpoint_count () == 0) + return -1; + + xtensa_linux_hw_point_initialize (gdbarch, bp_tgt, &p); + return xtensa_linux_insert_process_hw_point (&p, 0); +} + +/* Remove a hardware breakpoint. */ +static int +xtensa_linux_remove_hw_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + struct xtensa_linux_hw_point p; + + if (xtensa_linux_get_hw_breakpoint_count () == 0) + return -1; + + xtensa_linux_hw_point_initialize (gdbarch, bp_tgt, &p); + return xtensa_linux_remove_process_hw_point (&p, 0); +} + +/* Are we able to use a hardware watchpoint for the LEN bytes starting at + ADDR? */ +static int +xtensa_linux_region_ok_for_hw_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len) +{ + CORE_ADDR aligned_addr; + + /* Can not set watchpoints for zero or negative lengths. */ + if (len <= 0) + return 0; + + /* Test that the range [ADDR, ADDR + LEN) fits into the largest address + range covered by a watchpoint. */ + aligned_addr = addr & ~(XTENSA_MAX_WP_LENGTH - 1); + + if (aligned_addr + XTENSA_MAX_WP_LENGTH < addr + len) + return 0; + + /* The current ptrace interface can only handle watchpoint lengths that + are a power of 2. */ + if ((len & (len - 1)) != 0) + return 0; + + /* All tests passed so we must be able to set a watchpoint. */ + return 1; +} + +/* Insert a Hardware watchpoint. */ +static int +xtensa_linux_insert_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len, int rw, + struct expression *cond) +{ + struct xtensa_linux_hw_point p; + int slot; + + if (xtensa_linux_get_hw_watchpoint_count () == 0) + return -1; + + xtensa_linux_hw_watchpoint_initialize (addr, len, rw, &p); + return xtensa_linux_insert_process_hw_point (&p, 1); +} + +/* Remove a hardware watchpoint. */ +static int +xtensa_linux_remove_watchpoint (struct target_ops *self, + CORE_ADDR addr, int len, int rw, + struct expression *cond) +{ + struct xtensa_linux_hw_point p; + int slot; + + if (xtensa_linux_get_hw_watchpoint_count () == 0) + return -1; + + xtensa_linux_hw_watchpoint_initialize (addr, len, rw, &p); + return xtensa_linux_remove_process_hw_point (&p, 1); +} + +/* What was the data address the target was stopped on accessing. */ +static int +xtensa_linux_stopped_data_address (struct target_ops *target, + CORE_ADDR *addr_p) +{ + siginfo_t siginfo; + int slot; + + if (!linux_nat_get_siginfo (inferior_ptid, &siginfo)) + return 0; + + /* This must be a hardware breakpoint. */ + if (siginfo.si_signo != SIGTRAP + || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */) + return 0; + + /* We must be able to set hardware watchpoints. */ + if (xtensa_linux_get_hw_watchpoint_count () == 0) + return 0; + + slot = siginfo.si_errno; + + /* If we are in an even slot then we're looking at a breakpoint and not + a watchpoint. */ + if ((slot & 0x1) == 0) + return 0; + + *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr; + return 1; +} + +/* Has the target been stopped by hitting a watchpoint? */ +static int +xtensa_linux_stopped_by_watchpoint (struct target_ops *ops) +{ + CORE_ADDR addr; + return xtensa_linux_stopped_data_address (ops, &addr); +} + +static int +xtensa_linux_watchpoint_addr_within_range (struct target_ops *target, + CORE_ADDR addr, + CORE_ADDR start, int length) +{ + return start <= addr && start + length - 1 >= addr; +} + +/* Handle thread creation. We need to copy the breakpoints and watchpoints + in the parent thread to the child thread. */ +static void +xtensa_linux_new_thread (struct lwp_info *lp) +{ + int i; + struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); + + /* Mark that all the hardware breakpoints/watchpoints + for this thread need to be initialized. */ + + for (i = 0; i < MAX_BPTS; i++) + info->bpts_changed[i] = 1; + for (i = 0; i < MAX_WPTS; i++) + info->wpts_changed[i] = 1; + + lp->arch_private = info; +} + +static long +xtensa_linux_set_hw_point (const struct xtensa_linux_hw_point *bpt, + int pid, int slot, int watchpoint) +{ + uint32_t bp[2] = { bpt->addr, bpt->type }; + + return ptrace (PTRACE_SETHBPREGS, pid, slot << 1 | watchpoint, bp); +} + +/* Called when resuming a thread. + The hardware debug registers are updated when there is any change. */ +static void +xtensa_linux_prepare_to_resume (struct lwp_info *lwp) +{ + int pid, i; + struct xtensa_linux_hw_point *bpts, *wpts; + struct arch_lwp_info *lwp_info = lwp->arch_private; + + pid = ptid_get_lwp (lwp->ptid); + bpts = xtensa_linux_process_info_get (ptid_get_pid (lwp->ptid))->bpt; + wpts = xtensa_linux_process_info_get (ptid_get_pid (lwp->ptid))->wpt; + + if (lwp_info == NULL) + return; + + for (i = 0; i < xtensa_linux_get_hw_breakpoint_count (); i++) + if (lwp_info->bpts_changed[i]) + { + errno = 0; + + if (xtensa_linux_set_hw_point (bpts + i, pid, i, 0) < 0) + perror_with_name (_("Unexpected error setting breakpoint")); + + lwp_info->bpts_changed[i] = 0; + } + + for (i = 0; i < xtensa_linux_get_hw_watchpoint_count (); i++) + if (lwp_info->wpts_changed[i]) + { + errno = 0; + + if (xtensa_linux_set_hw_point (wpts + i, pid, i, 1) < 0) + perror_with_name (_("Unexpected error setting watchpoint")); + + lwp_info->wpts_changed[i] = 0; + } +} + +static void +xtensa_linux_new_fork (struct lwp_info *parent, pid_t child_pid) +{ + pid_t parent_pid; + struct xtensa_linux_process_info *parent_state; + struct xtensa_linux_process_info *child_state; + + /* NULL means no watchpoint has ever been set in the parent. In + that case, there's nothing to do. */ + if (parent->arch_private == NULL) + return; + + /* GDB core assumes the child inherits the watchpoints/hw + breakpoints of the parent, and will remove them all from the + forked off process. Copy the debug registers mirrors into the + new process so that all breakpoints and watchpoints can be + removed together. */ + + parent_pid = ptid_get_pid (parent->ptid); + parent_state = xtensa_linux_process_info_get (parent_pid); + child_state = xtensa_linux_process_info_get (child_pid); + memcpy (child_state->bpt, parent_state->bpt, sizeof (parent_state->bpt)); + memcpy (child_state->wpt, parent_state->wpt, sizeof (parent_state->wpt)); +} + void _initialize_xtensa_linux_nat (void); void @@ -316,5 +896,26 @@ _initialize_xtensa_linux_nat (void) t->to_fetch_registers = xtensa_linux_fetch_inferior_registers; t->to_store_registers = xtensa_linux_store_inferior_registers; + /* Add our hardware breakpoint and watchpoint implementation. */ + t->to_can_use_hw_breakpoint = xtensa_linux_can_use_hw_breakpoint; + t->to_insert_hw_breakpoint = xtensa_linux_insert_hw_breakpoint; + t->to_remove_hw_breakpoint = xtensa_linux_remove_hw_breakpoint; + + t->to_region_ok_for_hw_watchpoint = xtensa_linux_region_ok_for_hw_watchpoint; + t->to_insert_watchpoint = xtensa_linux_insert_watchpoint; + t->to_remove_watchpoint = xtensa_linux_remove_watchpoint; + t->to_stopped_by_watchpoint = xtensa_linux_stopped_by_watchpoint; + t->to_stopped_data_address = xtensa_linux_stopped_data_address; + t->to_watchpoint_addr_within_range = + xtensa_linux_watchpoint_addr_within_range; + linux_nat_add_target (t); + + /* Handle thread creation and exit. */ + linux_nat_set_new_thread (t, xtensa_linux_new_thread); + linux_nat_set_prepare_to_resume (t, xtensa_linux_prepare_to_resume); + + /* Handle process creation and exit. */ + linux_nat_set_new_fork (t, xtensa_linux_new_fork); + linux_nat_set_forget_process (t, xtensa_linux_forget_process); } -- 2.1.4