diff options
Diffstat (limited to 'libctf/ctf-serialize.c')
-rw-r--r-- | libctf/ctf-serialize.c | 334 |
1 files changed, 105 insertions, 229 deletions
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c index 82e5b7d..2d1f014 100644 --- a/libctf/ctf-serialize.c +++ b/libctf/ctf-serialize.c @@ -470,9 +470,9 @@ ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s, filter out reported symbols from the variable section, and filter out all other symbols from the symtypetab sections. (If we are not linking, the symbols are sorted; if we are linking, don't bother sorting if we are not - filtering out reported symbols: this is almost certaily an ld -r and only + filtering out reported symbols: this is almost certainly an ld -r and only the linker is likely to consume these symtypetabs again. The linker - doesn't care what order the symtypetab entries is in, since it only + doesn't care what order the symtypetab entries are in, since it only iterates over symbols and does not use the ctf_lookup_by_symbol* API.) */ s->sort_syms = 1; @@ -718,8 +718,8 @@ symerr: /* Type section. */ -/* Iterate through the dynamic type definition list and compute the - size of the CTF type section. */ +/* Iterate through the static types and the dynamic type definition list and + compute the size of the CTF type section. */ static size_t ctf_type_sect_size (ctf_dict_t *fp) @@ -778,7 +778,7 @@ ctf_type_sect_size (ctf_dict_t *fp) } } - return type_size; + return type_size + fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff; } /* Take a final lap through the dynamic type definition list and copy the @@ -933,30 +933,22 @@ ctf_sort_var (const void *one_, const void *two_, void *arg_) /* Overall serialization. */ -/* If the specified CTF dict is writable and has been modified, reload this dict - with the updated type definitions, ready for serialization. In order to make - this code and the rest of libctf as simple as possible, we perform updates by - taking the dynamic type definitions and creating an in-memory CTF dict - containing the definitions, and then call ctf_simple_open_internal() on it. - We perform one extra trick here for the benefit of callers and to keep our - code simple: ctf_simple_open_internal() will return a new ctf_dict_t, but we - want to keep the fp constant for the caller, so after - ctf_simple_open_internal() returns, we use memcpy to swap the interior of the - old and new ctf_dict_t's, and then free the old. - - We do not currently support serializing a dict that has already been - serialized in the past: but all the tables support it except for the types - table. */ +/* Emit a new CTF dict which is a serialized copy of this one: also reify + the string table and update all offsets in the current dict suitably. + (This simplifies ctf-string.c a little, at the cost of storing a second + copy of the strtab if this dict was originally read in via ctf_open.) -int -ctf_serialize (ctf_dict_t *fp) + Other aspects of the existing dict are unchanged, although some + static entries may be duplicated in the dynamic state (which should + have no effect on visible operation). */ + +static unsigned char * +ctf_serialize (ctf_dict_t *fp, size_t *bufsiz) { - ctf_dict_t ofp, *nfp; ctf_header_t hdr, *hdrp; ctf_dvdef_t *dvd; ctf_varent_t *dvarents; const ctf_strs_writable_t *strtab; - int err; int sym_functions = 0; unsigned char *t; @@ -969,13 +961,6 @@ ctf_serialize (ctf_dict_t *fp) emit_symtypetab_state_t symstate; memset (&symstate, 0, sizeof (emit_symtypetab_state_t)); - /* This isn't a very nice error code, but it's close enough: it's what you - get if you try to modify a type loaded out of a serialized dict, so - it makes at least a little sense that it's what you get if you try to - reserialize the dict again. */ - if (fp->ctf_stypes > 0) - return (ctf_set_errno (fp, ECTF_RDONLY)); - /* Fill in an initial CTF header. We will leave the label, object, and function sections empty and only output a header, type section, and string table. The type section begins at a 4-byte aligned @@ -993,7 +978,7 @@ ctf_serialize (ctf_dict_t *fp) /* Propagate all symbols in the symtypetabs into the dynamic state, so that we can put them back in the right order. Symbols already in the dynamic - state are left as they are. */ + state, likely due to repeated serialization, are left unchanged. */ do { ctf_next_t *it = NULL; @@ -1004,17 +989,17 @@ ctf_serialize (ctf_dict_t *fp) sym_functions)) != CTF_ERR) if ((ctf_add_funcobjt_sym_forced (fp, sym_functions, sym_name, sym)) < 0) if (ctf_errno (fp) != ECTF_DUPLICATE) - return -1; /* errno is set for us. */ + return NULL; /* errno is set for us. */ if (ctf_errno (fp) != ECTF_NEXT_END) - return -1; /* errno is set for us. */ + return NULL; /* errno is set for us. */ } while (sym_functions++ < 1); /* Figure out how big the symtypetabs are now. */ if (ctf_symtypetab_sect_sizes (fp, &symstate, &hdr, &objt_size, &func_size, &objtidx_size, &funcidx_size) < 0) - return -1; /* errno is set for us. */ + return NULL; /* errno is set for us. */ /* Propagate all vars into the dynamic state, so we can put them back later. Variables already in the dynamic state, likely due to repeated @@ -1026,7 +1011,7 @@ ctf_serialize (ctf_dict_t *fp) if (name != NULL && !ctf_dvd_lookup (fp, name)) if (ctf_add_variable_forced (fp, name, fp->ctf_vars[i].ctv_type) < 0) - return -1; /* errno is set for us. */ + return NULL; /* errno is set for us. */ } for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); @@ -1050,7 +1035,10 @@ ctf_serialize (ctf_dict_t *fp) buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; if ((buf = malloc (buf_size)) == NULL) - return (ctf_set_errno (fp, EAGAIN)); + { + ctf_set_errno (fp, EAGAIN); + return NULL; + } memcpy (buf, &hdr, sizeof (ctf_header_t)); t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff; @@ -1085,6 +1073,11 @@ ctf_serialize (ctf_dict_t *fp) assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff); + /* Copy in existing static types, then emit new dynamic types. */ + + memcpy (t, fp->ctf_buf + fp->ctf_header->cth_typeoff, + fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff); + t += fp->ctf_header->cth_stroff - fp->ctf_header->cth_typeoff; ctf_emit_type_sect (fp, &t); assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff); @@ -1111,136 +1104,15 @@ ctf_serialize (ctf_dict_t *fp) hdrp = (ctf_header_t *) buf; hdrp->cth_strlen = strtab->cts_len; buf_size += hdrp->cth_strlen; + *bufsiz = buf_size; - /* Finally, we are ready to ctf_simple_open() the new dict. If this is - successful, we then switch nfp and fp and free the old dict. */ - - if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0, - 0, NULL, 0, fp->ctf_syn_ext_strtab, - fp->ctf_str_atoms, &err)) == NULL) - { - free (buf); - return (ctf_set_errno (fp, err)); - } - - (void) ctf_setmodel (nfp, ctf_getmodel (fp)); - - nfp->ctf_parent = fp->ctf_parent; - nfp->ctf_parent_unreffed = fp->ctf_parent_unreffed; - nfp->ctf_refcnt = fp->ctf_refcnt; - if (nfp->ctf_dynbase == NULL) - nfp->ctf_dynbase = buf; /* Make sure buf is freed on close. */ - nfp->ctf_dthash = fp->ctf_dthash; - nfp->ctf_dtdefs = fp->ctf_dtdefs; - nfp->ctf_dvhash = fp->ctf_dvhash; - nfp->ctf_dvdefs = fp->ctf_dvdefs; - nfp->ctf_dtoldid = fp->ctf_dtoldid; - nfp->ctf_add_processing = fp->ctf_add_processing; - nfp->ctf_snapshots = fp->ctf_snapshots + 1; - nfp->ctf_specific = fp->ctf_specific; - nfp->ctf_nfuncidx = fp->ctf_nfuncidx; - nfp->ctf_nobjtidx = fp->ctf_nobjtidx; - nfp->ctf_objthash = fp->ctf_objthash; - nfp->ctf_funchash = fp->ctf_funchash; - nfp->ctf_dynsyms = fp->ctf_dynsyms; - nfp->ctf_ptrtab = fp->ctf_ptrtab; - nfp->ctf_pptrtab = fp->ctf_pptrtab; - nfp->ctf_typemax = fp->ctf_typemax; - nfp->ctf_stypes = fp->ctf_stypes; - nfp->ctf_dynsymidx = fp->ctf_dynsymidx; - nfp->ctf_dynsymmax = fp->ctf_dynsymmax; - nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len; - nfp->ctf_pptrtab_len = fp->ctf_pptrtab_len; - nfp->ctf_link_inputs = fp->ctf_link_inputs; - nfp->ctf_link_outputs = fp->ctf_link_outputs; - nfp->ctf_errs_warnings = fp->ctf_errs_warnings; - nfp->ctf_funcidx_names = fp->ctf_funcidx_names; - nfp->ctf_objtidx_names = fp->ctf_objtidx_names; - nfp->ctf_funcidx_sxlate = fp->ctf_funcidx_sxlate; - nfp->ctf_objtidx_sxlate = fp->ctf_objtidx_sxlate; - nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset; - nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab; - nfp->ctf_pptrtab_typemax = fp->ctf_pptrtab_typemax; - nfp->ctf_in_flight_dynsyms = fp->ctf_in_flight_dynsyms; - nfp->ctf_link_in_cu_mapping = fp->ctf_link_in_cu_mapping; - nfp->ctf_link_out_cu_mapping = fp->ctf_link_out_cu_mapping; - nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping; - nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer; - nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg; - nfp->ctf_link_variable_filter = fp->ctf_link_variable_filter; - nfp->ctf_link_variable_filter_arg = fp->ctf_link_variable_filter_arg; - nfp->ctf_symsect_little_endian = fp->ctf_symsect_little_endian; - nfp->ctf_link_flags = fp->ctf_link_flags; - nfp->ctf_dedup_atoms = fp->ctf_dedup_atoms; - nfp->ctf_dedup_atoms_alloc = fp->ctf_dedup_atoms_alloc; - memcpy (&nfp->ctf_dedup, &fp->ctf_dedup, sizeof (fp->ctf_dedup)); - - nfp->ctf_snapshot_lu = fp->ctf_snapshots; - - memcpy (&nfp->ctf_lookups, fp->ctf_lookups, sizeof (fp->ctf_lookups)); - nfp->ctf_structs = fp->ctf_structs; - nfp->ctf_unions = fp->ctf_unions; - nfp->ctf_enums = fp->ctf_enums; - nfp->ctf_names = fp->ctf_names; - - fp->ctf_dthash = NULL; - ctf_str_free_atoms (nfp); - nfp->ctf_str_atoms = fp->ctf_str_atoms; - nfp->ctf_prov_strtab = fp->ctf_prov_strtab; - nfp->ctf_dynstrtab = fp->ctf_dynstrtab; - nfp->ctf_str_movable_refs = fp->ctf_str_movable_refs; - fp->ctf_str_atoms = NULL; - fp->ctf_prov_strtab = NULL; - fp->ctf_dynstrtab = NULL; - fp->ctf_str_movable_refs = NULL; - memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t)); - memset (&fp->ctf_errs_warnings, 0, sizeof (ctf_list_t)); - fp->ctf_add_processing = NULL; - fp->ctf_ptrtab = NULL; - fp->ctf_pptrtab = NULL; - fp->ctf_funcidx_names = NULL; - fp->ctf_objtidx_names = NULL; - fp->ctf_funcidx_sxlate = NULL; - fp->ctf_objtidx_sxlate = NULL; - fp->ctf_objthash = NULL; - fp->ctf_funchash = NULL; - fp->ctf_dynsyms = NULL; - fp->ctf_dynsymidx = NULL; - fp->ctf_link_inputs = NULL; - fp->ctf_link_outputs = NULL; - fp->ctf_syn_ext_strtab = NULL; - fp->ctf_link_in_cu_mapping = NULL; - fp->ctf_link_out_cu_mapping = NULL; - fp->ctf_link_type_mapping = NULL; - fp->ctf_dedup_atoms = NULL; - fp->ctf_dedup_atoms_alloc = NULL; - fp->ctf_parent_unreffed = 1; - - fp->ctf_dvhash = NULL; - memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t)); - memset (fp->ctf_lookups, 0, sizeof (fp->ctf_lookups)); - memset (&fp->ctf_in_flight_dynsyms, 0, sizeof (fp->ctf_in_flight_dynsyms)); - memset (&fp->ctf_dedup, 0, sizeof (fp->ctf_dedup)); - fp->ctf_structs = NULL; - fp->ctf_unions = NULL; - fp->ctf_enums = NULL; - fp->ctf_names = NULL; - - memcpy (&ofp, fp, sizeof (ctf_dict_t)); - memcpy (fp, nfp, sizeof (ctf_dict_t)); - memcpy (nfp, &ofp, sizeof (ctf_dict_t)); - - nfp->ctf_refcnt = 1; /* Force nfp to be freed. */ - ctf_dict_close (nfp); - - return 0; + return buf; oom: - free (buf); - return (ctf_set_errno (fp, EAGAIN)); + ctf_set_errno (fp, EAGAIN); err: free (buf); - return -1; /* errno is set for us. */ + return NULL; /* errno is set for us. */ } /* File writing. */ @@ -1255,30 +1127,27 @@ err: int ctf_gzwrite (ctf_dict_t *fp, gzFile fd) { - const unsigned char *buf; - ssize_t resid; - ssize_t len; + unsigned char *buf; + unsigned char *p; + size_t bufsiz; + size_t len, written = 0; - resid = sizeof (ctf_header_t); - buf = (unsigned char *) fp->ctf_header; - while (resid != 0) - { - if ((len = gzwrite (fd, buf, resid)) <= 0) - return (ctf_set_errno (fp, errno)); - resid -= len; - buf += len; - } + if ((buf = ctf_serialize (fp, &bufsiz)) == NULL) + return -1; /* errno is set for us. */ - resid = fp->ctf_size; - buf = fp->ctf_buf; - while (resid != 0) + p = buf; + while (written < bufsiz) { - if ((len = gzwrite (fd, buf, resid)) <= 0) - return (ctf_set_errno (fp, errno)); - resid -= len; - buf += len; + if ((len = gzwrite (fd, p, bufsiz - written)) <= 0) + { + free (buf); + return (ctf_set_errno (fp, errno)); + } + written += len; + p += len; } + free (buf); return 0; } @@ -1288,88 +1157,95 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd) unsigned char * ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold) { - unsigned char *buf; + unsigned char *rawbuf; + unsigned char *buf = NULL; unsigned char *bp; - ctf_header_t *hp; - unsigned char *flipped, *src; - ssize_t header_len = sizeof (ctf_header_t); - ssize_t compress_len; + ctf_header_t *rawhp, *hp; + unsigned char *src; + size_t rawbufsiz; + size_t alloc_len = 0; + int uncompressed = 0; int flip_endian; - int uncompressed; int rc; flip_endian = getenv ("LIBCTF_WRITE_FOREIGN_ENDIAN") != NULL; - uncompressed = (fp->ctf_size < threshold); - if (ctf_serialize (fp) < 0) + if ((rawbuf = ctf_serialize (fp, &rawbufsiz)) == NULL) return NULL; /* errno is set for us. */ - compress_len = compressBound (fp->ctf_size); - if (fp->ctf_size < threshold) - compress_len = fp->ctf_size; - if ((buf = malloc (compress_len - + sizeof (struct ctf_header))) == NULL) + if (!ctf_assert (fp, rawbufsiz >= sizeof (ctf_header_t))) + goto err; + + if (rawbufsiz >= threshold) + alloc_len = compressBound (rawbufsiz - sizeof (ctf_header_t)) + + sizeof (ctf_header_t); + + /* Trivial operation if the buffer is incompressible or too small to bother + compressing, and we're not doing a forced write-time flip. */ + + if (rawbufsiz < threshold || rawbufsiz < alloc_len) + { + alloc_len = rawbufsiz; + uncompressed = 1; + } + + if (!flip_endian && uncompressed) + { + *size = rawbufsiz; + return rawbuf; + } + + if ((buf = malloc (alloc_len)) == NULL) { ctf_set_errno (fp, ENOMEM); ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"), - (unsigned long) (compress_len + sizeof (struct ctf_header))); - return NULL; + (unsigned long) (alloc_len)); + goto err; } + rawhp = (ctf_header_t *) rawbuf; hp = (ctf_header_t *) buf; - memcpy (hp, fp->ctf_header, header_len); - bp = buf + sizeof (struct ctf_header); - *size = sizeof (struct ctf_header); + memcpy (hp, rawbuf, sizeof (ctf_header_t)); + bp = buf + sizeof (ctf_header_t); + *size = sizeof (ctf_header_t); - if (uncompressed) - hp->cth_flags &= ~CTF_F_COMPRESS; - else + if (!uncompressed) hp->cth_flags |= CTF_F_COMPRESS; - src = fp->ctf_buf; - flipped = NULL; + src = rawbuf + sizeof (ctf_header_t); if (flip_endian) { - if ((flipped = malloc (fp->ctf_size)) == NULL) - { - ctf_set_errno (fp, ENOMEM); - ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"), - (unsigned long) (fp->ctf_size + sizeof (struct ctf_header))); - return NULL; - } ctf_flip_header (hp); - memcpy (flipped, fp->ctf_buf, fp->ctf_size); - if (ctf_flip (fp, fp->ctf_header, flipped, 1) < 0) - { - free (buf); - free (flipped); - return NULL; /* errno is set for us. */ - } - src = flipped; + if (ctf_flip (fp, rawhp, src, 1) < 0) + goto err; /* errno is set for us. */ } - if (uncompressed) - { - memcpy (bp, src, fp->ctf_size); - *size += fp->ctf_size; - } - else + if (!uncompressed) { + size_t compress_len = alloc_len - sizeof (ctf_header_t); + if ((rc = compress (bp, (uLongf *) &compress_len, - src, fp->ctf_size)) != Z_OK) + src, rawbufsiz - sizeof (ctf_header_t))) != Z_OK) { ctf_set_errno (fp, ECTF_COMPRESS); ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc)); - free (buf); - return NULL; + goto err; } *size += compress_len; } + else + { + memcpy (bp, src, rawbufsiz - sizeof (ctf_header_t)); + *size += rawbufsiz - sizeof (ctf_header_t); + } - free (flipped); - + free (rawbuf); return buf; +err: + free (buf); + free (rawbuf); + return NULL; } /* Compress the specified CTF data stream and write it to the specified file |