void subsegs_print_statistics (FILE *file) { frchainS *frchp; asection *s; fprintf (file, "frag chains:\n"); for (s = stdoutput->sections; s; s = s->next) { segment_info_type *seginfo; /* Skip gas-internal sections. */ if (segment_name (s)[0] == '*') continue; seginfo = seg_info (s); if (!seginfo) continue; for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next) { int count = 0; fragS *fragp; for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) count++; fprintf (file, "\n"); fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp, segment_name (s), count); } } }
static void out_debug_line (segT line_seg) { expressionS exp; symbolS *prologue_end; symbolS *line_end; struct line_seg *s; int sizeof_offset; sizeof_offset = out_header (line_seg, &exp); line_end = exp.X_add_symbol; /* Version. */ out_two (DWARF2_VERSION); /* Length of the prologue following this length. */ prologue_end = symbol_temp_make (); exp.X_add_symbol = prologue_end; exp.X_add_number = - (4 + 2 + 4); emit_expr (&exp, sizeof_offset); /* Parameters of the state machine. */ out_byte (DWARF2_LINE_MIN_INSN_LENGTH); out_byte (DWARF2_LINE_DEFAULT_IS_STMT); out_byte (DWARF2_LINE_BASE); out_byte (DWARF2_LINE_RANGE); out_byte (DWARF2_LINE_OPCODE_BASE); /* Standard opcode lengths. */ out_byte (0); /* DW_LNS_copy */ out_byte (1); /* DW_LNS_advance_pc */ out_byte (1); /* DW_LNS_advance_line */ out_byte (1); /* DW_LNS_set_file */ out_byte (1); /* DW_LNS_set_column */ out_byte (0); /* DW_LNS_negate_stmt */ out_byte (0); /* DW_LNS_set_basic_block */ out_byte (0); /* DW_LNS_const_add_pc */ out_byte (1); /* DW_LNS_fixed_advance_pc */ out_byte (0); /* DW_LNS_set_prologue_end */ out_byte (0); /* DW_LNS_set_epilogue_begin */ out_byte (1); /* DW_LNS_set_isa */ out_file_list (); symbol_set_value_now (prologue_end); /* For each section, emit a statement program. */ for (s = all_segs; s; s = s->next) if (SEG_NORMAL (s->seg)) process_entries (s->seg, s->head->head); else as_warn ("dwarf line number information for %s ignored", segment_name (s->seg)); symbol_set_value_now (line_end); }
int pa_shm_attach(pa_shm *m, unsigned id, bool writable) { char fn[32]; int fd = -1; int prot; struct stat st; pa_assert(m); segment_name(fn, sizeof(fn), m->id = id); if ((fd = shm_open(fn, writable ? O_RDWR : O_RDONLY, 0)) < 0) { if (errno != EACCES && errno != ENOENT) pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } if (fstat(fd, &st) < 0) { pa_log("fstat() failed: %s", pa_cstrerror(errno)); goto fail; } if (st.st_size <= 0 || st.st_size > (off_t) (MAX_SHM_SIZE+SHM_MARKER_SIZE) || PA_ALIGN((size_t) st.st_size) != (size_t) st.st_size) { pa_log("Invalid shared memory segment size"); goto fail; } m->size = (size_t) st.st_size; prot = writable ? PROT_READ | PROT_WRITE : PROT_READ; if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), prot, MAP_SHARED, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } m->do_unlink = false; m->shared = true; pa_assert_se(pa_close(fd) == 0); return 0; fail: if (fd >= 0) pa_close(fd); return -1; }
int pa_shm_attach_ro(pa_shm *m, unsigned id) { char fn[32]; int fd = -1; struct stat st; pa_assert(m); segment_name(fn, sizeof(fn), m->id = id); if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) { if (errno != EACCES) pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } if (fstat(fd, &st) < 0) { pa_log("fstat() failed: %s", pa_cstrerror(errno)); goto fail; } if (st.st_size <= 0 || st.st_size > (off_t) (MAX_SHM_SIZE+SHM_MARKER_SIZE) || PA_ALIGN((size_t) st.st_size) != (size_t) st.st_size) { pa_log("Invalid shared memory segment size"); goto fail; } m->size = (size_t) st.st_size; if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ, MAP_SHARED, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } m->do_unlink = FALSE; m->shared = TRUE; pa_assert_se(pa_close(fd) == 0); return 0; fail: if (fd >= 0) pa_close(fd); return -1; }
void pa_shm_free(pa_shm *m) { pa_assert(m); pa_assert(m->ptr); pa_assert(m->size > 0); #ifdef MAP_FAILED pa_assert(m->ptr != MAP_FAILED); #endif if (m->type == PA_MEM_TYPE_PRIVATE) { privatemem_free(m); goto finish; } #if defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) if (munmap(m->ptr, PA_PAGE_ALIGN(m->size)) < 0) pa_log("munmap() failed: %s", pa_cstrerror(errno)); #ifdef HAVE_SHM_OPEN if (m->type == PA_MEM_TYPE_SHARED_POSIX && m->do_unlink) { char fn[32]; segment_name(fn, sizeof(fn), m->id); if (shm_unlink(fn) < 0) pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); } #endif #ifdef HAVE_MEMFD if (m->type == PA_MEM_TYPE_SHARED_MEMFD && m->fd != -1) pa_assert_se(pa_close(m->fd) == 0); #endif #else /* We shouldn't be here without shm or memfd support */ pa_assert_not_reached(); #endif finish: pa_zero(*m); }
void pa_shm_free(pa_shm *m) { pa_assert(m); pa_assert(m->ptr); pa_assert(m->size > 0); #ifdef MAP_FAILED pa_assert(m->ptr != MAP_FAILED); #endif if (!m->shared) { #ifdef MAP_ANONYMOUS if (munmap(m->ptr, m->size) < 0) pa_log("munmap() failed: %s", pa_cstrerror(errno)); #elif defined(HAVE_POSIX_MEMALIGN) free(m->ptr); #else pa_xfree(m->ptr); #endif } else { #ifdef HAVE_SHM_OPEN if (munmap(m->ptr, PA_PAGE_ALIGN(m->size)) < 0) pa_log("munmap() failed: %s", pa_cstrerror(errno)); if (m->do_unlink) { char fn[32]; segment_name(fn, sizeof(fn), m->id); if (shm_unlink(fn) < 0) pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno)); } #else /* We shouldn't be here without shm support */ pa_assert_not_reached(); #endif } pa_zero(*m); }
int pa_shm_cleanup(void) { #ifdef HAVE_SHM_OPEN #ifdef SHM_PATH DIR *d; struct dirent *de; if (!(d = opendir(SHM_PATH))) { pa_log_warn("Failed to read "SHM_PATH": %s", pa_cstrerror(errno)); return -1; } while ((de = readdir(d))) { pa_shm seg; unsigned id; pid_t pid; char fn[128]; struct shm_marker *m; #if defined(__sun) if (strncmp(de->d_name, ".SHMDpulse-shm-", SHM_ID_LEN)) #else if (strncmp(de->d_name, "pulse-shm-", SHM_ID_LEN)) #endif continue; if (pa_atou(de->d_name + SHM_ID_LEN, &id) < 0) continue; if (pa_shm_attach(&seg, id, false) < 0) continue; if (seg.size < SHM_MARKER_SIZE) { pa_shm_free(&seg); continue; } m = (struct shm_marker*) ((uint8_t*) seg.ptr + seg.size - SHM_MARKER_SIZE); if (pa_atomic_load(&m->marker) != SHM_MARKER) { pa_shm_free(&seg); continue; } if (!(pid = (pid_t) pa_atomic_load(&m->pid))) { pa_shm_free(&seg); continue; } if (kill(pid, 0) == 0 || errno != ESRCH) { pa_shm_free(&seg); continue; } pa_shm_free(&seg); /* Ok, the owner of this shms segment is dead, so, let's remove the segment */ segment_name(fn, sizeof(fn), id); if (shm_unlink(fn) < 0 && errno != EACCES && errno != ENOENT) pa_log_warn("Failed to remove SHM segment %s: %s\n", fn, pa_cstrerror(errno)); } closedir(d); #endif /* SHM_PATH */ #endif /* HAVE_SHM_OPEN */ return 0; }
int pa_shm_create_rw(pa_shm *m, size_t size, bool shared, mode_t mode) { #ifdef HAVE_SHM_OPEN char fn[32]; int fd = -1; #endif pa_assert(m); pa_assert(size > 0); pa_assert(size <= MAX_SHM_SIZE); pa_assert(!(mode & ~0777)); pa_assert(mode >= 0600); /* Each time we create a new SHM area, let's first drop all stale * ones */ pa_shm_cleanup(); /* Round up to make it page aligned */ size = PA_PAGE_ALIGN(size); if (!shared) { m->id = 0; m->size = size; #ifdef MAP_ANONYMOUS if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } #elif defined(HAVE_POSIX_MEMALIGN) { int r; if ((r = posix_memalign(&m->ptr, PA_PAGE_SIZE, size)) < 0) { pa_log("posix_memalign() failed: %s", pa_cstrerror(r)); goto fail; } } #else m->ptr = pa_xmalloc(m->size); #endif m->do_unlink = false; } else { #ifdef HAVE_SHM_OPEN struct shm_marker *marker; pa_random(&m->id, sizeof(m->id)); segment_name(fn, sizeof(fn), m->id); if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode)) < 0) { pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } m->size = size + SHM_MARKER_SIZE; if (ftruncate(fd, (off_t) m->size) < 0) { pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } /* We store our PID at the end of the shm block, so that we * can check for dead shm segments later */ marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - SHM_MARKER_SIZE); pa_atomic_store(&marker->pid, (int) getpid()); pa_atomic_store(&marker->marker, SHM_MARKER); pa_assert_se(pa_close(fd) == 0); m->do_unlink = true; #else goto fail; #endif } m->shared = shared; return 0; fail: #ifdef HAVE_SHM_OPEN if (fd >= 0) { shm_unlink(fn); pa_close(fd); } #endif return -1; }
static void list_symbol_table (void) { extern symbolS *symbol_rootP; int got_some = 0; symbolS *ptr; eject = 1; listing_page (NULL); for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) { if (SEG_NORMAL (S_GET_SEGMENT (ptr)) || S_GET_SEGMENT (ptr) == absolute_section) { /* Don't report section symbols. They are not interesting. */ if (symbol_section_p (ptr)) continue; if (S_GET_NAME (ptr)) { char buf[30], fmt[8]; valueT val = S_GET_VALUE (ptr); /* @@ Note that this is dependent on the compilation options, not solely on the target characteristics. */ if (sizeof (val) == 4 && sizeof (int) == 4) sprintf (buf, "%08lx", (unsigned long) val); else if (sizeof (val) <= sizeof (unsigned long)) { sprintf (fmt, "%%0%lulx", (unsigned long) (sizeof (val) * 2)); sprintf (buf, fmt, (unsigned long) val); } #if defined (BFD64) else if (sizeof (val) > 4) sprintf_vma (buf, val); #endif else abort (); if (!got_some) { fprintf (list_file, "DEFINED SYMBOLS\n"); on_page++; got_some = 1; } if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line) { fprintf (list_file, "%20s:%-5d %s:%s %s\n", symbol_get_frag (ptr)->line->file->filename, symbol_get_frag (ptr)->line->line, segment_name (S_GET_SEGMENT (ptr)), buf, S_GET_NAME (ptr)); } else { fprintf (list_file, "%33s:%s %s\n", segment_name (S_GET_SEGMENT (ptr)), buf, S_GET_NAME (ptr)); } on_page++; listing_page (NULL); } } } if (!got_some) { fprintf (list_file, "NO DEFINED SYMBOLS\n"); on_page++; } emit_line (NULL, "\n"); got_some = 0; for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) { if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0) { if (S_GET_SEGMENT (ptr) == undefined_section) { if (!got_some) { got_some = 1; emit_line (NULL, "UNDEFINED SYMBOLS\n"); } emit_line (NULL, "%s\n", S_GET_NAME (ptr)); } } } if (!got_some) emit_line (NULL, "NO UNDEFINED SYMBOLS\n"); }
void listing_newline (char *ps) { char *file; unsigned int line; static unsigned int last_line = 0xffff; static char *last_file = NULL; list_info_type *new_i = NULL; if (listing == 0) return; if (now_seg == absolute_section) return; #ifdef OBJ_ELF /* In ELF, anything in a section beginning with .debug or .line is considered to be debugging information. This includes the statement which switches us into the debugging section, which we can only set after we are already in the debugging section. */ if ((listing & LISTING_NODEBUG) != 0 && listing_tail != NULL && ! listing_tail->debugging) { const char *segname; segname = segment_name (now_seg); if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0 || strncmp (segname, ".line", sizeof ".line" - 1) == 0) listing_tail->debugging = 1; } #endif as_where (&file, &line); if (ps == NULL) { if (line == last_line && !(last_file && file && filename_cmp (file, last_file))) return; new_i = (list_info_type *) xmalloc (sizeof (list_info_type)); /* Detect if we are reading from stdin by examining the file name returned by as_where(). [FIXME: We rely upon the name in the strcmp below being the same as the one used by input_scrub_new_file(), if that is not true, then this code will fail]. If we are reading from stdin, then we need to save each input line here (assuming of course that we actually have a line of input to read), so that it can be displayed in the listing that is produced at the end of the assembly. */ if (strcmp (file, _("{standard input}")) == 0 && input_line_pointer != NULL) { char *copy; int len; int seen_quote = 0; int seen_slash = 0; for (copy = input_line_pointer; *copy && (seen_quote || is_end_of_line [(unsigned char) *copy] != 1); copy++) { if (seen_slash) seen_slash = 0; else if (*copy == '\\') seen_slash = 1; else if (*copy == '"') seen_quote = !seen_quote; } len = copy - input_line_pointer + 1; copy = (char *) xmalloc (len); if (copy != NULL) { char *src = input_line_pointer; char *dest = copy; while (--len) { unsigned char c = *src++; /* Omit control characters in the listing. */ if (!ISCNTRL (c)) *dest++ = c; } *dest = 0; } new_i->line_contents = copy; } else new_i->line_contents = NULL; } else { new_i = (list_info_type *) xmalloc (sizeof (list_info_type)); new_i->line_contents = ps; } last_line = line; last_file = file; new_frag (); if (listing_tail) listing_tail->next = new_i; else head = new_i; listing_tail = new_i; new_i->frag = frag_now; new_i->line = line; new_i->file = file_info (file); new_i->next = (list_info_type *) NULL; new_i->messages = NULL; new_i->last_message = NULL; new_i->edict = EDICT_NONE; new_i->hll_file = (file_info_type *) NULL; new_i->hll_line = 0; new_i->debugging = 0; new_frag (); #ifdef OBJ_ELF /* In ELF, anything in a section beginning with .debug or .line is considered to be debugging information. */ if ((listing & LISTING_NODEBUG) != 0) { const char *segname; segname = segment_name (now_seg); if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0 || strncmp (segname, ".line", sizeof ".line" - 1) == 0) new_i->debugging = 1; } #endif }
int check_eh_frame (expressionS *exp, unsigned int *pnbytes) { struct frame_data { enum frame_state state; int cie_info_ok; struct cie_info cie_info; symbolS *size_end_sym; fragS *loc4_frag; int loc4_fix; int aug_size; int aug_shift; }; static struct frame_data eh_frame_data; static struct frame_data debug_frame_data; struct frame_data *d; /* Don't optimize. */ if (flag_traditional_format) return 0; #ifdef md_allow_eh_opt if (! md_allow_eh_opt) return 0; #endif /* Select the proper section data. */ if (strncmp (segment_name (now_seg), ".eh_frame", 9) == 0 && segment_name (now_seg)[9] != '_') d = &eh_frame_data; else if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0) d = &debug_frame_data; else return 0; if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym)) { /* We have come to the end of the CIE or FDE. See below where we set saw_size. We must check this first because we may now be looking at the next size. */ d->state = state_idle; } switch (d->state) { case state_idle: if (*pnbytes == 4) { /* This might be the size of the CIE or FDE. We want to know the size so that we don't accidentally optimize across an FDE boundary. We recognize the size in one of two forms: a symbol which will later be defined as a difference, or a subtraction of two symbols. Either way, we can tell when we are at the end of the FDE because the symbol becomes defined (in the case of a subtraction, the end symbol, from which the start symbol is being subtracted). Other ways of describing the size will not be optimized. */ if ((exp->X_op == O_symbol || exp->X_op == O_subtract) && ! S_IS_DEFINED (exp->X_add_symbol)) { d->state = state_saw_size; d->size_end_sym = exp->X_add_symbol; } } break; case state_saw_size: case state_saw_cie_offset: /* Assume whatever form it appears in, it appears atomically. */ d->state = (enum frame_state) (d->state + 1); break; case state_saw_pc_begin: /* Decide whether we should see an augmentation. */ if (! d->cie_info_ok && ! (d->cie_info_ok = get_cie_info (&d->cie_info))) d->state = state_error; else if (d->cie_info.z_augmentation) { d->state = state_seeing_aug_size; d->aug_size = 0; d->aug_shift = 0; } else d->state = state_wait_loc4; break; case state_seeing_aug_size: /* Bytes == -1 means this comes from an leb128 directive. */ if ((int)*pnbytes == -1 && exp->X_op == O_constant) { d->aug_size = exp->X_add_number; d->state = state_skipping_aug; } else if (*pnbytes == 1 && exp->X_op == O_constant) { unsigned char byte = exp->X_add_number; d->aug_size |= (byte & 0x7f) << d->aug_shift; d->aug_shift += 7; if ((byte & 0x80) == 0) d->state = state_skipping_aug; } else d->state = state_error; if (d->state == state_skipping_aug && d->aug_size == 0) d->state = state_wait_loc4; break; case state_skipping_aug: if ((int)*pnbytes < 0) d->state = state_error; else { int left = (d->aug_size -= *pnbytes); if (left == 0) d->state = state_wait_loc4; else if (left < 0) d->state = state_error; } break; case state_wait_loc4: if (*pnbytes == 1 && exp->X_op == O_constant && exp->X_add_number == DW_CFA_advance_loc4) { /* This might be a DW_CFA_advance_loc4. Record the frag and the position within the frag, so that we can change it later. */ frag_grow (1); d->state = state_saw_loc4; d->loc4_frag = frag_now; d->loc4_fix = frag_now_fix (); } break; case state_saw_loc4: d->state = state_wait_loc4; if (*pnbytes != 4) break; if (exp->X_op == O_constant) { /* This is a case which we can optimize. The two symbols being subtracted were in the same frag and the expression was reduced to a constant. We can do the optimization entirely in this function. */ if (exp->X_add_number < 0x40) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc | exp->X_add_number; /* No more bytes needed. */ return 1; } else if (exp->X_add_number < 0x100) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; *pnbytes = 1; } else if (exp->X_add_number < 0x10000) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; *pnbytes = 2; } } else if (exp->X_op == O_subtract && d->cie_info.code_alignment == 1) { /* This is a case we can optimize. The expression was not reduced, so we can not finish the optimization until the end of the assembly. We set up a variant frag which we handle later. */ frag_var (rs_cfa, 4, 0, 1 << 3, make_expr_symbol (exp), d->loc4_fix, (char *) d->loc4_frag); return 1; } else if ((exp->X_op == O_divide || exp->X_op == O_right_shift) && d->cie_info.code_alignment > 1) { if (symbol_symbolS (exp->X_add_symbol) && symbol_constant_p (exp->X_op_symbol) && S_GET_SEGMENT (exp->X_op_symbol) == absolute_section && ((exp->X_op == O_divide ? *symbol_X_add_number (exp->X_op_symbol) : (offsetT) 1 << *symbol_X_add_number (exp->X_op_symbol)) == (offsetT) d->cie_info.code_alignment)) { expressionS *symval; symval = symbol_get_value_expression (exp->X_add_symbol); if (symval->X_op == O_subtract) { /* This is a case we can optimize as well. The expression was not reduced, so we can not finish the optimization until the end of the assembly. We set up a variant frag which we handle later. */ frag_var (rs_cfa, 4, 0, d->cie_info.code_alignment << 3, make_expr_symbol (symval), d->loc4_fix, (char *) d->loc4_frag); return 1; } } } break; case state_error: /* Just skipping everything. */ break; } return 0; }
static int get_cie_info (struct cie_info *info) { fragS *f; fixS *fix; int offset; char CIE_id; char augmentation[10]; int iaug; int code_alignment = 0; /* We should find the CIE at the start of the section. */ f = seg_info (now_seg)->frchainP->frch_root; fix = seg_info (now_seg)->frchainP->fix_root; /* Look through the frags of the section to find the code alignment. */ /* First make sure that the CIE Identifier Tag is 0/-1. */ if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0) CIE_id = (char)0xff; else CIE_id = 0; offset = 4; while (f != NULL && offset >= f->fr_fix) { offset -= f->fr_fix; f = f->fr_next; } if (f == NULL || f->fr_fix - offset < 4 || f->fr_literal[offset] != CIE_id || f->fr_literal[offset + 1] != CIE_id || f->fr_literal[offset + 2] != CIE_id || f->fr_literal[offset + 3] != CIE_id) return 0; /* Next make sure the CIE version number is 1. */ offset += 4; while (f != NULL && offset >= f->fr_fix) { offset -= f->fr_fix; f = f->fr_next; } if (f == NULL || f->fr_fix - offset < 1 || f->fr_literal[offset] != 1) return 0; /* Skip the augmentation (a null terminated string). */ iaug = 0; ++offset; while (1) { while (f != NULL && offset >= f->fr_fix) { offset -= f->fr_fix; f = f->fr_next; } if (f == NULL) return 0; while (offset < f->fr_fix && f->fr_literal[offset] != '\0') { if ((size_t) iaug < (sizeof augmentation) - 1) { augmentation[iaug] = f->fr_literal[offset]; ++iaug; } ++offset; } if (offset < f->fr_fix) break; } ++offset; while (f != NULL && offset >= f->fr_fix) { offset -= f->fr_fix; f = f->fr_next; } if (f == NULL) return 0; augmentation[iaug] = '\0'; if (augmentation[0] == '\0') { /* No augmentation. */ } else if (strcmp (augmentation, "eh") == 0) { /* We have to skip a pointer. Unfortunately, we don't know how large it is. We find out by looking for a matching fixup. */ while (fix != NULL && (fix->fx_frag != f || fix->fx_where != offset)) fix = fix->fx_next; if (fix == NULL) offset += 4; else offset += fix->fx_size; while (f != NULL && offset >= f->fr_fix) { offset -= f->fr_fix; f = f->fr_next; } if (f == NULL) return 0; } else if (augmentation[0] != 'z') return 0; /* We're now at the code alignment factor, which is a ULEB128. If it isn't a single byte, forget it. */ code_alignment = f->fr_literal[offset] & 0xff; if ((code_alignment & 0x80) != 0) code_alignment = 0; info->code_alignment = code_alignment; info->z_augmentation = (augmentation[0] == 'z'); return 1; }
static int shm_attach(pa_shm *m, pa_mem_type_t type, unsigned id, int memfd_fd, bool writable, bool for_cleanup) { #if defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) char fn[32]; int fd = -1; int prot; struct stat st; pa_assert(m); switch (type) { #ifdef HAVE_SHM_OPEN case PA_MEM_TYPE_SHARED_POSIX: pa_assert(memfd_fd == -1); segment_name(fn, sizeof(fn), id); if ((fd = shm_open(fn, writable ? O_RDWR : O_RDONLY, 0)) < 0) { if ((errno != EACCES && errno != ENOENT) || !for_cleanup) pa_log("shm_open() failed: %s", pa_cstrerror(errno)); goto fail; } break; #endif #ifdef HAVE_MEMFD case PA_MEM_TYPE_SHARED_MEMFD: pa_assert(memfd_fd != -1); fd = memfd_fd; break; #endif default: goto fail; } if (fstat(fd, &st) < 0) { pa_log("fstat() failed: %s", pa_cstrerror(errno)); goto fail; } if (st.st_size <= 0 || st.st_size > (off_t) MAX_SHM_SIZE + (off_t) shm_marker_size(type) || PA_ALIGN((size_t) st.st_size) != (size_t) st.st_size) { pa_log("Invalid shared memory segment size"); goto fail; } prot = writable ? PROT_READ | PROT_WRITE : PROT_READ; if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(st.st_size), prot, MAP_SHARED, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } /* In case of attaching to memfd areas, _the caller_ maintains * ownership of the passed fd and has the sole responsibility * of closing it down.. For other types, we're the code path * which created the fd in the first place and we're thus the * ones responsible for closing it down */ if (type != PA_MEM_TYPE_SHARED_MEMFD) pa_assert_se(pa_close(fd) == 0); m->type = type; m->id = id; m->size = (size_t) st.st_size; m->do_unlink = false; m->fd = -1; return 0; fail: /* In case of memfds, caller maintains fd ownership */ if (fd >= 0 && type != PA_MEM_TYPE_SHARED_MEMFD) pa_close(fd); #endif /* defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) */ return -1; }
static int sharedmem_create(pa_shm *m, pa_mem_type_t type, size_t size, mode_t mode) { #if defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) char fn[32]; int fd = -1; struct shm_marker *marker; bool do_unlink = false; /* Each time we create a new SHM area, let's first drop all stale * ones */ pa_shm_cleanup(); pa_random(&m->id, sizeof(m->id)); switch (type) { #ifdef HAVE_SHM_OPEN case PA_MEM_TYPE_SHARED_POSIX: segment_name(fn, sizeof(fn), m->id); fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode); do_unlink = true; break; #endif #ifdef HAVE_MEMFD case PA_MEM_TYPE_SHARED_MEMFD: fd = memfd_create("pulseaudio", MFD_ALLOW_SEALING); break; #endif default: goto fail; } if (fd < 0) { pa_log("%s open() failed: %s", pa_mem_type_to_string(type), pa_cstrerror(errno)); goto fail; } m->type = type; m->size = size + shm_marker_size(type); m->do_unlink = do_unlink; if (ftruncate(fd, (off_t) m->size) < 0) { pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } if (type == PA_MEM_TYPE_SHARED_POSIX) { /* We store our PID at the end of the shm block, so that we * can check for dead shm segments later */ marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - shm_marker_size(type)); pa_atomic_store(&marker->pid, (int) getpid()); pa_atomic_store(&marker->marker, SHM_MARKER); } /* For memfds, we keep the fd open until we pass it * to the other PA endpoint over unix domain socket. */ if (type == PA_MEM_TYPE_SHARED_MEMFD) m->fd = fd; else { pa_assert_se(pa_close(fd) == 0); m->fd = -1; } return 0; fail: if (fd >= 0) { #ifdef HAVE_SHM_OPEN if (type == PA_MEM_TYPE_SHARED_POSIX) shm_unlink(fn); #endif pa_close(fd); } #endif /* defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) */ return -1; }