📄 ctf_create.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)ctf_create.c 1.2 04/10/22 SMI"#include <sys/sysmacros.h>#include <sys/param.h>#include <sys/mman.h>#include <ctf_impl.h>/* * This static string is used as the template for initially populating a * dynamic container's string table. We always store \0 in the first byte, * and we use the generic string "PARENT" to mark this container's parent * if one is associated with the container using ctf_import(). */static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT";/* * To create an empty CTF container, we just declare a zeroed header and call * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w * and initialize the dynamic members. We set dtstrlen to 1 to reserve the * first byte of the string table for a \0 byte, and we start assigning type * IDs at 1 because type ID 0 is used as a sentinel. */ctf_file_t *ctf_create(int *errp){ static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } }; ctf_sect_t cts; ctf_file_t *fp; cts.cts_name = _CTF_SECTION; cts.cts_type = SHT_PROGBITS; cts.cts_flags = 0; cts.cts_data = &hdr; cts.cts_size = sizeof (hdr); cts.cts_entsize = 1; cts.cts_offset = 0; if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) != NULL) { fp->ctf_flags |= LCTF_RDWR; fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE); fp->ctf_dtnextid = 1; fp->ctf_dtoldid = 0; } return (fp);}static uchar_t *ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *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)) { if (dmd->dmd_name) { ctm.ctm_name = soff; soff += strlen(dmd->dmd_name) + 1; } else ctm.ctm_name = 0; ctm.ctm_type = (ushort_t)dmd->dmd_type; ctm.ctm_offset = (ushort_t)dmd->dmd_offset; bcopy(&ctm, t, sizeof (ctm)); t += sizeof (ctm); } return (t);}static uchar_t *ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *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)) { if (dmd->dmd_name) { ctlm.ctlm_name = soff; soff += strlen(dmd->dmd_name) + 1; } else ctlm.ctlm_name = 0; ctlm.ctlm_type = (ushort_t)dmd->dmd_type; ctlm.ctlm_pad = 0; ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); bcopy(&ctlm, t, sizeof (ctlm)); t += sizeof (ctlm); } return (t);}static uchar_t *ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *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)) { cte.cte_name = soff; cte.cte_value = dmd->dmd_value; soff += strlen(dmd->dmd_name) + 1; bcopy(&cte, t, sizeof (cte)); t += sizeof (cte); } return (t);}static uchar_t *ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s){ ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); size_t len; for (; dmd != NULL; dmd = ctf_list_next(dmd)) { if (dmd->dmd_name == NULL) continue; /* skip anonymous members */ len = strlen(dmd->dmd_name) + 1; bcopy(dmd->dmd_name, s, len); s += len; } return (s);}/* * If the specified CTF container is writable and has been modified, reload * this container with the updated type definitions. 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 file * containing the definitions, and then call ctf_bufopen() on it. This not * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest * of the library code with different lookup paths for static and dynamic * type definitions. We are therefore optimizing greatly for lookup over * update, which we assume will be an uncommon operation. We perform one * extra trick here for the benefit of callers and to keep our code simple: * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp * constant for the caller, so after ctf_bufopen() returns, we use bcopy to * swap the interior of the old and new ctf_file_t's, and then free the old. */intctf_update(ctf_file_t *fp){ ctf_file_t ofp, *nfp; ctf_header_t hdr; ctf_dtdef_t *dtd; ctf_sect_t cts; uchar_t *s, *s0, *t; size_t size; void *buf; int err; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ /* * 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). */ bzero(&hdr, sizeof (hdr)); hdr.cth_magic = CTF_MAGIC; hdr.cth_version = CTF_VERSION; if (fp->ctf_flags & LCTF_CHILD) hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */ /* * Iterate through the dynamic type definition list and compute the * size of the CTF type section we will need to generate. */ for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ctf_list_next(dtd)) { uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) size += sizeof (ctf_stype_t); else size += sizeof (ctf_type_t); switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: size += sizeof (uint_t); break; case CTF_K_ARRAY: size += sizeof (ctf_array_t); break; case CTF_K_FUNCTION: size += sizeof (ushort_t) * (vlen + (vlen & 1)); break; case CTF_K_STRUCT: case CTF_K_UNION: if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) size += sizeof (ctf_member_t) * vlen; else size += sizeof (ctf_lmember_t) * vlen; break; case CTF_K_ENUM: size += sizeof (ctf_enum_t) * vlen; break; } } /* * Fill in the string table offset and size, compute the size of the * entire CTF buffer we need, and then allocate a new buffer and * bcopy the finished header to the start of the buffer. */ hdr.cth_stroff = hdr.cth_typeoff + size; hdr.cth_strlen = fp->ctf_dtstrlen; size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; if ((buf = ctf_data_alloc(size)) == MAP_FAILED) return (ctf_set_errno(fp, EAGAIN)); bcopy(&hdr, buf, sizeof (ctf_header_t)); t = (uchar_t *)buf + sizeof (ctf_header_t); s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff; bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE)); s += sizeof (_CTF_STRTAB_TEMPLATE); /* * We now take a final lap through the dynamic type definition list and * copy the appropriate type records and strings to the output buffer. */ for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ctf_list_next(dtd)) { uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); ctf_array_t cta; uint_t encoding; size_t len; if (dtd->dtd_name != NULL) { dtd->dtd_data.ctt_name = (uint_t)(s - s0); len = strlen(dtd->dtd_name) + 1; bcopy(dtd->dtd_name, s, len); s += len; } else dtd->dtd_data.ctt_name = 0; if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) len = sizeof (ctf_stype_t); else len = sizeof (ctf_type_t); bcopy(&dtd->dtd_data, t, len); t += len; switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: if (kind == CTF_K_INTEGER) { encoding = CTF_INT_DATA( dtd->dtd_u.dtu_enc.cte_format, dtd->dtd_u.dtu_enc.cte_offset, dtd->dtd_u.dtu_enc.cte_bits); } else { encoding = CTF_FP_DATA( dtd->dtd_u.dtu_enc.cte_format, dtd->dtd_u.dtu_enc.cte_offset, dtd->dtd_u.dtu_enc.cte_bits); } bcopy(&encoding, t, sizeof (encoding)); t += sizeof (encoding); break; case CTF_K_ARRAY: cta.cta_contents = (ushort_t) dtd->dtd_u.dtu_arr.ctr_contents; cta.cta_index = (ushort_t) dtd->dtd_u.dtu_arr.ctr_index; cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; bcopy(&cta, t, sizeof (cta)); t += sizeof (cta); break; case CTF_K_FUNCTION: { ushort_t *argv = (ushort_t *)(uintptr_t)t; uint_t argc; for (argc = 0; argc < vlen; argc++) *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc]; if (vlen & 1) *argv++ = 0; /* pad to 4-byte boundary */ t = (uchar_t *)argv; break; } case CTF_K_STRUCT: case CTF_K_UNION: if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t); else t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t); s = ctf_copy_membnames(dtd, s); break; case CTF_K_ENUM: t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t); s = ctf_copy_membnames(dtd, s); break; } } /* * Finally, we are ready to ctf_bufopen() the new container. If this * is successful, we then switch nfp and fp and free the old container. */ ctf_data_protect(buf, size); cts.cts_name = _CTF_SECTION; cts.cts_type = SHT_PROGBITS; cts.cts_flags = 0; cts.cts_data = buf; cts.cts_size = size; cts.cts_entsize = 1; cts.cts_offset = 0; if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) { ctf_data_free(buf, size); return (ctf_set_errno(fp, err)); } (void) ctf_setmodel(nfp, ctf_getmodel(fp)); (void) ctf_import(nfp, fp->ctf_parent); nfp->ctf_refcnt = fp->ctf_refcnt; nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */ nfp->ctf_dtdefs = fp->ctf_dtdefs; nfp->ctf_dtstrlen = fp->ctf_dtstrlen; nfp->ctf_dtnextid = fp->ctf_dtnextid; nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t)); bcopy(fp, &ofp, sizeof (ctf_file_t)); bcopy(nfp, fp, sizeof (ctf_file_t)); bcopy(&ofp, nfp, sizeof (ctf_file_t)); /* * Initialize the ctf_lookup_by_name top-level dictionary. We keep an * array of type name prefixes and the corresponding ctf_hash to use. * NOTE: This code must be kept in sync with the code in ctf_bufopen(). */ fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; nfp->ctf_refcnt = 1; /* force nfp to be freed */ ctf_close(nfp); return (0);}/* * Discard all of the dynamic type definitions that have been added to the * container since the last call to ctf_update(). We locate such types by * scanning the list and deleting elements that have type IDs greater than * ctf_dtoldid, which is set by ctf_update(), above. */intctf_discard(ctf_file_t *fp){ ctf_dtdef_t *dtd, *ntd; ctf_dmdef_t *dmd, *nmd; size_t len; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { if (dtd->dtd_type <= fp->ctf_dtoldid) continue; /* skip types that have been committed */ switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { case CTF_K_STRUCT: case CTF_K_UNION: case CTF_K_ENUM: for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = nmd) { if (dmd->dmd_name != NULL) { len = strlen(dmd->dmd_name) + 1; ctf_free(dmd->dmd_name, len); fp->ctf_dtstrlen -= len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -