[DWARVES]: Initial CTF support
Using a library written by David S. Miller. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
03a653048e
commit
2dfa5fe6ea
|
@ -27,13 +27,14 @@ endif (NOT CMAKE_BUILD_TYPE)
|
|||
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
find_package(DWARF REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}${CMAKE_INSTALL_PREFIX}/${__LIB}" "libdir")
|
||||
|
||||
set(dwarves_LIB_SRCS dwarves.c dwarf_loader.c)
|
||||
set(dwarves_LIB_SRCS dwarves.c ctf_loader.c libctf.c dwarf_loader.c)
|
||||
add_library(dwarves SHARED ${dwarves_LIB_SRCS})
|
||||
set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1)
|
||||
target_link_libraries(dwarves ${DWARF_LIBRARIES})
|
||||
target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
|
||||
set(dwarves_emit_LIB_SRCS dwarves_emit.c)
|
||||
add_library(dwarves_emit SHARED ${dwarves_emit_LIB_SRCS})
|
||||
|
|
5
MANIFEST
5
MANIFEST
|
@ -1,3 +1,5 @@
|
|||
ctf_loader.c
|
||||
ctf_loader.h
|
||||
dwarf_loader.c
|
||||
dwarf_loader.h
|
||||
dwarves.c
|
||||
|
@ -32,3 +34,6 @@ lib/ctracer_relay.h
|
|||
lib/linux.blacklist.cu
|
||||
ostra/ostra-cg
|
||||
ostra/python/ostra.py
|
||||
ctf.h
|
||||
libctf.c
|
||||
libctf.h
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
#ifndef _CTF_H
|
||||
#define _CTF_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct ctf_header {
|
||||
u_int16_t ctf_magic; /* Header magic value */
|
||||
#define CTF_MAGIC 0xcff1
|
||||
#define CTF_MAGIC_SWAP 0xf1cf
|
||||
|
||||
u_int8_t ctf_version; /* Header version */
|
||||
#define CTF_VERSION 2
|
||||
|
||||
u_int8_t ctf_flags; /* Header flags */
|
||||
#define CTF_FLAGS_COMPR 0x01
|
||||
|
||||
u_int32_t ctf_parent_label; /* Label of parent CTF object */
|
||||
u_int32_t ctf_parent_name; /* Name of parent CTF object */
|
||||
|
||||
/* All offsets are in bytes are relative to the end of
|
||||
* this header.
|
||||
*/
|
||||
u_int32_t ctf_label_off; /* Offset of label section */
|
||||
u_int32_t ctf_object_off; /* Offset of data object section */
|
||||
u_int32_t ctf_func_off; /* Offset of function section */
|
||||
u_int32_t ctf_type_off; /* Offset of type section */
|
||||
u_int32_t ctf_str_off; /* Offset of string section */
|
||||
u_int32_t ctf_str_len; /* Length of string section */
|
||||
};
|
||||
|
||||
#define CTF_REF_OFFSET(REF) ((REF) & 0x7fffffff)
|
||||
#define CTF_REF_TBL_ID(REF) (((REF) >> 31) & 0x1)
|
||||
#define CTF_STR_TBL_ID_0 0
|
||||
#define CTF_STR_TBL_ID_1 1
|
||||
|
||||
#define CTF_REF_ENCODE(TBL, OFF) (((TBL) << 31) | (OFF))
|
||||
|
||||
struct ctf_label_ent {
|
||||
u_int32_t ctf_label_ref;
|
||||
u_int32_t ctf_type_index;
|
||||
};
|
||||
|
||||
/* Types are encoded with ctf_short_type so long as the ctf_size
|
||||
* field can be fully represented in a u_int16_t. If not, then
|
||||
* the ctf_size is given the value 0xffff and ctf_full_type is
|
||||
* used.
|
||||
*/
|
||||
struct ctf_short_type {
|
||||
u_int32_t ctf_name;
|
||||
u_int16_t ctf_info;
|
||||
union {
|
||||
u_int16_t ctf_size;
|
||||
u_int16_t ctf_type;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct ctf_full_type {
|
||||
struct ctf_short_type base;
|
||||
u_int32_t ctf_size_high;
|
||||
u_int32_t ctf_size_low;
|
||||
};
|
||||
|
||||
#define CTF_GET_KIND(VAL) (((VAL) >> 11) & 0x1f)
|
||||
#define CTF_GET_VLEN(VAL) ((VAL) & 0x3ff)
|
||||
#define CTF_ISROOT(VAL) (((VAL) & 0x400) != 0)
|
||||
|
||||
#define CTF_INFO_ENCODE(KIND, VLEN, ISROOT) \
|
||||
(((ISROOT) ? 0x400 : 0) | ((KIND) << 11) | (VLEN))
|
||||
|
||||
#define CTF_TYPE_KIND_UNKN 0 /* Unknown */
|
||||
#define CTF_TYPE_KIND_INT 1 /* Integer */
|
||||
#define CTF_TYPE_KIND_FLT 2 /* Float */
|
||||
#define CTF_TYPE_KIND_PTR 3 /* Pointer */
|
||||
#define CTF_TYPE_KIND_ARR 4 /* Array */
|
||||
#define CTF_TYPE_KIND_FUNC 5 /* Function */
|
||||
#define CTF_TYPE_KIND_STR 6 /* Struct */
|
||||
#define CTF_TYPE_KIND_UNION 7 /* Union */
|
||||
#define CTF_TYPE_KIND_ENUM 8 /* Enumeration */
|
||||
#define CTF_TYPE_KIND_FWD 9 /* Forward */
|
||||
#define CTF_TYPE_KIND_TYPDEF 10 /* Typedef */
|
||||
#define CTF_TYPE_KIND_VOLATILE 11 /* Volatile */
|
||||
#define CTF_TYPE_KIND_CONST 12 /* Const */
|
||||
#define CTF_TYPE_KIND_RESTRICT 13 /* Restrict */
|
||||
#define CTF_TYPE_KIND_MAX 31
|
||||
|
||||
#define CTF_TYPE_INT_ATTRS(VAL) ((VAL) >> 24)
|
||||
#define CTF_TYPE_INT_OFFSET(VAL) (((VAL) >> 16) & 0xff)
|
||||
#define CTF_TYPE_INT_BITS(VAL) ((VAL) & 0xffff)
|
||||
|
||||
#define CTF_TYPE_INT_ENCODE(ATTRS, OFF, BITS) \
|
||||
(((ATTRS) << 24) | ((OFF) << 16) | (BITS))
|
||||
|
||||
/* Integer type attributes */
|
||||
#define CTF_TYPE_INT_SIGNED 0x1
|
||||
#define CTF_TYPE_INT_CHAR 0x2
|
||||
#define CTF_TYPE_INT_BOOL 0x4
|
||||
#define CTF_TYPE_INT_VARARGS 0x8
|
||||
|
||||
#define CTF_TYPE_FP_ATTRS(VAL) ((VAL) >> 24)
|
||||
#define CTF_TYPE_FP_OFFSET(VAL) (((VAL) >> 16) & 0xff)
|
||||
#define CTF_TYPE_FP_BITS(VAL) ((VAL) & 0xffff)
|
||||
|
||||
#define CTF_TYPE_FP_ENCODE(ATTRS, OFF, BITS) \
|
||||
(((ATTRS) << 24) | ((OFF) << 16) | (BITS))
|
||||
|
||||
/* Possible values for the float type attribute field */
|
||||
#define CTF_TYPE_FP_SINGLE 1
|
||||
#define CTF_TYPE_FP_DOUBLE 2
|
||||
#define CTF_TYPE_FP_CMPLX 3
|
||||
#define CTF_TYPE_FP_CMPLX_DBL 4
|
||||
#define CTF_TYPE_FP_CMPLX_LDBL 5
|
||||
#define CTF_TYPE_FP_LDBL 6
|
||||
#define CTF_TYPE_FP_INTVL 7
|
||||
#define CTF_TYPE_FP_INTVL_DBL 8
|
||||
#define CTF_TYPE_FP_INTVL_LDBL 9
|
||||
#define CTF_TYPE_FP_IMGRY 10
|
||||
#define CTF_TYPE_FP_IMGRY_DBL 11
|
||||
#define CTF_TYPE_FP_IMGRY_LDBL 12
|
||||
#define CTF_TYPE_FP_MAX 12
|
||||
|
||||
struct ctf_enum {
|
||||
u_int32_t ctf_enum_name;
|
||||
u_int32_t ctf_enum_val;
|
||||
};
|
||||
|
||||
struct ctf_array {
|
||||
u_int16_t ctf_array_type;
|
||||
u_int16_t ctf_array_index_type;
|
||||
u_int32_t ctf_array_nelems;
|
||||
};
|
||||
|
||||
/* Struct members are encoded with either ctf_short_member or
|
||||
* ctf_full_member, depending upon the 'size' of the struct or
|
||||
* union being defined. If it is less than CTF_SHORT_MEMBER_LIMIT
|
||||
* then ctf_short_member objects are used to encode, else
|
||||
* ctf_full_member is used.
|
||||
*/
|
||||
#define CTF_SHORT_MEMBER_LIMIT 8192
|
||||
|
||||
struct ctf_short_member {
|
||||
u_int32_t ctf_member_name;
|
||||
u_int16_t ctf_member_type;
|
||||
u_int16_t ctf_member_offset;
|
||||
};
|
||||
|
||||
struct ctf_full_member {
|
||||
u_int32_t ctf_member_name;
|
||||
u_int16_t ctf_member_type;
|
||||
u_int16_t ctf_member_unused;
|
||||
u_int32_t ctf_member_offset_high;
|
||||
u_int32_t ctf_member_offset_low;
|
||||
};
|
||||
|
||||
#endif /* _CTF_H */
|
|
@ -0,0 +1,815 @@
|
|||
/* ctfdump.c: CTF dumper.
|
||||
*
|
||||
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include <argp.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <gelf.h>
|
||||
|
||||
#include "libctf.h"
|
||||
#include "ctf.h"
|
||||
#include "dutil.h"
|
||||
#include "dwarves.h"
|
||||
|
||||
static void *zalloc(const size_t size)
|
||||
{
|
||||
void *s = malloc(size);
|
||||
if (s != NULL)
|
||||
memset(s, 0, size);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void oom(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "libclasses: out of memory(%s)\n", msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct ctf_state {
|
||||
Ctf *ctf;
|
||||
Elf *elf;
|
||||
Elf_Data *elf_syms;
|
||||
Elf_Data *elf_symstrs;
|
||||
struct cu *cu;
|
||||
int elf_num_syms;
|
||||
int in_fd;
|
||||
};
|
||||
|
||||
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
|
||||
GElf_Shdr *shp, const char *name)
|
||||
{
|
||||
Elf_Scn *sec = NULL;
|
||||
|
||||
while ((sec = elf_nextscn(elf, sec)) != NULL) {
|
||||
char *str;
|
||||
|
||||
gelf_getshdr(sec, shp);
|
||||
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
|
||||
if (!strcmp(name, str))
|
||||
break;
|
||||
}
|
||||
|
||||
return sec;
|
||||
}
|
||||
|
||||
struct elf_sym_iter_state {
|
||||
int (*func)(struct ctf_state *sp, const char *sym_name,
|
||||
int sym_index, int call_index, void *data);
|
||||
void *data;
|
||||
|
||||
int st_type;
|
||||
int limit;
|
||||
};
|
||||
|
||||
#if 0
|
||||
static int ctf_ignores_elf_symbol(GElf_Sym *sym, char *name, int type)
|
||||
{
|
||||
if (type == STT_OBJECT &&
|
||||
sym->st_shndx == SHN_ABS &&
|
||||
sym->st_value == 0)
|
||||
return 1;
|
||||
if (sym->st_name == 0)
|
||||
return 1;
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
return 1;
|
||||
if (!strcmp(name, "_START_") || !strcmp(name, "_END_"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elf_symbol_iterate(struct ctf_state *sp,
|
||||
struct elf_sym_iter_state *ep)
|
||||
{
|
||||
int i, index;
|
||||
|
||||
index = 0;
|
||||
for (i = 0; i < sp->elf_num_syms; i++) {
|
||||
GElf_Sym sym;
|
||||
char *name;
|
||||
int type;
|
||||
|
||||
if (gelf_getsym(sp->elf_syms, i, &sym) == NULL) {
|
||||
fprintf(stderr, "Could not get ELF symbol %d.\n", i);
|
||||
exit(2);
|
||||
}
|
||||
type = GELF_ST_TYPE(sym.st_info);
|
||||
name = (char *)sp->elf_symstrs->d_buf + sym.st_name;
|
||||
|
||||
if ((ep->st_type == -1 || ep->st_type == type) &&
|
||||
!ctf_ignores_elf_symbol(&sym, name, type)) {
|
||||
if (index >= ep->limit) {
|
||||
fprintf(stderr, "Symbol limit reached "
|
||||
"([%u], %d vs %d).\n",
|
||||
ep->limit, i, sp->elf_num_syms);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (ep->func(sp, name, i, index++, ep->data) < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parse_elf(struct ctf_state *sp)
|
||||
{
|
||||
GElf_Ehdr ehdr;
|
||||
GElf_Shdr shdr;
|
||||
Elf_Data *data;
|
||||
Elf_Scn *sec;
|
||||
|
||||
if (gelf_getehdr(sp->elf, &ehdr) == NULL) {
|
||||
fprintf(stderr, "Cannot get elf header.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
sec = elf_section_by_name(sp->elf, &ehdr, &shdr, ".SUNW_ctf");
|
||||
if (!sec) {
|
||||
fprintf(stderr, "File has no CTF section.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
data = elf_getdata(sec, NULL);
|
||||
if (!data) {
|
||||
fprintf(stderr, "Cannot get data of CTF section.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
sp->ctf = ctf_begin(data->d_buf, data->d_size);
|
||||
if (!sp->ctf) {
|
||||
fprintf(stderr, "Cannot initialize CTF state.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (shdr.sh_link != 0)
|
||||
sec = elf_getscn(sp->elf, shdr.sh_link);
|
||||
else
|
||||
sec = elf_section_by_name(sp->elf, &ehdr, &shdr, ".symtab");
|
||||
|
||||
if (!sec)
|
||||
return;
|
||||
|
||||
if (gelf_getshdr(sec, &shdr) != NULL) {
|
||||
sp->elf_syms = elf_getdata(sec, NULL);
|
||||
sp->elf_num_syms = shdr.sh_size / shdr.sh_entsize;
|
||||
|
||||
sec = elf_getscn(sp->elf, shdr.sh_link);
|
||||
sp->elf_symstrs = elf_getdata(sec, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static char *ctf_string(u_int32_t ref, struct ctf_state *sp)
|
||||
{
|
||||
struct ctf_header *hp = ctf_get_buffer(sp->ctf);
|
||||
u_int32_t off = CTF_REF_OFFSET(ref);
|
||||
char *name;
|
||||
|
||||
if (CTF_REF_TBL_ID(ref) != CTF_STR_TBL_ID_0)
|
||||
return "(external ref)";
|
||||
|
||||
if (off >= ctf_get32(sp->ctf, &hp->ctf_str_len))
|
||||
return "(ref out-of-bounds)";
|
||||
|
||||
if ((off + ctf_get32(sp->ctf, &hp->ctf_str_off)) >=
|
||||
ctf_get_size(sp->ctf))
|
||||
return "(string table truncated)";
|
||||
|
||||
name = ((char *)(hp + 1) + ctf_get32(sp->ctf, &hp->ctf_str_off) + off);
|
||||
if (name[0] == '\0')
|
||||
return "(anonymous)";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static char *ctf_format_flt_attrs(u_int32_t eval, char *buf)
|
||||
{
|
||||
u_int32_t attrs = CTF_TYPE_FP_ATTRS(eval);
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
if (attrs < CTF_TYPE_FP_SINGLE ||
|
||||
attrs > CTF_TYPE_FP_MAX)
|
||||
buf += sprintf(buf, "0x%02x ", attrs);
|
||||
else {
|
||||
switch (attrs) {
|
||||
case CTF_TYPE_FP_SINGLE:
|
||||
buf += sprintf(buf, "single ");
|
||||
break;
|
||||
case CTF_TYPE_FP_DOUBLE:
|
||||
buf += sprintf(buf, "double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_CMPLX:
|
||||
buf += sprintf(buf, "complex ");
|
||||
break;
|
||||
case CTF_TYPE_FP_CMPLX_DBL:
|
||||
buf += sprintf(buf, "complex double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_CMPLX_LDBL:
|
||||
buf += sprintf(buf, "complex long double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_LDBL:
|
||||
buf += sprintf(buf, "long double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_INTVL:
|
||||
buf += sprintf(buf, "interval ");
|
||||
break;
|
||||
case CTF_TYPE_FP_INTVL_DBL:
|
||||
buf += sprintf(buf, "interval double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_INTVL_LDBL:
|
||||
buf += sprintf(buf, "interval long double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_IMGRY:
|
||||
buf += sprintf(buf, "imaginary ");
|
||||
break;
|
||||
case CTF_TYPE_FP_IMGRY_DBL:
|
||||
buf += sprintf(buf, "imaginary double ");
|
||||
break;
|
||||
case CTF_TYPE_FP_IMGRY_LDBL:
|
||||
buf += sprintf(buf, "imaginary long double ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int dump_one_func(struct ctf_state *sp, const char *sym_name,
|
||||
int sym_index, int call_index, void *data)
|
||||
{
|
||||
u_int16_t **func_pp = data;
|
||||
u_int16_t val = ctf_get16(sp->ctf, *func_pp);
|
||||
u_int16_t type = CTF_GET_KIND(val);
|
||||
u_int16_t vlen = CTF_GET_VLEN(val);
|
||||
u_int16_t i;
|
||||
|
||||
(*func_pp)++;
|
||||
|
||||
if (type == CTF_TYPE_KIND_UNKN && vlen == 0)
|
||||
return 0;
|
||||
|
||||
if (type != CTF_TYPE_KIND_FUNC) {
|
||||
fprintf(stderr, "Expected function type, got %u\n", type);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
fprintf(stdout, " [%6d] %-36s %8d\n",
|
||||
call_index, sym_name, sym_index);
|
||||
fprintf(stdout, " 0x%04x (",
|
||||
ctf_get16(sp->ctf, *func_pp));
|
||||
|
||||
(*func_pp)++;
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (i >= 1)
|
||||
fprintf(stdout, ", ");
|
||||
|
||||
fprintf(stdout, "0x%04x", ctf_get16(sp->ctf, *func_pp));
|
||||
(*func_pp)++;
|
||||
}
|
||||
fprintf(stdout, ")\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_funcs(struct ctf_state *sp)
|
||||
{
|
||||
struct ctf_header *hp = ctf_get_buffer(sp->ctf);
|
||||
struct elf_sym_iter_state estate;
|
||||
u_int16_t *func_ptr;
|
||||
|
||||
fprintf(stdout, "CTF Functions:\n");
|
||||
fprintf(stdout,
|
||||
" [ Nr ] "
|
||||
"SymName "
|
||||
"SymIndex\n"
|
||||
" Returns "
|
||||
"Args\n");
|
||||
|
||||
memset(&estate, 0, sizeof(estate));
|
||||
func_ptr = ctf_get_buffer(sp->ctf) + sizeof(*hp) +
|
||||
ctf_get32(sp->ctf, &hp->ctf_func_off);
|
||||
estate.data = &func_ptr;
|
||||
estate.func = dump_one_func;
|
||||
estate.st_type = STT_FUNC;
|
||||
estate.limit = INT_MAX;
|
||||
|
||||
elf_symbol_iterate(sp, &estate);
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct base_type *base_type__new(const char *name, size_t size)
|
||||
{
|
||||
struct base_type *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self != NULL) {
|
||||
self->name = strings__add(name);
|
||||
self->size = size / 8;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static void type__init(struct type *self, uint16_t tag, unsigned int id,
|
||||
const char *name, size_t size)
|
||||
{
|
||||
INIT_LIST_HEAD(&self->node);
|
||||
INIT_LIST_HEAD(&self->namespace.tags);
|
||||
self->size = size;
|
||||
self->namespace.tag.id = id;
|
||||
self->namespace.tag.tag = tag;
|
||||
self->namespace.name = strings__add(name[0] == '(' ? NULL : name);
|
||||
}
|
||||
|
||||
static struct type *type__new(uint16_t tag, unsigned int id,
|
||||
const char *name, size_t size)
|
||||
{
|
||||
struct type *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self != NULL)
|
||||
type__init(self, tag, id, name, size);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static struct class *class__new(const char *name, unsigned int id, size_t size)
|
||||
{
|
||||
struct class *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self != NULL) {
|
||||
type__init(&self->type, DW_TAG_structure_type, id, name, size);
|
||||
INIT_LIST_HEAD(&self->vtable);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static int create_new_base_type(struct ctf_state *sp, void *ptr,
|
||||
int vlen __unused, struct ctf_full_type *tp,
|
||||
unsigned int id)
|
||||
{
|
||||
u_int32_t *enc = ptr, name_idx;
|
||||
char name[64], *buf = name;
|
||||
u_int32_t eval = ctf_get32(sp->ctf, enc);
|
||||
u_int32_t attrs = CTF_TYPE_INT_ATTRS(eval);
|
||||
struct base_type *base;
|
||||
|
||||
if (attrs & CTF_TYPE_INT_SIGNED)
|
||||
buf += sprintf(buf, "signed ");
|
||||
if (attrs & CTF_TYPE_INT_CHAR)
|
||||
buf += sprintf(buf, "char ");
|
||||
if (attrs & CTF_TYPE_INT_BOOL)
|
||||
buf += sprintf(buf, "bool ");
|
||||
if (attrs & CTF_TYPE_INT_VARARGS)
|
||||
buf += sprintf(buf, "varargs ");
|
||||
|
||||
name_idx = ctf_get32(sp->ctf, &tp->base.ctf_name);
|
||||
buf += sprintf(buf, "%s", ctf_string(name_idx, sp));
|
||||
base = base_type__new(name, CTF_TYPE_INT_BITS(eval));
|
||||
if (base == NULL)
|
||||
oom("base_type__new");
|
||||
|
||||
base->tag.tag = DW_TAG_base_type;
|
||||
base->tag.id = id;
|
||||
cu__add_tag(sp->cu, &base->tag);
|
||||
|
||||
return sizeof(*enc);
|
||||
}
|
||||
|
||||
static int create_new_base_type_float(struct ctf_state *sp, void *ptr,
|
||||
int vlen __unused,
|
||||
struct ctf_full_type *tp,
|
||||
unsigned int id)
|
||||
{
|
||||
u_int32_t *enc = ptr, eval;
|
||||
char name[64];
|
||||
struct base_type *base;
|
||||
|
||||
eval = ctf_get32(sp->ctf, enc);
|
||||
sprintf(ctf_format_flt_attrs(eval, name), "%s",
|
||||
ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp));
|
||||
|
||||
base = base_type__new(name, CTF_TYPE_FP_BITS(eval));
|
||||
if (base == NULL)
|
||||
oom("base_type__new");
|
||||
|
||||
base->tag.tag = DW_TAG_base_type;
|
||||
base->tag.id = id;
|
||||
cu__add_tag(sp->cu, &base->tag);
|
||||
|
||||
return sizeof(*enc);
|
||||
}
|
||||
|
||||
static int create_new_array(struct ctf_state *sp, void *ptr,
|
||||
int vlen __unused,
|
||||
struct ctf_full_type *tp __unused,
|
||||
unsigned int id)
|
||||
{
|
||||
struct ctf_array *ap = ptr;
|
||||
struct array_type *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self == NULL)
|
||||
oom("array_type");
|
||||
|
||||
/* FIXME: where to get the number of dimensions?
|
||||
* it it flattened? */
|
||||
self->dimensions = 1;
|
||||
self->nr_entries = malloc(sizeof(uint32_t));
|
||||
|
||||
if (self->nr_entries == NULL)
|
||||
oom("array_type->nr_entries");
|
||||
|
||||
self->nr_entries[0] = ctf_get32(sp->ctf, &ap->ctf_array_nelems);
|
||||
self->tag.tag = DW_TAG_array_type;
|
||||
self->tag.id = id;
|
||||
self->tag.type = ctf_get16(sp->ctf, &ap->ctf_array_type);
|
||||
|
||||
cu__add_tag(sp->cu, &self->tag);
|
||||
|
||||
return sizeof(*ap);
|
||||
}
|
||||
|
||||
static int create_new_subroutine_type(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct ctf_full_type *tp,
|
||||
unsigned int id)
|
||||
{
|
||||
u_int16_t *args = ptr;
|
||||
u_int16_t i;
|
||||
const char *name = ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp);
|
||||
unsigned int type = ctf_get16(sp->ctf, &tp->base.u.ctf_type);
|
||||
struct function *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self == NULL)
|
||||
oom("function__new");
|
||||
|
||||
self->name = strings__add(name);
|
||||
INIT_LIST_HEAD(&self->vtable_node);
|
||||
INIT_LIST_HEAD(&self->tool_node);
|
||||
INIT_LIST_HEAD(&self->proto.parms);
|
||||
self->proto.tag.tag = DW_TAG_subroutine_type;
|
||||
self->proto.tag.id = id;
|
||||
self->proto.tag.type = type;
|
||||
INIT_LIST_HEAD(&self->lexblock.tags);
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
//fprintf(stdout, "0x%04x", ctf_get16(sp->ctf, &args[i]));
|
||||
}
|
||||
|
||||
vlen *= sizeof(*args);
|
||||
|
||||
/* Round up to next multiple of 4 to maintain
|
||||
* 32-bit alignment.
|
||||
*/
|
||||
if (vlen & 0x2)
|
||||
vlen += 0x2;
|
||||
|
||||
cu__add_tag(sp->cu, &self->proto.tag);
|
||||
|
||||
return vlen;
|
||||
}
|
||||
|
||||
static unsigned long create_full_members(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct type *class)
|
||||
{
|
||||
struct ctf_full_member *mp = ptr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
struct class_member *member = zalloc(sizeof(*member));
|
||||
uint32_t bit_offset;
|
||||
|
||||
if (member == NULL)
|
||||
oom("class_member");
|
||||
|
||||
member->tag.tag = DW_TAG_member;
|
||||
member->tag.type = ctf_get16(sp->ctf, &mp[i].ctf_member_type);
|
||||
member->name = strings__add(ctf_string(ctf_get32(sp->ctf, &mp[i].ctf_member_name), sp));
|
||||
bit_offset = (ctf_get32(sp->ctf, &mp[i].ctf_member_offset_high) << 16) |
|
||||
ctf_get32(sp->ctf, &mp[i].ctf_member_offset_low);
|
||||
member->offset = bit_offset / 8;
|
||||
member->bit_offset = bit_offset % 8;
|
||||
type__add_member(class, member);
|
||||
hashtags__hash(sp->cu->hash_tags, &member->tag);
|
||||
}
|
||||
|
||||
return sizeof(*mp);
|
||||
}
|
||||
|
||||
static unsigned long create_short_members(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct type *class)
|
||||
{
|
||||
struct ctf_short_member *mp = ptr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
struct class_member *member = zalloc(sizeof(*member));
|
||||
uint32_t bit_offset;
|
||||
|
||||
if (member == NULL)
|
||||
oom("class_member");
|
||||
|
||||
member->tag.tag = DW_TAG_member;
|
||||
member->tag.type = ctf_get16(sp->ctf, &mp[i].ctf_member_type);
|
||||
member->name = strings__add(ctf_string(ctf_get32(sp->ctf, &mp[i].ctf_member_name), sp));
|
||||
bit_offset = ctf_get16(sp->ctf, &mp[i].ctf_member_offset);
|
||||
member->offset = bit_offset / 8;
|
||||
member->bit_offset = bit_offset % 8;
|
||||
|
||||
type__add_member(class, member);
|
||||
hashtags__hash(sp->cu->hash_tags, &member->tag);
|
||||
}
|
||||
|
||||
return sizeof(*mp);
|
||||
}
|
||||
|
||||
static int create_new_class(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct ctf_full_type *tp,
|
||||
u_int64_t size, unsigned int id)
|
||||
{
|
||||
unsigned long member_size;
|
||||
const char *name = ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp);
|
||||
struct class *self = class__new(name, id, size);
|
||||
|
||||
if (size >= CTF_SHORT_MEMBER_LIMIT) {
|
||||
member_size = create_full_members(sp, ptr, vlen, &self->type);
|
||||
} else {
|
||||
member_size = create_short_members(sp, ptr, vlen, &self->type);
|
||||
}
|
||||
|
||||
cu__add_tag(sp->cu, &self->type.namespace.tag);
|
||||
|
||||
return (vlen * member_size);
|
||||
}
|
||||
|
||||
static int create_new_union(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct ctf_full_type *tp,
|
||||
u_int64_t size, unsigned int id)
|
||||
{
|
||||
unsigned long member_size;
|
||||
const char *name = ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp);
|
||||
struct type *self = type__new(DW_TAG_union_type, id, name, size);
|
||||
|
||||
if (size >= CTF_SHORT_MEMBER_LIMIT) {
|
||||
member_size = create_full_members(sp, ptr, vlen, self);
|
||||
} else {
|
||||
member_size = create_short_members(sp, ptr, vlen, self);
|
||||
}
|
||||
|
||||
cu__add_tag(sp->cu, &self->namespace.tag);
|
||||
|
||||
return (vlen * member_size);
|
||||
}
|
||||
|
||||
static struct enumerator *enumerator__new(const char *name,
|
||||
uint32_t value)
|
||||
{
|
||||
struct enumerator *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self != NULL) {
|
||||
self->name = strings__add(name);
|
||||
self->value = value;
|
||||
self->tag.tag = DW_TAG_enumerator;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static int create_new_enumeration(struct ctf_state *sp, void *ptr,
|
||||
int vlen, struct ctf_full_type *tp,
|
||||
unsigned int id)
|
||||
{
|
||||
struct ctf_enum *ep = ptr;
|
||||
u_int16_t i;
|
||||
struct type *enumeration = type__new(DW_TAG_enumeration_type, id,
|
||||
ctf_string(ctf_get32(sp->ctf,
|
||||
&tp->base.ctf_name), sp), 0);
|
||||
|
||||
if (enumeration == NULL)
|
||||
oom("enumeration");
|
||||
|
||||
for (i = 0; i < vlen; i++) {
|
||||
char *name = ctf_string(ctf_get32(sp->ctf, &ep[i].ctf_enum_name), sp);
|
||||
uint32_t value = ctf_get32(sp->ctf, &ep[i].ctf_enum_val);
|
||||
struct enumerator *enumerator = enumerator__new(name, value);
|
||||
|
||||
if (enumerator == NULL)
|
||||
oom("enumerator__new");
|
||||
|
||||
enumeration__add(enumeration, enumerator);
|
||||
hashtags__hash(sp->cu->hash_tags, &enumerator->tag);
|
||||
}
|
||||
|
||||
cu__add_tag(sp->cu, &enumeration->namespace.tag);
|
||||
|
||||
return (vlen * sizeof(*ep));
|
||||
}
|
||||
|
||||
static int create_new_forward_decl(struct ctf_state *sp, void *ptr __unused,
|
||||
int vlen __unused, struct ctf_full_type *tp,
|
||||
u_int64_t size, unsigned int id)
|
||||
{
|
||||
char *name = ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp);
|
||||
struct class *self = class__new(name, id, size);
|
||||
|
||||
if (self == NULL)
|
||||
oom("class foward decl");
|
||||
self->type.declaration = 1;
|
||||
cu__add_tag(sp->cu, &self->type.namespace.tag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_new_typedef(struct ctf_state *sp, int type,
|
||||
void *ptr __unused, int vlen __unused,
|
||||
struct ctf_full_type *tp,
|
||||
u_int64_t size, unsigned int id)
|
||||
{
|
||||
const char *name = ctf_string(ctf_get32(sp->ctf, &tp->base.ctf_name), sp);
|
||||
unsigned int type_id = ctf_get16(sp->ctf, &tp->base.u.ctf_type);
|
||||
unsigned int tag;
|
||||
struct type *self;
|
||||
|
||||
switch (type) {
|
||||
case CTF_TYPE_KIND_TYPDEF: tag = DW_TAG_typedef; break;
|
||||
default:
|
||||
printf("%s: FOO %d\n\n", __func__, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
self = type__new(tag, id, name, size);
|
||||
if (self == NULL)
|
||||
oom("type__new");
|
||||
self->namespace.tag.type = type_id;
|
||||
cu__add_tag(sp->cu, &self->namespace.tag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_new_tag(struct ctf_state *sp, int type,
|
||||
void *ptr __unused, int vlen __unused,
|
||||
struct ctf_full_type *tp, unsigned int id)
|
||||
{
|
||||
unsigned int type_id = ctf_get16(sp->ctf, &tp->base.u.ctf_type);
|
||||
struct tag *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self == NULL)
|
||||
oom("tag__new");
|
||||
|
||||
switch (type) {
|
||||
case CTF_TYPE_KIND_CONST: self->tag = DW_TAG_const_type; break;
|
||||
case CTF_TYPE_KIND_PTR: self->tag = DW_TAG_pointer_type; break;
|
||||
case CTF_TYPE_KIND_RESTRICT: self->tag = DW_TAG_restrict_type; break;
|
||||
case CTF_TYPE_KIND_VOLATILE: self->tag = DW_TAG_volatile_type; break;
|
||||
default:
|
||||
printf("%s: FOO %d\n\n", __func__, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->id = id;
|
||||
self->type = type_id;
|
||||
cu__add_tag(sp->cu, self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void load_types(struct ctf_state *sp)
|
||||
{
|
||||
struct ctf_header *hp = ctf_get_buffer(sp->ctf);
|
||||
struct ctf_full_type *type_ptr, *end;
|
||||
unsigned int type_index;
|
||||
|
||||
type_ptr = ctf_get_buffer(sp->ctf) + sizeof(*hp) +
|
||||
ctf_get32(sp->ctf, &hp->ctf_type_off);
|
||||
end = ctf_get_buffer(sp->ctf) + sizeof(*hp) +
|
||||
ctf_get32(sp->ctf, &hp->ctf_str_off);
|
||||
|
||||
type_index = 0x0001;
|
||||
if (hp->ctf_parent_name ||
|
||||
hp->ctf_parent_label)
|
||||
type_index += 0x8000;
|
||||
|
||||
while (type_ptr < end) {
|
||||
u_int16_t val, type, vlen, base_size;
|
||||
u_int64_t size;
|
||||
void *ptr;
|
||||
|
||||
val = ctf_get16(sp->ctf, &type_ptr->base.ctf_info);
|
||||
type = CTF_GET_KIND(val);
|
||||
vlen = CTF_GET_VLEN(val);
|
||||
|
||||
base_size = ctf_get16(sp->ctf, &type_ptr->base.u.ctf_size);
|
||||
ptr = type_ptr;
|
||||
if (base_size == 0xffff) {
|
||||
size = ctf_get32(sp->ctf, &type_ptr->ctf_size_high);
|
||||
size <<= 32;
|
||||
size |= ctf_get32(sp->ctf, &type_ptr->ctf_size_low);
|
||||
ptr += sizeof(struct ctf_full_type);
|
||||
} else {
|
||||
size = base_size;
|
||||
ptr += sizeof(struct ctf_short_type);
|
||||
}
|
||||
|
||||
if (type == CTF_TYPE_KIND_INT) {
|
||||
vlen = create_new_base_type(sp, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_FLT) {
|
||||
vlen = create_new_base_type_float(sp, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_ARR) {
|
||||
vlen = create_new_array(sp, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_FUNC) {
|
||||
vlen = create_new_subroutine_type(sp, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_STR) {
|
||||
vlen = create_new_class(sp, ptr,
|
||||
vlen, type_ptr, size, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_UNION) {
|
||||
vlen = create_new_union(sp, ptr,
|
||||
vlen, type_ptr, size, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_ENUM) {
|
||||
vlen = create_new_enumeration(sp, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_FWD) {
|
||||
vlen = create_new_forward_decl(sp, ptr, vlen, type_ptr, size, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_TYPDEF) {
|
||||
vlen = create_new_typedef(sp, type, ptr, vlen, type_ptr, size, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_VOLATILE ||
|
||||
type == CTF_TYPE_KIND_PTR ||
|
||||
type == CTF_TYPE_KIND_CONST ||
|
||||
type == CTF_TYPE_KIND_RESTRICT) {
|
||||
vlen = create_new_tag(sp, type, ptr, vlen, type_ptr, type_index);
|
||||
} else if (type == CTF_TYPE_KIND_UNKN) {
|
||||
printf("CTF: [%#6x] %1d Unknown\n", type_index, CTF_ISROOT(val));
|
||||
vlen = 0;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
type_ptr = ptr + vlen;
|
||||
type_index++;
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_ctf(struct ctf_state *sp)
|
||||
{
|
||||
//dump_funcs(sp);
|
||||
load_types(sp);
|
||||
}
|
||||
|
||||
static void open_files(struct ctf_state *sp, const char *in_filename)
|
||||
{
|
||||
sp->in_fd = -1;
|
||||
if (in_filename) {
|
||||
sp->in_fd = open(in_filename, O_RDONLY);
|
||||
if (sp->in_fd < 0) {
|
||||
perror("open");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ctf__load(struct cus *self, struct argp *argp __unused,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
struct ctf_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
open_files(&state, argv[argc - 1]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) {
|
||||
fprintf(stderr, "Cannot set libelf version.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
state.elf = elf_begin(state.in_fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!state.elf) {
|
||||
fprintf(stderr, "Cannot read ELF file.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
parse_elf(&state);
|
||||
|
||||
state.cu = cu__new("FIXME.c", 8, NULL, 0);
|
||||
if (state.cu == NULL)
|
||||
oom("cu__new");
|
||||
|
||||
cus__add(self, state.cu);
|
||||
|
||||
dump_ctf(&state);
|
||||
|
||||
elf_end(state.elf);
|
||||
|
||||
close(state.in_fd);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _CTF_LOADER_H_
|
||||
#define _CTF_LOADER_H_ 1
|
||||
/*
|
||||
Copyright (C) 2008 Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
struct cus;
|
||||
struct argp;
|
||||
|
||||
int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[]);
|
||||
|
||||
#endif /* _CTF_LOADER_H_ */
|
18
dwarves.c
18
dwarves.c
|
@ -24,6 +24,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ctf_loader.h"
|
||||
#include "dwarf_loader.h"
|
||||
#include "list.h"
|
||||
#include "dwarves.h"
|
||||
|
@ -1292,8 +1293,10 @@ static size_t union__fprintf(struct type *self, const struct cu *cu,
|
|||
|
||||
if (type == NULL) {
|
||||
tag__type_not_found(&pos->tag);
|
||||
printed += fprintf(fp, "%.*s>>>ERROR: type for %s not "
|
||||
"found!\n", uconf.indent, tabs, pos->name);
|
||||
printed += fprintf(fp, "%.*s>>>ERROR: type(%#llx) for %s not "
|
||||
"found!\n", uconf.indent, tabs,
|
||||
(unsigned long long)pos->tag.type,
|
||||
pos->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2096,8 +2099,10 @@ size_t class__fprintf(struct class *self, const struct cu *cu,
|
|||
type = cu__find_tag_by_id(cu, pos->tag.type);
|
||||
if (type == NULL) {
|
||||
tag__type_not_found(&pos->tag);
|
||||
printed += fprintf(fp, "%.*s>>>ERROR: type for %s not "
|
||||
"found!\n", cconf.indent, tabs, pos->name);
|
||||
printed += fprintf(fp, "%.*s>>>ERROR: type(%#llx) for %s not "
|
||||
"found!\n", cconf.indent, tabs,
|
||||
(unsigned long long)pos->tag.type,
|
||||
pos->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2513,7 +2518,12 @@ int cus__loadfl(struct cus *self, struct argp *argp, int argc, char *argv[])
|
|||
* for the magic types they support or just pass them the file,
|
||||
* unloading the shared object if it says its not the type they
|
||||
* support.
|
||||
* FIXME: for now we just check if no DWARF info was found
|
||||
* by looking at the list of CUs found:
|
||||
*/
|
||||
if (list_empty(&self->cus))
|
||||
err = ctf__load(self, argp, argc, argv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "libctf.h"
|
||||
#include "ctf.h"
|
||||
|
||||
struct Ctf {
|
||||
void *buf;
|
||||
size_t size;
|
||||
int swapped;
|
||||
};
|
||||
|
||||
u_int16_t ctf_get16(Ctf *cp, u_int16_t *p)
|
||||
{
|
||||
u_int16_t val = *p;
|
||||
|
||||
if (cp->swapped)
|
||||
val = ((val >> 8) | (val << 8));
|
||||
return val;
|
||||
}
|
||||
|
||||
u_int32_t ctf_get32(Ctf *cp, u_int32_t *p)
|
||||
{
|
||||
u_int32_t val = *p;
|
||||
|
||||
if (cp->swapped)
|
||||
val = ((val >> 24) |
|
||||
((val >> 8) & 0x0000ff00) |
|
||||
((val << 8) & 0x00ff0000) |
|
||||
(val << 24));
|
||||
return val;
|
||||
}
|
||||
|
||||
void ctf_put16(Ctf *cp, u_int16_t *p, u_int16_t val)
|
||||
{
|
||||
if (cp->swapped)
|
||||
val = ((val >> 8) | (val << 8));
|
||||
*p = val;
|
||||
}
|
||||
|
||||
void ctf_put32(Ctf *cp, u_int32_t *p, u_int32_t val)
|
||||
{
|
||||
if (cp->swapped)
|
||||
val = ((val >> 24) |
|
||||
((val >> 8) & 0x0000ff00) |
|
||||
((val << 8) & 0x00ff0000) |
|
||||
(val << 24));
|
||||
*p = val;
|
||||
}
|
||||
|
||||
static int decompress_ctf(struct Ctf *cp, void *orig_buf, size_t orig_size)
|
||||
{
|
||||
struct ctf_header *hp = orig_buf;
|
||||
const char *err_str;
|
||||
z_stream state;
|
||||
size_t len;
|
||||
void *new;
|
||||
|
||||
len = (ctf_get32(cp, &hp->ctf_str_off) +
|
||||
ctf_get32(cp, &hp->ctf_str_len));
|
||||
new = malloc(len + sizeof(*hp));
|
||||
if (!new) {
|
||||
fprintf(stderr, "CTF decompression allocation failure.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(new, hp, sizeof(*hp));
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.next_in = (Bytef *) (hp + 1);
|
||||
state.avail_in = orig_size - sizeof(*hp);
|
||||
state.next_out = new + sizeof(*hp);
|
||||
state.avail_out = len;
|
||||
|
||||
if (inflateInit(&state) != Z_OK) {
|
||||
err_str = "Ctf decompression inflateInit failure.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (inflate(&state, Z_FINISH) != Z_STREAM_END) {
|
||||
err_str = "Ctf decompression inflate failure.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (inflateEnd(&state) != Z_OK) {
|
||||
err_str = "Ctf decompression inflateEnd failure.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (state.total_out != len) {
|
||||
err_str = "Ctf decompression truncation error.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
cp->buf = new;
|
||||
cp->size = len + sizeof(*hp);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fputs(err_str, stderr);
|
||||
free(new);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Ctf *ctf_begin(void *orig_buf, size_t orig_size)
|
||||
{
|
||||
struct ctf_header *hp = orig_buf;
|
||||
struct Ctf *cp;
|
||||
int swapped;
|
||||
|
||||
if (hp->ctf_magic == CTF_MAGIC)
|
||||
swapped = 0;
|
||||
else if (hp->ctf_magic == CTF_MAGIC_SWAP)
|
||||
swapped = 1;
|
||||
else {
|
||||
fprintf(stderr, "Bad CTF magic %04x.\n", hp->ctf_magic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hp->ctf_version != CTF_VERSION) {
|
||||
fprintf(stderr, "Bad CTF version %u, expected %u.\n",
|
||||
hp->ctf_version, CTF_VERSION);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cp = malloc(sizeof(*cp));
|
||||
if (!cp) {
|
||||
fprintf(stderr, "Ctf allocation failure.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(cp, 0, sizeof(*cp));
|
||||
cp->swapped = swapped;
|
||||
|
||||
if (!(hp->ctf_flags & CTF_FLAGS_COMPR)) {
|
||||
cp->buf = malloc(orig_size);
|
||||
if (!cp->buf) {
|
||||
fprintf(stderr, "Ctf buffer allocation failure.\n");
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(cp->buf, orig_buf, orig_size);
|
||||
cp->size = orig_size;
|
||||
|
||||
return cp;
|
||||
} else {
|
||||
int err = decompress_ctf(cp, orig_buf, orig_size);
|
||||
|
||||
if (err) {
|
||||
fprintf(stderr, "Ctf decompression failure.\n");
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
void ctf_end(Ctf *cp)
|
||||
{
|
||||
free(cp->buf);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void *ctf_get_buffer(Ctf *cp)
|
||||
{
|
||||
return cp->buf;
|
||||
}
|
||||
|
||||
size_t ctf_get_size(Ctf *cp)
|
||||
{
|
||||
return cp->size;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _LIBCTF_H
|
||||
#define _LIBCTF_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct Ctf Ctf;
|
||||
|
||||
extern Ctf *ctf_begin(void *buf, size_t size);
|
||||
extern void ctf_end(Ctf *ctf);
|
||||
|
||||
extern u_int16_t ctf_get16(Ctf *cp, u_int16_t *p);
|
||||
extern u_int32_t ctf_get32(Ctf *cp, u_int32_t *p);
|
||||
extern void ctf_put16(Ctf *cp, u_int16_t *p, u_int16_t val);
|
||||
extern void ctf_put32(Ctf *cp, u_int32_t *p, u_int32_t val);
|
||||
|
||||
extern void *ctf_get_buffer(Ctf *cp);
|
||||
extern size_t ctf_get_size(Ctf *cp);
|
||||
|
||||
#endif /* _LIBCTF_H */
|
Loading…
Reference in New Issue