static int dtor( GEM_PLOTTER self ) { int i=0; LOG(("%s: %s\n", (char*)__FILE__, __FUNCTION__)); if( VIEW(self).mem ) free( VIEW(self).mem ); #ifdef WITH_8BPP_SUPPORT if( DUMMY_PRIV(self)->vfmt.indexed ){ for( i=OFFSET_WEB_PAL; i<OFFSET_CUST_PAL+16; i++){ vs_color( self->vdi_handle, i, &sys_pal[i][0] ); } } #endif /* close Hermes stuff: */ Hermes_ConverterReturn( hermes_cnv_h ); Hermes_Done(); if( self->priv_data != NULL ){ if( DUMMY_PRIV(self)->buf_packed ) free( DUMMY_PRIV(self)->buf_packed ); if( DUMMY_PRIV(self)->buf_planar ) free( DUMMY_PRIV(self)->buf_planar ); free( self->priv_data ); } snapshot_destroy( self ); return( 1 ); }
int backtrace_snapshot(int pid, int *tids, int *index, int nr_tids) { int i, rc = 0; struct snapshot *snap; if ((snap = get_snapshot(pid, tids, index, nr_tids)) == NULL) return -1; for (i = 0; i < snap->num_threads; ++i) { int x; char comm[16]; char end_pad[25] = "------------------------"; x = get_thread_comm(snap->tids[i], comm, sizeof(comm)); if (x > 0 && x <= sizeof(end_pad)) { end_pad[sizeof(end_pad) - x] = '\0'; printf("-------------- thread %d (%d) (%s) %s\n", (index != NULL ? index[i] : i+1), snap->tids[i], comm, end_pad); } snap->cur_thr = i; if (backtrace_thread(&snapshot_addr_space_accessors, snap) < 0) rc = -1; } snapshot_destroy(snap); return rc; }
/* * ndmp_remove_snapshot * * This function will parse the path to get the real volume name. * It will then remove the snapshot for that volume and job name. * This function should be called after NDMP backup is finished. * * Parameters: * vol_name (input) - name of the volume * * Returns: * 0: on success * -1: otherwise */ int ndmp_remove_snapshot(char *vol_name, char *jname) { char vol[ZFS_MAXNAMELEN]; if (vol_name == 0 || get_zfsvolname(vol, sizeof (vol), vol_name) == -1) return (0); return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL)); }
/* * ndmp_create_snapshot * * This function will parse the path to get the real volume name. * It will then create a snapshot based on volume and job name. * This function should be called before the NDMP backup is started. * * Parameters: * vol_name (input) - name of the volume * * Returns: * 0: on success * -1: otherwise */ int ndmp_create_snapshot(char *vol_name, char *jname) { char vol[ZFS_MAXNAMELEN]; if (vol_name == 0 || get_zfsvolname(vol, sizeof (vol), vol_name) == -1) return (0); /* * If there is an old snapshot left from the previous * backup it could be stale one and it must be * removed before using it. */ if (ndmp_has_backup_snapshot(vol, jname)) (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL); return (snapshot_create(vol, jname, B_FALSE, B_TRUE)); }
int backtrace_snapshot(int pid, int *tids, int *index, int nr_tids) { int i, rc = 0; struct snapshot *snap; if ((snap = get_snapshot(pid, tids, index, nr_tids)) == NULL) return -1; for (i = 0; i < snap->num_threads; ++i) { printf("-------------------- thread %d (%d) --------------------\n", (index != NULL ? index[i] : i+1), snap->tids[i]); snap->cur_thr = i; if (backtrace_thread(&snapshot_addr_space_accessors, snap) < 0) rc = -1; } snapshot_destroy(snap); return rc; }
/* * save process' memory maps, stack contents, thread identifiers and registers */ struct snapshot *get_snapshot(int pid, int *tids, int *index, int nr_tids) { struct snapshot *res; int attached_tid = 0; int i, n_frames; long page, label, rc; struct mem_data_chunk **stacks_cover = NULL; if ((page = sysconf(_SC_PAGESIZE)) < 0) { perror("get pagesize"); return NULL; } --page; res = calloc(1, sizeof(struct snapshot)); /* * create memory_map structure corresponding to process' maps */ res->map = create_maps(pid); if (res->map == NULL) goto get_snapshot_fail; /* * get process' threads */ res->num_threads = get_threads(pid, &res->tids); if (res->num_threads < 0 || res->tids == NULL) goto get_snapshot_fail; /* * user-provided list of threads */ if (tids != NULL) { if (adjust_threads(res->tids, res->num_threads, tids, index, nr_tids) < 0) goto get_snapshot_fail; free(res->tids); res->num_threads = nr_tids; res->tids = tids; } res->cur_thr = 0; res->regs = malloc(sizeof(res->regs[0])*res->num_threads); if (res->regs == NULL) { perror("malloc"); goto get_snapshot_fail; } /* FREEZE PROCESS */ if (attach_process(pid) < 0) goto get_snapshot_fail; for (i = 0; i < res->num_threads; ++i) { struct iovec iov; /* * we have already attached to main thread. call attach_thread() * for other ones */ attached_tid = res->tids[i]; if (res->tids[i] != pid && attach_thread(res->tids[i]) < 0) goto get_snapshot_fail_attached; /* * save thread's registers */ iov.iov_len = sizeof(res->regs[0]); iov.iov_base = &res->regs[i]; rc = ptrace(PTRACE_GETREGSET, res->tids[i], NT_PRSTATUS, &iov); if (rc < 0) { perror("PTRACE_GETREGSET"); goto get_snapshot_fail_attached; } /* * save label on memory region. it will indicate that memory contents * upper than this point (%rsp) will needed to unwind stacks */ label = SP_REG(&res->regs[i]) & ~page; rc = mem_map_add_label(res->map, (void *)label, res->num_threads); if (rc < 0) { fprintf(stderr, "failed to add label 0x%lx [rsp 0x%llx thread %d]\n", label, (long long unsigned int)SP_REG(&res->regs[i]), res->tids[i]); goto get_snapshot_fail_attached; } /* * detach from thread. it will still be frozen due to SIGSTOP */ if (res->tids[i] != pid && detach_thread(res->tids[i]) < 0) goto get_snapshot_fail_attached; } /* * arrange data chunks to copy memory contents. in most cases the chunks * will start from %rsp pointing somewhere in thread's stack * to the end of the stack region */ stacks_cover = malloc(sizeof(struct mem_data_chunk*) * res->num_threads); n_frames = mem_map_build_label_cover(res->map, stack_size, stacks_cover, page + 1); if (stacks_cover == NULL) { fprintf(stderr, "error: stacks cover == NULL, n_frames=%d\n", n_frames); goto get_snapshot_fail_attached; } /* * copy memory contents */ rc = copy_memory(pid, stacks_cover, n_frames); if (rc < 0) goto get_snapshot_fail_attached; /* UNFREEZE PROCESS */ if (detach_process(pid) < 0) goto get_snapshot_fail; if (opt_verbose) { for (i = 0; i < n_frames; ++i) { struct mem_data_chunk *chunk = stacks_cover[i]; printf("chunk #%d: 0x%lx-0x%lx length: %ldK\n", i, (size_t)chunk->start, (size_t)chunk->start + chunk->length, chunk->length >> 10); } } free(stacks_cover); return res; get_snapshot_fail_attached: if (attached_tid) detach_thread(attached_tid); detach_process(pid); get_snapshot_fail: if (opt_verbose) { fprintf(stderr, "maps of %d:\n", pid); print_proc_maps(pid); } free(stacks_cover); snapshot_destroy(res); return NULL; }
/* * save process' memory maps, stack contents, thread identifiers and registers */ struct snapshot *get_snapshot(int pid, int *tids, int *index, int nr_tids) { struct snapshot *res; int i, attached_tid, n_frames; long page, label, rc; struct mem_data_chunk **stacks_cover = NULL; int v_major, v_minor; int use_process_vm_readv = 0; if ((page = sysconf(_SC_PAGESIZE)) < 0) { perror("get pagesize"); return NULL; } --page; res = calloc(1, sizeof(struct snapshot)); /* * create memory_map structure corresponding to process' maps */ res->map = create_maps(pid); if (res->map == NULL) goto get_snapshot_fail; /* * get process' threads */ res->num_threads = get_threads(pid, &res->tids); if (res->num_threads < 0 || res->tids == NULL) goto get_snapshot_fail; /* * user-provided list of threads */ if (tids != NULL) { if (adjust_threads(res->tids, res->num_threads, tids, index, nr_tids) < 0) goto get_snapshot_fail; free(res->tids); res->num_threads = nr_tids; res->tids = tids; } res->cur_thr = 0; res->regs = malloc(sizeof(struct user_regs_struct)*res->num_threads); if (res->regs == NULL) { perror("malloc"); goto get_snapshot_fail; } /* * decide how to copy memory contents of the process. on newer kernels * proc_vm_readv() is used by default. on older kernels or when the option * --proc-mem is specified read the file /proc/<pid>/mem */ if (!opt_proc_mem) { if (get_kernel_version(&v_major, &v_minor) < 0) goto get_snapshot_fail; if (((v_major << 16) | v_minor) >= 0x30002) use_process_vm_readv = 1; } else { use_process_vm_readv = 0; } /* FREEZE PROCESS */ if (attach_process(pid) < 0) goto get_snapshot_fail; for (i = 0; i < res->num_threads; ++i) { /* * we have already attached to main thread. call attach_thread() * for other ones */ attached_tid = res->tids[i]; if (res->tids[i] != pid && attach_thread(res->tids[i]) < 0) goto get_snapshot_fail_attached; /* * save thread's registers */ rc = ptrace(PTRACE_GETREGS, res->tids[i], NULL, &res->regs[i]); if (rc < 0) { perror("PTRACE_GETREGS"); goto get_snapshot_fail_attached; } /* * save label on memory region. it will indicate that memory contents * upper than this point (%rsp) will needed to unwind stacks */ label = res->regs[i].rsp & ~page; rc = mem_map_add_label(res->map, (void *)label, res->num_threads); if (rc < 0) { fprintf(stderr, "failed to add label 0x%lx [rsp 0x%lx thread %d]\n", label, res->regs[i].rsp, res->tids[i]); goto get_snapshot_fail_attached; } /* * detach from thread. it will still be frozen due to SIGSTOP */ if (res->tids[i] != pid && detach_thread(res->tids[i]) < 0) goto get_snapshot_fail_attached; } /* * arrange data chunks to copy memory contents. in most cases the chunks * will start from %rsp pointing somewhere in thread's stack * to the end of the stack region */ stacks_cover = malloc(sizeof(struct mem_data_chunk*) * res->num_threads); n_frames = mem_map_build_label_cover(res->map, stack_size, stacks_cover, page + 1); if (stacks_cover == NULL) { fprintf(stderr, "error: stacks cover == NULL, n_frames=%d\n", n_frames); goto get_snapshot_fail_attached; } /* * copy memory contents */ rc = use_process_vm_readv ? copy_memory_process_vm_readv(pid, stacks_cover, n_frames) : copy_memory_proc_mem(pid, stacks_cover, n_frames); if (rc < 0) goto get_snapshot_fail_attached; /* UNFREEZE PROCESS */ if (detach_process(pid) < 0) goto get_snapshot_fail; if (opt_verbose) { for (i = 0; i < n_frames; ++i) { struct mem_data_chunk *chunk = stacks_cover[i]; printf("chunk #%d: 0x%lx-0x%lx length: %ldK\n", i, (size_t)chunk->start, (size_t)chunk->start + chunk->length, chunk->length >> 10); } } free(stacks_cover); return res; get_snapshot_fail_attached: if (attached_tid) detach_thread(attached_tid); detach_process(pid); get_snapshot_fail: if (opt_verbose) { fprintf(stderr, "maps of %d:\n", pid); print_proc_maps(pid); } free(stacks_cover); snapshot_destroy(res); return NULL; }