ctf.c revision 1c4f4ba644d8782956721a39baaa3a53ebc34570
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Create and parse buffers containing CTF data.
*/
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <ctype.h>
#include <zlib.h>
#include <elf.h>
#include "ctf_headers.h"
#include "ctftools.h"
#include "strtab.h"
#include "memory.h"
/*
* Name of the file currently being read, used to print error messages. We
* assume that only one file will be read at a time, and thus make no attempt
* to allow curfile to be used simultaneously by multiple threads.
*
* The value is only valid during a call to ctf_load.
*/
char *curfile;
struct ctf_buf {
int nptent; /* number of processed types */
int ntholes; /* number of type holes */
};
/*PRINTFLIKE1*/
static void
parseterminate(char *fmt, ...)
{
}
void
{
b->ctb_size += CTF_BUF_CHUNK_SIZE;
}
ctf_buf_new(void)
{
strtab_create(&b->ctb_strtab);
ctf_buf_grow(b);
return (b);
}
void
{
strtab_destroy(&b->ctb_strtab);
free(b);
}
ctf_buf_cur(ctf_buf_t *b)
{
}
void
{
while (n != 0) {
ctf_buf_grow(b);
p = (char *)p + len;
n -= len;
}
}
static int
{
return (1);
}
static void
{
}
static void
{
int nargs;
int i;
if (!idp) {
fdata[0] = 0;
return;
}
if (nargs > CTF_MAX_VLEN) {
terminate("function %s has too many args: %d > %d\n",
}
}
id = 0;
}
}
/*
* Depending on the size of the type being described, either a ctf_stype_t (for
* types with size < CTF_LSTRUCT_THRESH) or a ctf_type_t (all others) will be
* written. We isolate the determination here so the rest of the writer code
* doesn't need to care.
*/
static void
{
if (size > CTF_MAX_SIZE) {
} else {
}
}
static void
{
}
static int
{
int i;
/*
* There shouldn't be any holes in the type list (where a hole is
* defined as two consecutive tdescs without consecutive ids), but
* check for them just in case. If we do find holes, we need to make
* fake entries to fill the holes, or we won't be able to reconstruct
* the tree from the written data.
*/
write_sized_type_rec(b, &ctt, 0);
b->nptent++;
}
}
case INTRINSIC:
isroot, 1);
else
encoding = 0;
if (ip->intr_signed)
encoding |= CTF_INT_CHAR;
encoding |= CTF_INT_BOOL;
} else
break;
case POINTER:
write_unsized_type_rec(b, &ctt);
break;
case ARRAY:
break;
case STRUCT:
case UNION:
i++; /* count up struct or union members */
if (i > CTF_MAX_VLEN) {
terminate("sou %s has too many members: %d > %d\n",
}
else
offset);
}
} else {
offset);
}
}
break;
case ENUM:
i++; /* count up enum members */
if (i > CTF_MAX_VLEN) {
terminate("enum %s has too many values: %d > %d\n",
}
}
break;
case FORWARD:
write_unsized_type_rec(b, &ctt);
break;
case TYPEDEF:
write_unsized_type_rec(b, &ctt);
break;
case VOLATILE:
write_unsized_type_rec(b, &ctt);
break;
case CONST:
write_unsized_type_rec(b, &ctt);
break;
case FUNCTION:
if (i > CTF_MAX_VLEN) {
terminate("function %s has too many args: %d > %d\n",
i, CTF_MAX_VLEN);
}
write_unsized_type_rec(b, &ctt);
}
id = 0;
i++;
}
if (i & 1) {
id = 0;
}
break;
case RESTRICT:
write_unsized_type_rec(b, &ctt);
break;
default:
}
return (1);
}
typedef struct resbuf {
} resbuf_t;
static void
{
}
static void
{
int rc;
}
static ssize_t
{
int rc;
}
return (n);
}
static void
{
int rc;
for (;;) {
break;
}
}
static void
{
int rc;
}
/*
* Pad the buffer to a power-of-2 boundary
*/
static void
{
static const char pad[8] = { 0 };
while (topad > 0) {
topad -= 8;
}
}
static ssize_t
{
*posp += n;
return (n);
}
static caddr_t
{
&bufpos);
return (outbuf);
}
/*
* Create the compression buffer, and fill it with the CTF and string
* table data. We flush the compression state between the two so the
* dictionary used for the string tables won't be polluted with values
* that made sense for the CTF data.
*/
static caddr_t
{
&resbuf);
}
{
ctf_header_t h;
int i;
/*
* Prepare the header, and create the CTF output buffers. The data
* object section and function section are both lists of 2-byte
* integers; we pad these out to the next 4-byte boundary if needed.
*/
h.cth_version = CTF_VERSION;
h.cth_lbloff = 0;
buf);
for (i = 0; i < iiburst->iib_nobjts; i++)
for (i = 0; i < iiburst->iib_nfuncs; i++)
/*
* We only do compression for ctfmerge, as ctfconvert is only
* supposed to be used on intermediary build objects. This is
* significantly faster.
*/
if (do_compress)
else
return (outbuf);
}
void
{
*incrementp = sizeof (ctf_type_t);
} else {
*incrementp = sizeof (ctf_stype_t);
}
}
static int
{
int count = 0;
/* LINTED - pointer alignment */
case CTF_K_INTEGER:
case CTF_K_FLOAT:
dptr += 4;
break;
case CTF_K_POINTER:
case CTF_K_FORWARD:
case CTF_K_TYPEDEF:
case CTF_K_VOLATILE:
case CTF_K_CONST:
case CTF_K_RESTRICT:
case CTF_K_FUNCTION:
break;
case CTF_K_ARRAY:
dptr += sizeof (ctf_array_t);
break;
case CTF_K_STRUCT:
case CTF_K_UNION:
if (size < CTF_LSTRUCT_THRESH)
else
break;
case CTF_K_ENUM:
break;
case CTF_K_UNKNOWN:
break;
default:
parseterminate("Unknown CTF type %d (#%d) at %#x",
}
count++;
}
return (count);
}
/*
* Resurrect the labels stored in the CTF data, returning the index associated
* with a label provided by the caller. There are several cases, outlined
* below. Note that, given two labels, the one associated with the lesser type
* index is considered to be older than the other.
*
* 1. matchlbl == NULL - return the index of the most recent label.
* 2. matchlbl == "BASE" - return the index of the oldest label.
* 3. matchlbl != NULL, but doesn't match any labels in the section - warn
* the user, and proceed as if matchlbl == "BASE" (for safety).
* 4. matchlbl != NULL, and matches one of the labels in the section - return
* the type index associated with the label.
*/
static int
{
char *baselabel;
/* LINTED - pointer alignment */
if (baseidx == -1) {
return (lastidx);
}
return (lastidx);
}
/* User provided a label that didn't match */
warning("%s: Cannot find label `%s' - using base (%s)\n",
return (baseidx);
}
return (lastidx);
}
static void
{
/* LINTED - pointer alignment */
"Unexpected end of object symbols at %x of %x",
}
if (id == 0) {
continue;
}
} else
}
}
static void
{
int i;
/* LINTED - pointer alignment */
dptr += 2;
parseterminate("Unexpected end of function symbols");
if (info == 0) {
symit_name(si));
continue;
}
/* LINTED - pointer alignment */
dptr += 2;
} else
/* LINTED - pointer alignment */
parseterminate("Reference to invalid type %d",
id);
}
}
}
}
static void
{
int tcnt;
int iicnt = 0;
int i;
/*
* A maxid of zero indicates a request to resurrect all types, so reset
* maxid to the maximum type id.
*/
if (maxid == 0)
break;
/* LINTED - pointer alignment */
"Unable to cope with non-zero strtab id");
} else
switch (kind) {
case CTF_K_INTEGER:
/* LINTED - pointer alignment */
if (encoding & CTF_INT_CHAR)
else if (encoding & CTF_INT_BOOL)
else if (encoding & CTF_INT_VARARGS)
else
break;
case CTF_K_FLOAT:
/* LINTED - pointer alignment */
break;
case CTF_K_POINTER:
break;
case CTF_K_ARRAY:
/* LINTED - pointer alignment */
dptr += sizeof (ctf_array_t);
break;
case CTF_K_STRUCT:
case CTF_K_UNION:
if (size < CTF_LSTRUCT_THRESH) {
/* LINTED - pointer alignment */
dptr;
dptr += sizeof (ctf_member_t);
}
} else {
/* LINTED - pointer alignment */
dptr;
dptr += sizeof (ctf_lmember_t);
(int)CTF_LMEM_OFFSET(ctlm);
}
}
break;
case CTF_K_ENUM:
/* LINTED - pointer alignment */
dptr += sizeof (ctf_enum_t);
}
break;
case CTF_K_FORWARD:
break;
case CTF_K_TYPEDEF:
break;
case CTF_K_VOLATILE:
break;
case CTF_K_CONST:
break;
case CTF_K_FUNCTION:
/* LINTED - pointer alignment */
for (i = 0; i < vlen; i++) {
/* LINTED - pointer alignment */
if (argid != 0)
}
if (vlen & 1)
break;
case CTF_K_RESTRICT:
break;
case CTF_K_UNKNOWN:
break;
default:
}
else
iicnt++;
}
}
}
/*
* For lack of other inspiration, we're going to take the boring route. We
* count the number of types. This lets us malloc that many tdesc structs
* before we start filling them in. This has the advantage of allowing us to
* avoid a merge-esque remap step.
*/
static tdata_t *
{
int idx, i;
/* shudder */
for (i = 1; i <= ntypes; i++) {
}
/* we have the technology - we can rebuild them */
return (td);
}
static size_t
{
int rc;
return (NULL);
}
}
/*
* Reconstruct the type tree from a given buffer of CTF data. Only the types
* up to the type associated with the provided label, inclusive, will be
* reconstructed. If a NULL label is provided, all types will be reconstructed.
*
* This function won't work on files that have been uniquified.
*/
tdata_t *
{
ctf_header_t *h;
if (bufsz < sizeof (ctf_header_t))
parseterminate("Corrupt CTF - short header");
/* LINTED - pointer alignment */
h = (ctf_header_t *)buf;
buf += sizeof (ctf_header_t);
bufsz -= sizeof (ctf_header_t);
if (h->cth_version != CTF_VERSION)
if (h->cth_flags & CTF_F_COMPRESS) {
ctfdatasz) {
parseterminate("Corrupt CTF - short decompression "
}
} else {
}
if (h->cth_flags & CTF_F_COMPRESS)
return (td);
}