As I've said in my previous post, thread_db has a call to remove_thread_event_breakpoints after the inferior having execd, here: static ptid_t thread_db_wait (ptid_t ptid, struct target_waitstatus *ourstatus) { ptid = target_beneath->to_wait (ptid, ourstatus); (...) if (ourstatus->kind == TARGET_WAITKIND_EXECD) { remove_thread_event_breakpoints (); <<<<< unpush_target (&thread_db_ops); using_thread_db = 0; return ptid; } breakpoint.c:remove_thread_event_breakpoints is this: void remove_thread_event_breakpoints (void) { struct breakpoint *b, *temp; ALL_BREAKPOINTS_SAFE (b, temp) if (b->type == bp_thread_event) delete_breakpoint (b); } With the previous patch I just sent in place, which marks the breakpoints not inserted before reaching this point, delete_breakpoint (and its callees), will no longer try to remove the breakpoint locations from the inferior. The problem with always inserted mode, is that update_global_location_list, the workhorse that detects duplicate locations, and if locations should be deleted or inserted, finds that breakpoint locations tagged as not inserted but which are enabled, and so goes on and inserts them. But the addresses in which they are being inserted don't make any sense in the new exec image, and we again see errors like: /home/pedro/gdb/execl_hunt/build32/gdb/testsuite/gdb.threads/execl1: error while loading shared libraries: libm.so.6: failed to map segment from shared object: Cannot allocate memory IMO, having the breakpoints management functions whose job is to delete a breakpoint insert locations, is a side effect that is always undesirable. Here's another example I found while working on non-stop, which requires always-inserted mode, that is broken due to that same fact: void target_detach (char *args, int from_tty) { /* If we're in breakpoints-always-inserted mode, have to remove them before detaching. */ remove_breakpoints (); (current_target.to_detach) (args, from_tty); } static void thread_db_detach (char *args, int from_tty) { disable_thread_event_reporting (); target_beneath->to_detach (args, from_tty); /* Should this be done by detach_command? */ target_mourn_inferior (); } static void disable_thread_event_reporting (void) { td_thr_events_t events; /* Set the process wide mask saying we aren't interested in any events anymore. */ td_event_emptyset (&events); td_ta_set_event_p (thread_agent, &events); /* Delete thread event breakpoints, if any. */ remove_thread_event_breakpoints (); <<<<<< td_create_bp_addr = 0; td_death_bp_addr = 0; } Notice that first, all breakpoints are removed from the inferior in target_detach, but if the inferior has thread_db loaded, the remove_thread_event_breakpoints call, which calls delete_breakpoint, will end up reinserting the locations into the inferior, with the effect that the inferior crashes with hitting a left over breakpoint right after detaching. IMO, the best solution to these problems is making sure that update_global_location_list does not insert breakpoints locations if being called from a function that is deleting (a) breakpoint(s). This also gets rid of the hack of temporarilly disabling always-inserted mode in update_breakpoints_after_exec, which was there due to this exact fact. Tested on x86_64-unknown-linux-gnu {,-m32}, with and without always-inserted mode. No regressions, and execl.exp now passes cleanly in all combinations, always. OK? -- Pedro Alves