int breakpoints_init(struct process *proc) { debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); /* XXX breakpoint dictionary should be initialized * outside. Here we just put in breakpoints. */ assert(proc->breakpoints != NULL); /* Only the thread group leader should hold the breakpoints. */ assert(proc->leader == proc); /* N.B. the following used to be conditional on this, and * maybe it still needs to be. */ assert(proc->filename != NULL); struct library *lib = ltelf_read_main_binary(proc, proc->filename); struct entry_breakpoint *entry_bp = NULL; int bp_state = 0; int result = -1; switch ((int)(lib != NULL)) { fail: switch (bp_state) { case 2: proc_remove_library(proc, lib); proc_remove_breakpoint(proc, &entry_bp->super); case 1: breakpoint_destroy(&entry_bp->super); } library_destroy(lib); free(entry_bp); case 0: return result; } entry_bp = malloc(sizeof(*entry_bp)); if (entry_bp == NULL || (entry_breakpoint_init(proc, entry_bp, lib->entry, lib)) < 0) { fprintf(stderr, "Couldn't initialize entry breakpoint for PID %d.\n" "Some tracing events may be missed.\n", proc->pid); free(entry_bp); } else { ++bp_state; if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0) goto fail; ++bp_state; if ((result = breakpoint_turn_on(&entry_bp->super, proc)) < 0) goto fail; } proc_add_library(proc, lib); proc->callstack_depth = 0; return 0; }
static void private_process_destroy(struct Process *proc, int was_exec) { /* Pop remaining stack elements. */ while (proc->callstack_depth > 0) { /* When this is called just before a process is * destroyed, the breakpoints should either have been * retracted by now, or were killed by exec. In any * case, it's safe to pretend that there are no * breakpoints associated with the stack elements, so * that stack_pop doesn't attempt to destroy them. */ size_t i = proc->callstack_depth - 1; if (!proc->callstack[i].is_syscall) proc->callstack[i].return_addr = 0; callstack_pop(proc); } if (!was_exec) free(proc->filename); /* Libraries and symbols. This is only relevant in * leader. */ struct library *lib; for (lib = proc->libraries; lib != NULL; ) { struct library *next = lib->next; library_destroy(lib); free(lib); lib = next; } proc->libraries = NULL; /* Breakpoints. */ if (proc->breakpoints != NULL) { proc_each_breakpoint(proc, NULL, destroy_breakpoint_cb, NULL); dict_clear(proc->breakpoints); proc->breakpoints = NULL; } destroy_unwind(proc); }
static void crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) { debug (DEBUG_FUNCTION, "crawl_linkmap()"); if (!dbg || !dbg->r_map) { debug(2, "Debug structure or it's linkmap are NULL!"); return; } /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ arch_addr_t addr = (arch_addr_t)(uintptr_t)dbg->r_map; while (addr != 0) { struct lt_link_map_64 rlm = {}; if (lm_fetcher(proc)(proc, addr, &rlm) < 0) { debug(2, "Unable to read link map"); return; } arch_addr_t key = addr; /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ addr = (arch_addr_t)(uintptr_t)rlm.l_next; if (rlm.l_name == 0) { debug(2, "Name of mapped library is NULL"); return; } char lib_name[BUFSIZ]; /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ umovebytes(proc, (arch_addr_t)(uintptr_t)rlm.l_name, lib_name, sizeof(lib_name)); /* Library name can be an empty string, in which case * the entry represents either the main binary, or a * VDSO. Unfortunately we can't rely on that, as in * recent glibc, that entry is initialized to VDSO * SONAME. * * It's not clear how to detect VDSO in this case. We * can't assume that l_name of real DSOs will be * either absolute or relative (for LD_LIBRARY_PATH=: * it will be neither). We can't compare l_addr with * AT_SYSINFO_EHDR either, as l_addr is bias (which * also means it's not unique, and therefore useless * for this). We could load VDSO from process image * and at least compare actual SONAMEs. For now, this * kludge is about the best that we can do. */ if (*lib_name == 0 || strcmp(lib_name, "linux-vdso.so.1") == 0 || strcmp(lib_name, "linux-gate.so.1") == 0 || strcmp(lib_name, "linux-vdso32.so.1") == 0 || strcmp(lib_name, "linux-vdso64.so.1") == 0) continue; /* Do we have that library already? */ if (proc_each_library(proc, NULL, library_with_key_cb, &key)) continue; struct library *lib = malloc(sizeof(*lib)); if (lib == NULL) { fail: if (lib != NULL) library_destroy(lib); fprintf(stderr, "Couldn't load ELF object %s: %s\n", lib_name, strerror(errno)); continue; } library_init(lib, LT_LIBTYPE_DSO); if (ltelf_read_library(lib, proc, lib_name, rlm.l_addr) < 0) goto fail; lib->key = key; proc_add_library(proc, lib); } return; }
int 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", proc->pid, pid, strerror(errno)); return -1; } retp->tracesysgood = proc->tracesysgood; retp->e_machine = proc->e_machine; retp->e_class = proc->e_class; /* For non-leader processes, that's all we need to do. */ if (retp->leader != retp) return 0; /* Clone symbols first so that we can clone and relink * breakpoints. */ struct library *lib; 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) { fail2: process_bare_destroy(retp, 0); /* Error when cloning. Unroll what was done. */ for (lib = retp->libraries; lib != NULL; ) { struct library *next = lib->next; library_destroy(lib); free(lib); lib = next; } goto fail1; } nlibp = &(*nlibp)->next; } /* Now clone breakpoints. Symbol relinking is done in * clone_single_bp. */ 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) goto fail2; /* And finally the call stack. */ /* XXX clearly the callstack handling should be moved to a * separate module and this whole business extracted to * callstack_clone, or callstack_element_clone. */ memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack)); retp->callstack_depth = proc->callstack_depth; size_t i; for (i = 0; i < retp->callstack_depth; ++i) { struct callstack_element *elem = &retp->callstack[i]; struct fetch_context *ctx = elem->fetch_context; if (ctx != NULL) { struct fetch_context *nctx = fetch_arg_clone(retp, ctx); if (nctx == NULL) { size_t j; fail3: for (j = 0; j < i; ++j) { nctx = elem->fetch_context; fetch_arg_done(nctx); elem->fetch_context = NULL; } goto fail2; } elem->fetch_context = nctx; } struct value_dict *args = elem->arguments; if (args != NULL) { struct value_dict *nargs = malloc(sizeof(*nargs)); if (nargs == NULL || val_dict_clone(nargs, args) < 0) { size_t j; for (j = 0; j < i; ++j) { nargs = elem->arguments; val_dict_destroy(nargs); free(nargs); elem->arguments = NULL; } /* Pretend that this round went well, * so that fail3 frees I-th * fetch_context. */ ++i; goto fail3; } elem->arguments = nargs; } /* If it's not a syscall, we need to find the * corresponding library symbol in the cloned * library. */ if (!elem->is_syscall && elem->c_un.libfunc != NULL) { struct library_symbol *libfunc = elem->c_un.libfunc; int rc = proc_find_symbol(retp, libfunc, NULL, &elem->c_un.libfunc); assert(rc == 0); } } /* At this point, retp is fully initialized, except for OS and * arch parts, and we can call private_process_destroy. */ if (os_process_clone(retp, proc) < 0) { private_process_destroy(retp, 0); return -1; } if (arch_process_clone(retp, proc) < 0) { os_process_destroy(retp); private_process_destroy(retp, 0); return -1; } return 0; } 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) { fail: free(filename); return -1; } proc = open_program(filename, pid); if (proc == NULL) goto fail; free(filename); trace_set_options(proc); return 0; }
int main(char *argv[],int argc) { mc_init(); el_bool stop = el_false; hre_t re_load = hre_compile("^load(&play)?\\s+(.*)$","i"); hre_t re_play = hre_compile("^play$","i"); hre_t re_pause = hre_compile("^pause$","i"); hre_t re_next = hre_compile("^next$","i"); hre_t re_previous = hre_compile("^prev(ious)?$","i"); hre_t re_track = hre_compile("^track\\s+([0-9]+)$","i"); hre_t re_quhit = hre_compile("^quit$","i"); hre_t re_seek = hre_compile("^seek\\s([0-9]+([.][0-9]+)?)$","i"); hre_t re_quit = hre_compile("^quit$","i"); hre_t re_repeat = hre_compile("^repeat\\s+(off|list|track)$","i"); hre_t re_again = hre_compile("^again$","i"); hre_t re_scan = hre_compile("^scan\\s+(.*)$","i"); file_info_t *history_file = mc_take_over(file_info_new_home(".btb_playlist")); printf("history file: %s\n", file_info_absolute_path(history_file)); printf("history file: %s\n", file_info_path(history_file)); if (file_info_exists(history_file)) { read_history(file_info_absolute_path(history_file)); } i18n_set_language("nl"); printf(_("Starting btb_playlist\n")); playlist_player_t *player = playlist_player_new(); while (!stop) { char* line = readln(">", player); hre_trim(line); if (hre_has_match(re_quit, line)) { stop = el_true; } else if (hre_has_match(re_load, line)) { hre_matches m = hre_match(re_load, line); hre_match_t *mplay = hre_matches_get(m, 1); hre_match_t *match = hre_matches_get(m, 2); char* file = mc_strdup(hre_match_str(match)); char* play = mc_strdup(hre_match_str(mplay)); hre_matches_destroy(m); printf("loading '%s', '%s'\n", file, play); file_info_t *info = file_info_new(file); if (file_info_exists(info)) { if (file_info_is_file(info)) { if (file_info_can_read(info)) { const char *mediafile = NULL; track_array array; if (strcasecmp(file_info_ext(info),"cue") == 0) { array = tracks_from_cue(file_info_absolute_path(info)); track_t* t = track_array_get(array, 0); } else { array = tracks_from_media(file_info_absolute_path(info)); } playlist_t* pl = playlist_new("playlist"); int i; for(i=0; i < track_array_count(array); ++i) { playlist_append(pl, track_array_get(array, i)); } playlist_player_set_playlist(player, pl); track_array_destroy(array); } } } file_info_destroy(info); if (strcasecmp(play,"&play")==0) { playlist_player_play(player); } mc_free(file); mc_free(play); } else if (hre_has_match(re_play, line)) { playlist_player_play(player); } else if (hre_has_match(re_pause, line)) { playlist_player_pause(player); } else if (hre_has_match(re_seek, line)) { hre_matches m = hre_match(re_seek, line); hre_match_t* match = hre_matches_get(m, 1); char* position = mc_strdup(hre_match_str(match)); hre_matches_destroy(m); double s = atof(position); int ms = s * 1000; mc_free(position); playlist_player_seek(player, ms); } else if (hre_has_match(re_next, line)) { playlist_player_next(player); } else if (hre_has_match(re_previous, line)) { playlist_player_previous(player); } else if (hre_has_match(re_track, line)) { hre_matches m = hre_match(re_track, line); hre_match_t* match = hre_matches_get(m, 1); char* nr = mc_strdup(hre_match_str(match)); hre_matches_destroy(m); int index = atoi(nr); mc_free(nr); printf("setting track %d\n",index); playlist_player_set_track(player, index); } else if (hre_has_match(re_repeat, line)) { hre_matches m = hre_match(re_repeat, line); hre_match_t* match = hre_matches_get(m, 1); if (strcasecmp(hre_match_str(match),"track") == 0) { playlist_player_set_repeat(player, PLP_TRACK_REPEAT); } else if (strcasecmp(hre_match_str(match),"list") == 0) { playlist_player_set_repeat(player, PLP_LIST_REPEAT); } else { playlist_player_set_repeat(player, PLP_NO_REPEAT); } hre_matches_destroy(m); } else if (hre_has_match(re_again, line)) { playlist_player_again(player); } else if (hre_has_match(re_scan, line)) { hre_matches m = hre_match(re_scan, line); hre_match_t* match = hre_matches_get(m, 1); printf("scanning %s\n", hre_match_str(match)); library_t* library = library_new(); printf("calling scan_library\n"); //scan_library(library, hre_match_str(match), library_cb); printf("\n"); printf("library: %d tracks\n", library_count(library)); printf("done scanning, destroying library\n"); library_destroy(library); printf("library destroyed\n"); hre_matches_destroy(m); printf("matches destroyed\n"); } mc_free(line); } playlist_player_destroy(player); printf("%d\n",write_history(file_info_absolute_path(history_file))); file_info_destroy(history_file); hre_destroy(re_load); hre_destroy(re_play); hre_destroy(re_pause); hre_destroy(re_quit); hre_destroy(re_seek); hre_destroy(re_track); hre_destroy(re_next); hre_destroy(re_previous); hre_destroy(re_again); hre_destroy(re_repeat); hre_destroy(re_scan); return 0; }
int library_clone(struct library *retp, struct library *lib) { const char *soname = NULL; const char *pathname; /* Make lifetimes of strings stored at original independent of * those at the clone. */ if (strdup_if(&soname, lib->soname, lib->own_soname) < 0 || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) { if (lib->own_soname) free((char *)soname); return -1; } private_library_init(retp, lib->type); library_set_soname(retp, soname, lib->own_soname); library_set_pathname(retp, pathname, lib->own_pathname); retp->key = lib->key; /* Clone symbols. */ { struct library_symbol *it; struct library_symbol **nsymp = &retp->symbols; for (it = lib->symbols; it != NULL; it = it->next) { *nsymp = malloc(sizeof(**nsymp)); if (*nsymp == NULL || library_symbol_clone(*nsymp, it) < 0) { free(*nsymp); *nsymp = NULL; fail: /* Release what we managed to allocate. */ library_destroy(retp); return -1; } (*nsymp)->lib = retp; nsymp = &(*nsymp)->next; } *nsymp = NULL; } /* Clone exported names. */ { struct library_exported_name *it; struct library_exported_name **nnamep = &retp->exported_names; for (it = lib->exported_names; it != NULL; it = it->next) { *nnamep = malloc(sizeof(**nnamep)); if (*nnamep == NULL || library_exported_name_clone(*nnamep, it) < 0) { free(*nnamep); goto fail; } nnamep = &(*nnamep)->next; } *nnamep = NULL; } if (os_library_clone(retp, lib) < 0) goto fail; if (arch_library_clone(retp, lib) < 0) { os_library_destroy(retp); goto fail; } return 0; }