diff options
Diffstat (limited to 'libctf')
-rw-r--r-- | libctf/ChangeLog | 12 | ||||
-rw-r--r-- | libctf/ctf-serialize.c | 729 |
2 files changed, 424 insertions, 317 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 58c0ed4..4e4e9af 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,17 @@ 2021-03-18 Nick Alcock <nick.alcock@oracle.com> + * ctf-serialize.c: General reshuffling, and... + (emit_symtypetab_state_t): New, migrated from + local variables in ctf_serialize. + (ctf_serialize): Split out most section sizing and + emission. + (ctf_symtypetab_sect_sizes): New (split out). + (ctf_emit_symtypetab_sects): Likewise. + (ctf_type_sect_size): Likewise. + (ctf_emit_type_sect): Likewise. + +2021-03-18 Nick Alcock <nick.alcock@oracle.com> + * ctf-impl.h (ctf_dict_t): Fix comment. 2021-03-18 Nick Alcock <nick.alcock@oracle.com> diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c index e0bd98c..1e2c98b 100644 --- a/libctf/ctf-serialize.c +++ b/libctf/ctf-serialize.c @@ -26,29 +26,39 @@ #include <elf.h> #include "elf-bfd.h" -/* Delete data symbols that have been assigned names from the variable section. - Must be called from within ctf_serialize, because that is the only place - you can safely delete variables without messing up ctf_rollback. */ +/* Symtypetab sections. */ -static int -symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp) +/* Symtypetab emission flags. */ + +#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1 +#define CTF_SYMTYPETAB_EMIT_PAD 0x2 +#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4 + +/* Properties of symtypetab emission, shared by symtypetab section + sizing and symtypetab emission itself. */ + +typedef struct emit_symtypetab_state { - ctf_dvdef_t *dvd, *nvd; - ctf_id_t type; + /* True if linker-reported symbols are being filtered out. symfp is set if + this is true: otherwise, indexing is forced and the symflags indicate as + much. */ + int filter_syms; - for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd) - { - nvd = ctf_list_next (dvd); + /* True if symbols are being sorted. */ + int sort_syms; - if (((type = (ctf_id_t) (uintptr_t) - ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0) - && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL - && type == dvd->dvd_type) - ctf_dvd_delete (fp, dvd); - } + /* Flags for symtypetab emission. */ + int symflags; - return 0; -} + /* The dict to which the linker has reported symbols. */ + ctf_dict_t *symfp; + + /* The maximum number of objects seen. */ + size_t maxobjt; + + /* The maximum number of func info entris seen. */ + size_t maxfunc; +} emit_symtypetab_state_t; /* Determine if a symbol is "skippable" and should never appear in the symtypetab sections. */ @@ -68,12 +78,6 @@ ctf_symtab_skippable (ctf_link_sym_t *sym) && sym->st_value == 0)); } -/* Symtypetab emission flags. */ - -#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1 -#define CTF_SYMTYPETAB_EMIT_PAD 0x2 -#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4 - /* Get the number of symbols in a symbol hash, the count of symbols, the maximum seen, the eventual size, without any padding elements, of the func/data and (if generated) index sections, and the size of accumulated padding elements. @@ -427,140 +431,40 @@ emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp, return 0; } -static unsigned char * -ctf_copy_smembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) -{ - ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - ctf_member_t ctm; - - for (; dmd != NULL; dmd = ctf_list_next (dmd)) - { - ctf_member_t *copied; - - ctm.ctm_name = 0; - ctm.ctm_type = (uint32_t) dmd->dmd_type; - ctm.ctm_offset = (uint32_t) dmd->dmd_offset; - - memcpy (t, &ctm, sizeof (ctm)); - copied = (ctf_member_t *) t; - if (dmd->dmd_name) - ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctm_name); - - t += sizeof (ctm); - } - - return t; -} - -static unsigned char * -ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) -{ - ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - ctf_lmember_t ctlm; - - for (; dmd != NULL; dmd = ctf_list_next (dmd)) - { - ctf_lmember_t *copied; - - ctlm.ctlm_name = 0; - ctlm.ctlm_type = (uint32_t) dmd->dmd_type; - ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset); - ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset); - - memcpy (t, &ctlm, sizeof (ctlm)); - copied = (ctf_lmember_t *) t; - if (dmd->dmd_name) - ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctlm_name); - - t += sizeof (ctlm); - } - - return t; -} +/* Delete data symbols that have been assigned names from the variable section. + Must be called from within ctf_serialize, because that is the only place + you can safely delete variables without messing up ctf_rollback. */ -static unsigned char * -ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) +static int +symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp) { - ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - ctf_enum_t cte; + ctf_dvdef_t *dvd, *nvd; + ctf_id_t type; - for (; dmd != NULL; dmd = ctf_list_next (dmd)) + for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd) { - ctf_enum_t *copied; + nvd = ctf_list_next (dvd); - cte.cte_value = dmd->dmd_value; - memcpy (t, &cte, sizeof (cte)); - copied = (ctf_enum_t *) t; - ctf_str_add_ref (fp, dmd->dmd_name, &copied->cte_name); - t += sizeof (cte); + if (((type = (ctf_id_t) (uintptr_t) + ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0) + && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL + && type == dvd->dvd_type) + ctf_dvd_delete (fp, dvd); } - return t; + return 0; } -/* Sort a newly-constructed static variable array. */ - -typedef struct ctf_sort_var_arg_cb -{ - ctf_dict_t *fp; - ctf_strs_t *strtab; -} ctf_sort_var_arg_cb_t; - +/* Figure out the sizes of the symtypetab sections, their indexed state, + etc. */ static int -ctf_sort_var (const void *one_, const void *two_, void *arg_) -{ - const ctf_varent_t *one = one_; - const ctf_varent_t *two = two_; - ctf_sort_var_arg_cb_t *arg = arg_; - - return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab), - ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab))); -} - -/* 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. */ -int -ctf_serialize (ctf_dict_t *fp) +ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s, + ctf_header_t *hdr, size_t *objt_size, + size_t *func_size, size_t *objtidx_size, + size_t *funcidx_size) { - ctf_dict_t ofp, *nfp; - ctf_header_t hdr, *hdrp; - ctf_dtdef_t *dtd; - ctf_dvdef_t *dvd; - ctf_varent_t *dvarents; - ctf_strs_writable_t strtab; - - unsigned char *t; - unsigned long i; - size_t buf_size, type_size, objt_size, func_size; + size_t nfuncs, nobjts; size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize; - size_t funcidx_size, objtidx_size; - size_t nvars, nfuncs, nobjts, maxobjt, maxfunc; - size_t nsymtypes = 0; - const char **sym_name_order = NULL; - unsigned char *buf = NULL, *newbuf; - int err; - - /* Symtab filtering. If filter_syms is true, symfp is set: otherwise, - CTF_SYMTYPETAB_FORCE_INDEXED is set in symflags. */ - int filter_syms = 0; - int sort_syms = 1; - int symflags = 0; - ctf_dict_t *symfp = NULL; - - if (!(fp->ctf_flags & LCTF_RDWR)) - return (ctf_set_errno (fp, ECTF_RDONLY)); - - /* Update required? */ - if (!(fp->ctf_flags & LCTF_DIRTY)) - return 0; /* If doing a writeout as part of linking, and the link flags request it, filter out reported symbols from the variable section, and filter out all @@ -571,124 +475,59 @@ ctf_serialize (ctf_dict_t *fp) doesn't care what order the symtypetab entries is in, since it only iterates over symbols and does not use the ctf_lookup_by_symbol* API.) */ + s->sort_syms = 1; if (fp->ctf_flags & LCTF_LINKING) { - filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS); - if (!filter_syms) - sort_syms = 0; - } - - /* 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 - boundary past the CTF header itself (at relative offset zero). The flag - indicating a new-style function info section (an array of CTF_K_FUNCTION - type IDs in the types section) is flipped on. */ - - memset (&hdr, 0, sizeof (hdr)); - hdr.cth_magic = CTF_MAGIC; - hdr.cth_version = CTF_VERSION; - - /* This is a new-format func info section, and the symtab and strtab come out - of the dynsym and dynstr these days. */ - hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR); - - /* Iterate through the dynamic type definition list and compute the - size of the CTF type section we will need to generate. */ - - for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs); - dtd != NULL; dtd = ctf_list_next (dtd)) - { - uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); - uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); - - if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) - type_size += sizeof (ctf_stype_t); - else - type_size += sizeof (ctf_type_t); - - switch (kind) - { - case CTF_K_INTEGER: - case CTF_K_FLOAT: - type_size += sizeof (uint32_t); - break; - case CTF_K_ARRAY: - type_size += sizeof (ctf_array_t); - break; - case CTF_K_SLICE: - type_size += sizeof (ctf_slice_t); - break; - case CTF_K_FUNCTION: - type_size += sizeof (uint32_t) * (vlen + (vlen & 1)); - break; - case CTF_K_STRUCT: - case CTF_K_UNION: - if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) - type_size += sizeof (ctf_member_t) * vlen; - else - type_size += sizeof (ctf_lmember_t) * vlen; - break; - case CTF_K_ENUM: - type_size += sizeof (ctf_enum_t) * vlen; - break; - } + s->filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS); + if (!s->filter_syms) + s->sort_syms = 0; } /* Find the dict to which the linker has reported symbols, if any. */ - if (filter_syms) + if (s->filter_syms) { if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms) - symfp = fp->ctf_parent; + s->symfp = fp->ctf_parent; else - symfp = fp; + s->symfp = fp; } /* If not filtering, keep all potential symbols in an unsorted, indexed dict. */ - if (!filter_syms) - symflags = CTF_SYMTYPETAB_FORCE_INDEXED; + if (!s->filter_syms) + s->symflags = CTF_SYMTYPETAB_FORCE_INDEXED; else - hdr.cth_flags |= CTF_F_IDXSORTED; + hdr->cth_flags |= CTF_F_IDXSORTED; - if (!ctf_assert (fp, (filter_syms && symfp) - || (!filter_syms && !symfp - && ((symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0)))) + if (!ctf_assert (fp, (s->filter_syms && s->symfp) + || (!s->filter_syms && !s->symfp + && ((s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0)))) return -1; /* Work out the sizes of the object and function sections, and work out the number of pad (unassigned) symbols in each, and the overall size of the sections. */ - if (symtypetab_density (fp, symfp, fp->ctf_objthash, &nobjts, &maxobjt, - &objt_unpadsize, &objt_padsize, &objtidx_size, - symflags) < 0) + if (symtypetab_density (fp, s->symfp, fp->ctf_objthash, &nobjts, &s->maxobjt, + &objt_unpadsize, &objt_padsize, objtidx_size, + s->symflags) < 0) return -1; /* errno is set for us. */ ctf_dprintf ("Object symtypetab: %i objects, max %i, unpadded size %i, " - "%i bytes of pads, index size %i\n", (int) nobjts, (int) maxobjt, - (int) objt_unpadsize, (int) objt_padsize, (int) objtidx_size); + "%i bytes of pads, index size %i\n", (int) nobjts, + (int) s->maxobjt, (int) objt_unpadsize, (int) objt_padsize, + (int) *objtidx_size); - if (symtypetab_density (fp, symfp, fp->ctf_funchash, &nfuncs, &maxfunc, - &func_unpadsize, &func_padsize, &funcidx_size, - symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) + if (symtypetab_density (fp, s->symfp, fp->ctf_funchash, &nfuncs, &s->maxfunc, + &func_unpadsize, &func_padsize, funcidx_size, + s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) return -1; /* errno is set for us. */ ctf_dprintf ("Function symtypetab: %i functions, max %i, unpadded size %i, " - "%i bytes of pads, index size %i\n", (int) nfuncs, (int) maxfunc, - (int) func_unpadsize, (int) func_padsize, (int) funcidx_size); - - /* If we are filtering symbols out, those symbols that the linker has not - reported have now been removed from the ctf_objthash and ctf_funchash. - Delete entries from the variable section that duplicate newly-added data - symbols. There's no need to migrate new ones in, because the compiler - always emits both a variable and a data symbol simultaneously, and - filtering only happens at final link time. */ - - if (filter_syms && symfp->ctf_dynsyms && - symtypetab_delete_nonstatic_vars (fp, symfp) < 0) - return -1; + "%i bytes of pads, index size %i\n", (int) nfuncs, + (int) s->maxfunc, (int) func_unpadsize, (int) func_padsize, + (int) *funcidx_size); /* It is worth indexing each section if it would save space to do so, due to reducing the number of pads sufficiently. A pad is the same size as a @@ -701,56 +540,48 @@ ctf_serialize (ctf_dict_t *fp) but just an ld -r), we must emit things in indexed fashion just as the compiler does. */ - objt_size = objt_unpadsize; - if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED) + *objt_size = objt_unpadsize; + if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED) && ((objt_padsize + objt_unpadsize) * CTF_INDEX_PAD_THRESHOLD > objt_padsize)) { - objt_size += objt_padsize; - objtidx_size = 0; + *objt_size += objt_padsize; + *objtidx_size = 0; } - func_size = func_unpadsize; - if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED) + *func_size = func_unpadsize; + if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED) && ((func_padsize + func_unpadsize) * CTF_INDEX_PAD_THRESHOLD > func_padsize)) { - func_size += func_padsize; - funcidx_size = 0; + *func_size += func_padsize; + *funcidx_size = 0; } - /* Computing the number of entries in the CTF variable section is much - simpler. */ - - for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); - dvd != NULL; dvd = ctf_list_next (dvd), nvars++); - - /* Compute the size of the CTF buffer we need, sans only the string table, - then allocate a new buffer and memcpy the finished header to the start of - the buffer. (We will adjust this later with strtab length info.) */ - - hdr.cth_lbloff = hdr.cth_objtoff = 0; - hdr.cth_funcoff = hdr.cth_objtoff + objt_size; - hdr.cth_objtidxoff = hdr.cth_funcoff + func_size; - hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size; - hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size; - hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t)); - hdr.cth_stroff = hdr.cth_typeoff + type_size; - hdr.cth_strlen = 0; - - buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; + /* If we are filtering symbols out, those symbols that the linker has not + reported have now been removed from the ctf_objthash and ctf_funchash. + Delete entries from the variable section that duplicate newly-added data + symbols. There's no need to migrate new ones in, because the compiler + always emits both a variable and a data symbol simultaneously, and + filtering only happens at final link time. */ - if ((buf = malloc (buf_size)) == NULL) - return (ctf_set_errno (fp, EAGAIN)); + if (s->filter_syms && s->symfp->ctf_dynsyms && + symtypetab_delete_nonstatic_vars (fp, s->symfp) < 0) + return -1; - memcpy (buf, &hdr, sizeof (ctf_header_t)); - t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff; + return 0; +} - hdrp = (ctf_header_t *) buf; - if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL)) - ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname); - if (fp->ctf_cuname != NULL) - ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname); +static int +ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s, + unsigned char **tptr, size_t objt_size, + size_t func_size, size_t objtidx_size, + size_t funcidx_size) +{ + unsigned char *t = *tptr; + size_t nsymtypes = 0; + const char **sym_name_order = NULL; + int err; /* Sort the linker's symbols into name order if need be. */ @@ -760,10 +591,10 @@ ctf_serialize (ctf_dict_t *fp) void *symname; const char **walk; - if (filter_syms) + if (s->filter_syms) { - if (symfp->ctf_dynsyms) - nsymtypes = ctf_dynhash_elements (symfp->ctf_dynsyms); + if (s->symfp->ctf_dynsyms) + nsymtypes = ctf_dynhash_elements (s->symfp->ctf_dynsyms); else nsymtypes = 0; } @@ -776,11 +607,11 @@ ctf_serialize (ctf_dict_t *fp) walk = sym_name_order; - if (filter_syms) + if (s->filter_syms) { - if (symfp->ctf_dynsyms) + if (s->symfp->ctf_dynsyms) { - while ((err = ctf_dynhash_next_sorted (symfp->ctf_dynsyms, &i, + while ((err = ctf_dynhash_next_sorted (s->symfp->ctf_dynsyms, &i, &symname, NULL, ctf_dynhash_sort_by_name, NULL)) == 0) @@ -795,7 +626,7 @@ ctf_serialize (ctf_dict_t *fp) /* Since we partition the set of symbols back into objt and func, we can sort the two independently without harm. */ - if (sort_syms) + if (s->sort_syms) sort_fun = ctf_dynhash_sort_by_name; while ((err = ctf_dynhash_next_sorted (fp->ctf_objthash, &i, &symname, @@ -816,82 +647,209 @@ ctf_serialize (ctf_dict_t *fp) Emission is done in symtab order if there is no index, and in index (name) order otherwise. */ - if ((objtidx_size == 0) && symfp && symfp->ctf_dynsymidx) + if ((objtidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx) { ctf_dprintf ("Emitting unindexed objt symtypetab\n"); - if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx, - NULL, symfp->ctf_dynsymmax + 1, maxobjt, objt_size, - symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0) + if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, + s->symfp->ctf_dynsymidx, NULL, + s->symfp->ctf_dynsymmax + 1, s->maxobjt, + objt_size, s->symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0) goto err; /* errno is set for us. */ } else { ctf_dprintf ("Emitting indexed objt symtypetab\n"); - if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order, - nsymtypes, maxobjt, objt_size, symflags) < 0) + if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL, + sym_name_order, nsymtypes, s->maxobjt, + objt_size, s->symflags) < 0) goto err; /* errno is set for us. */ } t += objt_size; - if ((funcidx_size == 0) && symfp && symfp->ctf_dynsymidx) + if ((funcidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx) { ctf_dprintf ("Emitting unindexed func symtypetab\n"); - if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx, - NULL, symfp->ctf_dynsymmax + 1, maxfunc, - func_size, symflags | CTF_SYMTYPETAB_EMIT_FUNCTION + if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, + s->symfp->ctf_dynsymidx, NULL, + s->symfp->ctf_dynsymmax + 1, s->maxfunc, + func_size, s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION | CTF_SYMTYPETAB_EMIT_PAD) < 0) goto err; /* errno is set for us. */ } else { ctf_dprintf ("Emitting indexed func symtypetab\n"); - if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order, - nsymtypes, maxfunc, func_size, - symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) + if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL, sym_name_order, + nsymtypes, s->maxfunc, func_size, + s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) goto err; /* errno is set for us. */ } t += func_size; if (objtidx_size > 0) - if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order, - nsymtypes, objtidx_size, symflags) < 0) + if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order, + nsymtypes, objtidx_size, s->symflags) < 0) goto err; t += objtidx_size; if (funcidx_size > 0) - if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order, + if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order, nsymtypes, funcidx_size, - symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) + s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0) goto err; t += funcidx_size; free (sym_name_order); - sym_name_order = NULL; + *tptr = t; - /* Work over the variable list, translating everything into ctf_varent_t's and - prepping the string table. */ + return 0; - dvarents = (ctf_varent_t *) t; - for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; - dvd = ctf_list_next (dvd), i++) + oom: + ctf_set_errno (fp, EAGAIN); + goto err; +symerr: + ctf_err_warn (fp, 0, err, _("error serializing symtypetabs")); + err: + free (sym_name_order); + return -1; +} + +/* Type section. */ + +static unsigned char * +ctf_copy_smembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) +{ + ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + ctf_member_t ctm; + + for (; dmd != NULL; dmd = ctf_list_next (dmd)) { - ctf_varent_t *var = &dvarents[i]; + ctf_member_t *copied; - ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name); - var->ctv_type = (uint32_t) dvd->dvd_type; + ctm.ctm_name = 0; + ctm.ctm_type = (uint32_t) dmd->dmd_type; + ctm.ctm_offset = (uint32_t) dmd->dmd_offset; + + memcpy (t, &ctm, sizeof (ctm)); + copied = (ctf_member_t *) t; + if (dmd->dmd_name) + ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctm_name); + + t += sizeof (ctm); } - assert (i == nvars); - t += sizeof (ctf_varent_t) * nvars; + return t; +} - assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff); +static unsigned char * +ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) +{ + ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + ctf_lmember_t ctlm; + + for (; dmd != NULL; dmd = ctf_list_next (dmd)) + { + ctf_lmember_t *copied; - /* We now take a final lap through the dynamic type definition list and copy - the appropriate type records to the output buffer, noting down the - strings as we go. */ + ctlm.ctlm_name = 0; + ctlm.ctlm_type = (uint32_t) dmd->dmd_type; + ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset); + ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset); + + memcpy (t, &ctlm, sizeof (ctlm)); + copied = (ctf_lmember_t *) t; + if (dmd->dmd_name) + ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctlm_name); + + t += sizeof (ctlm); + } + + return t; +} + +static unsigned char * +ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) +{ + ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + ctf_enum_t cte; + + for (; dmd != NULL; dmd = ctf_list_next (dmd)) + { + ctf_enum_t *copied; + + cte.cte_value = dmd->dmd_value; + memcpy (t, &cte, sizeof (cte)); + copied = (ctf_enum_t *) t; + ctf_str_add_ref (fp, dmd->dmd_name, &copied->cte_name); + t += sizeof (cte); + } + + return t; +} + +/* Iterate through 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) +{ + ctf_dtdef_t *dtd; + size_t type_size; + + for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs); + dtd != NULL; dtd = ctf_list_next (dtd)) + { + uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); + uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); + + if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) + type_size += sizeof (ctf_stype_t); + else + type_size += sizeof (ctf_type_t); + + switch (kind) + { + case CTF_K_INTEGER: + case CTF_K_FLOAT: + type_size += sizeof (uint32_t); + break; + case CTF_K_ARRAY: + type_size += sizeof (ctf_array_t); + break; + case CTF_K_SLICE: + type_size += sizeof (ctf_slice_t); + break; + case CTF_K_FUNCTION: + type_size += sizeof (uint32_t) * (vlen + (vlen & 1)); + break; + case CTF_K_STRUCT: + case CTF_K_UNION: + if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) + type_size += sizeof (ctf_member_t) * vlen; + else + type_size += sizeof (ctf_lmember_t) * vlen; + break; + case CTF_K_ENUM: + type_size += sizeof (ctf_enum_t) * vlen; + break; + } + } + + return type_size; +} + +/* Take a final lap through the dynamic type definition list and copy the + appropriate type records to the output buffer, noting down the strings as + we go. */ + +static void +ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr) +{ + unsigned char *t = *tptr; + ctf_dtdef_t *dtd; for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ctf_list_next (dtd)) @@ -978,6 +936,147 @@ ctf_serialize (ctf_dict_t *fp) break; } } + + *tptr = t; +} + +/* Variable section. */ + +/* Sort a newly-constructed static variable array. */ + +typedef struct ctf_sort_var_arg_cb +{ + ctf_dict_t *fp; + ctf_strs_t *strtab; +} ctf_sort_var_arg_cb_t; + +static int +ctf_sort_var (const void *one_, const void *two_, void *arg_) +{ + const ctf_varent_t *one = one_; + const ctf_varent_t *two = two_; + ctf_sort_var_arg_cb_t *arg = arg_; + + return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab), + ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab))); +} + +/* 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. */ +int +ctf_serialize (ctf_dict_t *fp) +{ + ctf_dict_t ofp, *nfp; + ctf_header_t hdr, *hdrp; + ctf_dvdef_t *dvd; + ctf_varent_t *dvarents; + ctf_strs_writable_t strtab; + int err; + + unsigned char *t; + unsigned long i; + size_t buf_size, type_size, objt_size, func_size; + size_t funcidx_size, objtidx_size; + size_t nvars; + unsigned char *buf = NULL, *newbuf; + + emit_symtypetab_state_t symstate; + memset (&symstate, 0, sizeof (emit_symtypetab_state_t)); + + if (!(fp->ctf_flags & LCTF_RDWR)) + return (ctf_set_errno (fp, ECTF_RDONLY)); + + /* Update required? */ + if (!(fp->ctf_flags & LCTF_DIRTY)) + return 0; + + /* 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 + boundary past the CTF header itself (at relative offset zero). The flag + indicating a new-style function info section (an array of CTF_K_FUNCTION + type IDs in the types section) is flipped on. */ + + memset (&hdr, 0, sizeof (hdr)); + hdr.cth_magic = CTF_MAGIC; + hdr.cth_version = CTF_VERSION; + + /* This is a new-format func info section, and the symtab and strtab come out + of the dynsym and dynstr these days. */ + hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR); + + if (ctf_symtypetab_sect_sizes (fp, &symstate, &hdr, &objt_size, &func_size, + &objtidx_size, &funcidx_size) < 0) + return -1; /* errno is set for us. */ + + for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); + dvd != NULL; dvd = ctf_list_next (dvd), nvars++); + + type_size = ctf_type_sect_size (fp); + + /* Compute the size of the CTF buffer we need, sans only the string table, + then allocate a new buffer and memcpy the finished header to the start of + the buffer. (We will adjust this later with strtab length info.) */ + + hdr.cth_lbloff = hdr.cth_objtoff = 0; + hdr.cth_funcoff = hdr.cth_objtoff + objt_size; + hdr.cth_objtidxoff = hdr.cth_funcoff + func_size; + hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size; + hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size; + hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t)); + hdr.cth_stroff = hdr.cth_typeoff + type_size; + hdr.cth_strlen = 0; + + buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; + + if ((buf = malloc (buf_size)) == NULL) + return (ctf_set_errno (fp, EAGAIN)); + + memcpy (buf, &hdr, sizeof (ctf_header_t)); + t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff; + + hdrp = (ctf_header_t *) buf; + if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL)) + ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname); + if (fp->ctf_cuname != NULL) + ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname); + + if (ctf_emit_symtypetab_sects (fp, &symstate, &t, objt_size, func_size, + objtidx_size, funcidx_size) < 0) + goto err; + + assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_varoff); + + /* Work over the variable list, translating everything into ctf_varent_t's and + prepping the string table. */ + + dvarents = (ctf_varent_t *) t; + for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; + dvd = ctf_list_next (dvd), i++) + { + ctf_varent_t *var = &dvarents[i]; + + ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name); + var->ctv_type = (uint32_t) dvd->dvd_type; + } + assert (i == nvars); + + t += sizeof (ctf_varent_t) * nvars; + + assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff); + + ctf_emit_type_sect (fp, &t); + assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff); /* Construct the final string table and fill out all the string refs with the @@ -1125,19 +1224,15 @@ ctf_serialize (ctf_dict_t *fp) return 0; -symerr: - ctf_err_warn (fp, 0, err, _("error serializing symtypetabs")); - goto err; oom: free (buf); - free (sym_name_order); return (ctf_set_errno (fp, EAGAIN)); err: free (buf); - free (sym_name_order); return -1; /* errno is set for us. */ } +/* File writing. */ /* Write the compressed CTF data stream to the specified gzFile descriptor. */ int |