ctf: Include the initial implementation of a ctf encoder
"pahole -Z foo" will create foo.SUNW_ctf, that if objcopy --add-section'ed to the right word-sized object will work, sans VARARGS, that will get fixed soon (as in, probably, tomorrow). Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
b27463f995
commit
feab8aa5e3
|
@ -32,7 +32,7 @@ find_package(ZLIB REQUIRED)
|
||||||
|
|
||||||
_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}${CMAKE_INSTALL_PREFIX}/${__LIB}" "libdir")
|
_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}${CMAKE_INSTALL_PREFIX}/${__LIB}" "libdir")
|
||||||
|
|
||||||
set(dwarves_LIB_SRCS dwarves.c gobuffer strings ctf_loader.c libctf.c dwarf_loader.c dutil.c)
|
set(dwarves_LIB_SRCS dwarves.c gobuffer strings ctf_encoder.c ctf_loader.c libctf.c dwarf_loader.c dutil.c)
|
||||||
add_library(dwarves SHARED ${dwarves_LIB_SRCS})
|
add_library(dwarves SHARED ${dwarves_LIB_SRCS})
|
||||||
set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1)
|
set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1)
|
||||||
target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES})
|
target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat Inc.
|
||||||
|
Copyright (C) 2009 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dwarves.h"
|
||||||
|
#include "libctf.h"
|
||||||
|
#include "ctf.h"
|
||||||
|
|
||||||
|
static int tag__check_id_drift(const struct tag *self,
|
||||||
|
uint16_t core_id, uint16_t ctf_id)
|
||||||
|
{
|
||||||
|
if (ctf_id != core_id) {
|
||||||
|
fprintf(stderr, "%s: %s id drift, core: %u, libctf: %d\n",
|
||||||
|
__func__, dwarf_tag_name(self->tag), core_id, ctf_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwarf_to_ctf_type(uint16_t tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case DW_TAG_const_type: return CTF_TYPE_KIND_CONST;
|
||||||
|
case DW_TAG_pointer_type: return CTF_TYPE_KIND_PTR;
|
||||||
|
case DW_TAG_restrict_type: return CTF_TYPE_KIND_RESTRICT;
|
||||||
|
case DW_TAG_volatile_type: return CTF_TYPE_KIND_VOLATILE;
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
case DW_TAG_structure_type: return CTF_TYPE_KIND_STR;
|
||||||
|
case DW_TAG_union_type: return CTF_TYPE_KIND_UNION;
|
||||||
|
}
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int base_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
struct base_type *bt = tag__base_type(self);
|
||||||
|
int ctf_id = ctf__add_base_type(ctf, bt->name, bt->bit_size);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pointer_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
int ctf_id = ctf__add_short_type(ctf, dwarf_to_ctf_type(self->tag),
|
||||||
|
self->type, 0);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int typedef__encode(struct tag *self, uint16_t core_id, struct ctf *ctf)
|
||||||
|
{
|
||||||
|
int ctf_id = ctf__add_short_type(ctf, CTF_TYPE_KIND_TYPDEF, self->type,
|
||||||
|
tag__namespace(self)->name);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fwd_decl__encode(struct tag *self, uint16_t core_id, struct ctf *ctf)
|
||||||
|
{
|
||||||
|
int ctf_id = ctf__add_fwd_decl(ctf, tag__namespace(self)->name);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int structure_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
struct type *type = tag__type(self);
|
||||||
|
int64_t position;
|
||||||
|
int ctf_id = ctf__add_struct(ctf, dwarf_to_ctf_type(self->tag),
|
||||||
|
type->namespace.name, type->size,
|
||||||
|
type->nr_members, &position);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const bool is_short = type->size < CTF_SHORT_MEMBER_LIMIT;
|
||||||
|
struct class_member *pos;
|
||||||
|
type__for_each_member(type, pos) {
|
||||||
|
if (is_short)
|
||||||
|
ctf__add_short_member(ctf, pos->name, pos->tag.type,
|
||||||
|
pos->bit_offset, &position);
|
||||||
|
else
|
||||||
|
ctf__add_full_member(ctf, pos->name, pos->tag.type,
|
||||||
|
pos->bit_offset, &position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t array_type__nelems(struct tag *self)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t nelem = 1;
|
||||||
|
struct array_type *array = tag__array_type(self);
|
||||||
|
|
||||||
|
for (i = array->dimensions - 1; i >= 0; --i)
|
||||||
|
nelem *= array->nr_entries[i];
|
||||||
|
|
||||||
|
return nelem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int array_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
const uint32_t nelems = array_type__nelems(self);
|
||||||
|
int ctf_id = ctf__add_array(ctf, self->type, 0, nelems);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int subroutine_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
struct parameter *pos;
|
||||||
|
int64_t position;
|
||||||
|
struct ftype *ftype = tag__ftype(self);
|
||||||
|
int ctf_id = ctf__add_function_type(ctf, self->type, ftype->nr_parms,
|
||||||
|
&position);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ftype__for_each_parameter(ftype, pos)
|
||||||
|
ctf__add_parameter(ctf, pos->tag.type, &position);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int enumeration_type__encode(struct tag *self, uint16_t core_id,
|
||||||
|
struct ctf *ctf)
|
||||||
|
{
|
||||||
|
struct type *etype = tag__type(self);
|
||||||
|
int64_t position;
|
||||||
|
int ctf_id = ctf__add_enumeration_type(ctf, etype->namespace.name,
|
||||||
|
etype->nr_members, &position);
|
||||||
|
|
||||||
|
if (ctf_id < 0 || tag__check_id_drift(self, core_id, ctf_id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct enumerator *pos;
|
||||||
|
type__for_each_enumerator(etype, pos)
|
||||||
|
ctf__add_enumerator(ctf, pos->name, pos->value, &position);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tag__encode_ctf(struct tag *self, uint16_t core_id, struct ctf *ctf)
|
||||||
|
{
|
||||||
|
switch (self->tag) {
|
||||||
|
case DW_TAG_base_type:
|
||||||
|
base_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_const_type:
|
||||||
|
case DW_TAG_pointer_type:
|
||||||
|
case DW_TAG_restrict_type:
|
||||||
|
case DW_TAG_volatile_type:
|
||||||
|
pointer_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_typedef:
|
||||||
|
typedef__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_structure_type:
|
||||||
|
case DW_TAG_union_type:
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
if (tag__type(self)->declaration)
|
||||||
|
fwd_decl__encode(self, core_id, ctf);
|
||||||
|
else
|
||||||
|
structure_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_array_type:
|
||||||
|
array_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_subroutine_type:
|
||||||
|
subroutine_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
case DW_TAG_enumeration_type:
|
||||||
|
enumeration_type__encode(self, core_id, ctf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cu__encode_ctf(struct cu *self)
|
||||||
|
{
|
||||||
|
struct ctf *ctf = ctf__new(self->filename, NULL, 0);
|
||||||
|
|
||||||
|
ctf__set_strings(ctf, &strings->gb);
|
||||||
|
|
||||||
|
uint16_t id;
|
||||||
|
struct tag *pos;
|
||||||
|
cu__for_each_type(self, id, pos)
|
||||||
|
tag__encode_ctf(pos, id, ctf);
|
||||||
|
|
||||||
|
ctf__encode(ctf, CTF_FLAGS_COMPR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef _CTF_ENCODER_H_
|
||||||
|
#define _CTF_ENCODER_H_ 1
|
||||||
|
/*
|
||||||
|
Copyright (C) 2009 Red Hat Inc.
|
||||||
|
Copyright (C) 2009 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 cu;
|
||||||
|
|
||||||
|
int cu__encode_ctf(struct cu *self);
|
||||||
|
|
||||||
|
#endif /* _CTF_ENCODER_H_ */
|
12
ctf_loader.c
12
ctf_loader.c
|
@ -131,7 +131,7 @@ static void elf_symbol_iterate(struct ctf_state *sp,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int parse_elf(struct ctf_state *sp, int *wordsizep)
|
static int parse_elf(struct ctf_state *sp, const char *filename, int *wordsizep)
|
||||||
{
|
{
|
||||||
GElf_Ehdr ehdr;
|
GElf_Ehdr ehdr;
|
||||||
GElf_Shdr shdr;
|
GElf_Shdr shdr;
|
||||||
|
@ -153,7 +153,7 @@ static int parse_elf(struct ctf_state *sp, int *wordsizep)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp->ctf = ctf__new(sp->cu->filename, data->d_buf, data->d_size);
|
sp->ctf = ctf__new(filename, data->d_buf, data->d_size);
|
||||||
if (!sp->ctf) {
|
if (!sp->ctf) {
|
||||||
fprintf(stderr, "Cannot initialize CTF state.\n");
|
fprintf(stderr, "Cannot initialize CTF state.\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -818,6 +818,8 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu)
|
||||||
pos->byte_size = integral_bit_size / 8;
|
pos->byte_size = integral_bit_size / 8;
|
||||||
|
|
||||||
if (integral_bit_size == 0 || type_bit_size == integral_bit_size) {
|
if (integral_bit_size == 0 || type_bit_size == integral_bit_size) {
|
||||||
|
if (integral_bit_size == 0)
|
||||||
|
fprintf(stderr, "boo!\n");
|
||||||
pos->bit_size = integral_bit_size;
|
pos->bit_size = integral_bit_size;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -867,13 +869,13 @@ int ctf__load(struct cus *self, struct conf_load *conf, const char *filename)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parse_elf(&state, filename, &wordsize))
|
||||||
|
return -1;
|
||||||
|
|
||||||
state.cu = cu__new(filename, wordsize, NULL, 0, filename);
|
state.cu = cu__new(filename, wordsize, NULL, 0, filename);
|
||||||
if (state.cu == NULL)
|
if (state.cu == NULL)
|
||||||
oom("cu__new");
|
oom("cu__new");
|
||||||
|
|
||||||
if (parse_elf(&state, &wordsize))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
dump_ctf(&state);
|
dump_ctf(&state);
|
||||||
|
|
||||||
elf_end(state.elf);
|
elf_end(state.elf);
|
||||||
|
|
|
@ -551,14 +551,13 @@ static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu)
|
||||||
tag__init(&self->tag, die);
|
tag__init(&self->tag, die);
|
||||||
self->name = strings__add(strings, attr_string(die, DW_AT_name));
|
self->name = strings__add(strings, attr_string(die, DW_AT_name));
|
||||||
self->byte_offset = attr_offset(die, DW_AT_data_member_location);
|
self->byte_offset = attr_offset(die, DW_AT_data_member_location);
|
||||||
self->bit_offset = self->byte_offset * 8 + self->bitfield_offset;
|
|
||||||
/*
|
/*
|
||||||
* Will be cached later, in class_member__cache_byte_size
|
* Will be cached later, in class_member__cache_byte_size
|
||||||
*/
|
*/
|
||||||
self->byte_size = 0;
|
self->byte_size = 0;
|
||||||
self->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
|
self->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
|
||||||
self->bitfield_size = attr_numeric(die, DW_AT_bit_size);
|
self->bitfield_size = attr_numeric(die, DW_AT_bit_size);
|
||||||
if (self->bitfield_size != 0)
|
self->bit_offset = self->byte_offset * 8 + self->bitfield_offset;
|
||||||
/*
|
/*
|
||||||
* We may need to recode the type, possibly creating a suitably
|
* We may need to recode the type, possibly creating a suitably
|
||||||
* sized new base_type
|
* sized new base_type
|
||||||
|
@ -1306,6 +1305,11 @@ static void namespace__recode_dwarf_types(struct tag *self, struct cu *cu)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pos->tag) {
|
switch (pos->tag) {
|
||||||
|
case DW_TAG_member:
|
||||||
|
/* Check if this is an already recoded bitfield */
|
||||||
|
if (pos->type != 0)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
case DW_TAG_subroutine_type:
|
case DW_TAG_subroutine_type:
|
||||||
case DW_TAG_subprogram:
|
case DW_TAG_subprogram:
|
||||||
ftype__recode_dwarf_types(pos, cu);
|
ftype__recode_dwarf_types(pos, cu);
|
||||||
|
@ -1705,8 +1709,42 @@ static void die__process(Dwarf_Die *die, struct cu *cu)
|
||||||
static int class_member__cache_byte_size(struct tag *self, struct cu *cu,
|
static int class_member__cache_byte_size(struct tag *self, struct cu *cu,
|
||||||
void *cookie __unused)
|
void *cookie __unused)
|
||||||
{
|
{
|
||||||
if (self->tag == DW_TAG_member || self->tag == DW_TAG_inheritance)
|
if (self->tag == DW_TAG_member || self->tag == DW_TAG_inheritance) {
|
||||||
tag__class_member(self)->byte_size = tag__size(self, cu);
|
struct class_member *member;
|
||||||
|
|
||||||
|
if (member->bitfield_size != 0) {
|
||||||
|
struct tag *type = tag__follow_typedef(&member->tag, cu);
|
||||||
|
uint16_t type_bit_size;
|
||||||
|
size_t integral_bit_size;
|
||||||
|
|
||||||
|
if (tag__is_enumeration(type)) {
|
||||||
|
type_bit_size = tag__type(type)->size;
|
||||||
|
integral_bit_size = sizeof(int) * 8; /* FIXME: always this size? */
|
||||||
|
} else {
|
||||||
|
struct base_type *bt = tag__base_type(type);
|
||||||
|
type_bit_size = bt->bit_size;
|
||||||
|
integral_bit_size = base_type__name_to_size(bt, cu);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* XXX: integral_bit_size can be zero if base_type__name_to_size doesn't
|
||||||
|
* know about the base_type name, so one has to add there when
|
||||||
|
* such base_type isn't found. pahole will put zero on the
|
||||||
|
* struct output so it should be easy to spot the name when
|
||||||
|
* such unlikely thing happens.
|
||||||
|
*/
|
||||||
|
member->byte_size = integral_bit_size / 8;
|
||||||
|
|
||||||
|
if (integral_bit_size == 0 || type_bit_size == integral_bit_size) {
|
||||||
|
member->bit_size = integral_bit_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
member->bit_size = type_bit_size;
|
||||||
|
} else {
|
||||||
|
member->byte_size = tag__size(self, cu);
|
||||||
|
member->bit_size = member->byte_size * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1738,6 +1776,7 @@ static int cus__load_module(struct cus *self, struct conf_load *conf,
|
||||||
oom("cu__new");
|
oom("cu__new");
|
||||||
cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
|
cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
|
||||||
die__process(cu_die, cu);
|
die__process(cu_die, cu);
|
||||||
|
base_type_name_to_size_table__init();
|
||||||
cu__for_all_tags(cu, class_member__cache_byte_size, NULL);
|
cu__for_all_tags(cu, class_member__cache_byte_size, NULL);
|
||||||
off = noff;
|
off = noff;
|
||||||
if (conf && conf->steal) {
|
if (conf && conf->steal) {
|
||||||
|
|
292
libctf.c
292
libctf.c
|
@ -1,18 +1,25 @@
|
||||||
#include <stdio.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "libctf.h"
|
#include "libctf.h"
|
||||||
#include "ctf.h"
|
#include "ctf.h"
|
||||||
#include "dutil.h"
|
#include "dutil.h"
|
||||||
|
#include "gobuffer.h"
|
||||||
|
|
||||||
struct ctf {
|
struct ctf {
|
||||||
void *buf;
|
void *buf;
|
||||||
size_t size;
|
struct gobuffer types;
|
||||||
int swapped;
|
struct gobuffer *strings;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
size_t size;
|
||||||
|
int swapped;
|
||||||
|
unsigned int type_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint16_t ctf__get16(struct ctf *self, uint16_t *p)
|
uint16_t ctf__get16(struct ctf *self, uint16_t *p)
|
||||||
|
@ -169,3 +176,280 @@ size_t ctf__get_size(struct ctf *self)
|
||||||
{
|
{
|
||||||
return self->size;
|
return self->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctf__set_strings(struct ctf *self, struct gobuffer *strings)
|
||||||
|
{
|
||||||
|
self->strings = strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_base_type(struct ctf *self, uint32_t name, uint16_t size)
|
||||||
|
{
|
||||||
|
struct ctf_full_type t;
|
||||||
|
|
||||||
|
t.base.ctf_name = name;
|
||||||
|
t.base.ctf_info = CTF_INFO_ENCODE(CTF_TYPE_KIND_INT, 0, 0);
|
||||||
|
t.base.ctf_size = size;
|
||||||
|
t.ctf_size_high = CTF_TYPE_INT_ENCODE(0, 0, size);
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &t, sizeof(t) - sizeof(uint32_t));
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_short_type(struct ctf *self, uint16_t kind, uint16_t type,
|
||||||
|
uint32_t name)
|
||||||
|
{
|
||||||
|
struct ctf_short_type t;
|
||||||
|
|
||||||
|
t.ctf_name = name;
|
||||||
|
t.ctf_info = CTF_INFO_ENCODE(kind, 0, 0);
|
||||||
|
t.ctf_type = type;
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &t, sizeof(t));
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_fwd_decl(struct ctf *self, uint32_t name)
|
||||||
|
{
|
||||||
|
return ctf__add_short_type(self, CTF_TYPE_KIND_FWD, 0, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_array(struct ctf *self, uint16_t type, uint16_t index_type,
|
||||||
|
uint32_t nelems)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
struct ctf_short_type t;
|
||||||
|
struct ctf_array a;
|
||||||
|
} array;
|
||||||
|
|
||||||
|
array.t.ctf_name = 0;
|
||||||
|
array.t.ctf_info = CTF_INFO_ENCODE(CTF_TYPE_KIND_ARR, 0, 0);
|
||||||
|
array.t.ctf_size = 0;
|
||||||
|
array.a.ctf_array_type = type;
|
||||||
|
array.a.ctf_array_index_type = index_type;
|
||||||
|
array.a.ctf_array_nelems = nelems;
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &array, sizeof(array));
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctf__add_short_member(struct ctf *self, uint32_t name, uint16_t type,
|
||||||
|
uint16_t offset, int64_t *position)
|
||||||
|
{
|
||||||
|
struct ctf_short_member m = {
|
||||||
|
.ctf_member_name = name,
|
||||||
|
.ctf_member_type = type,
|
||||||
|
.ctf_member_offset = offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(gobuffer__ptr(&self->types, *position), &m, sizeof(m));
|
||||||
|
*position += sizeof(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctf__add_full_member(struct ctf *self, uint32_t name, uint16_t type,
|
||||||
|
uint64_t offset, int64_t *position)
|
||||||
|
{
|
||||||
|
struct ctf_full_member m = {
|
||||||
|
.ctf_member_name = name,
|
||||||
|
.ctf_member_type = type,
|
||||||
|
.ctf_member_offset_high = offset >> 32,
|
||||||
|
.ctf_member_offset_low = offset & 0xffffffffl,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(gobuffer__ptr(&self->types, *position), &m, sizeof(m));
|
||||||
|
*position += sizeof(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_struct(struct ctf *self, uint16_t kind, uint32_t name,
|
||||||
|
uint64_t size, uint16_t nr_members, int64_t *position)
|
||||||
|
{
|
||||||
|
const bool is_short = size < CTF_SHORT_MEMBER_LIMIT;
|
||||||
|
uint32_t members_len = ((is_short ? sizeof(struct ctf_short_member) :
|
||||||
|
sizeof(struct ctf_full_member)) *
|
||||||
|
nr_members);
|
||||||
|
struct ctf_full_type t;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
t.base.ctf_name = name;
|
||||||
|
t.base.ctf_info = CTF_INFO_ENCODE(kind, nr_members, 0);
|
||||||
|
if (size < 0xffff) {
|
||||||
|
len = sizeof(t.base);
|
||||||
|
t.base.ctf_size = size;
|
||||||
|
} else {
|
||||||
|
len = sizeof(t);
|
||||||
|
t.base.ctf_size = 0xffff;
|
||||||
|
t.ctf_size_high = size >> 32;
|
||||||
|
t.ctf_size_low = size & 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &t, len);
|
||||||
|
*position = gobuffer__allocate(&self->types, members_len);
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctf__add_parameter(struct ctf *self, uint16_t type, int64_t *position)
|
||||||
|
{
|
||||||
|
uint16_t *parm = gobuffer__ptr(&self->types, *position);
|
||||||
|
|
||||||
|
*parm = type;
|
||||||
|
*position += sizeof(*parm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_function_type(struct ctf *self, uint16_t type, uint16_t nr_parms,
|
||||||
|
int64_t *position)
|
||||||
|
{
|
||||||
|
struct ctf_short_type t;
|
||||||
|
int len = sizeof(uint16_t) * nr_parms;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Round up to next multiple of 4 to maintain 32-bit alignment.
|
||||||
|
*/
|
||||||
|
if (len & 0x2)
|
||||||
|
len += 0x2;
|
||||||
|
|
||||||
|
t.ctf_name = 0;
|
||||||
|
t.ctf_info = CTF_INFO_ENCODE(CTF_TYPE_KIND_FUNC, nr_parms, 0);
|
||||||
|
t.ctf_type = type;
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &t, sizeof(t));
|
||||||
|
*position = gobuffer__allocate(&self->types, len);
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__add_enumeration_type(struct ctf *self, uint32_t name,
|
||||||
|
uint16_t nr_entries, int64_t *position)
|
||||||
|
{
|
||||||
|
struct ctf_short_type e;
|
||||||
|
|
||||||
|
e.ctf_name = name;
|
||||||
|
e.ctf_info = CTF_INFO_ENCODE(CTF_TYPE_KIND_ENUM, nr_entries, 0);
|
||||||
|
e.ctf_size = 0;
|
||||||
|
|
||||||
|
gobuffer__add(&self->types, &e, sizeof(e));
|
||||||
|
*position = gobuffer__allocate(&self->types,
|
||||||
|
nr_entries * sizeof(struct ctf_enum));
|
||||||
|
return ++self->type_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ctf__add_enumerator(struct ctf *self, uint32_t name, uint32_t value,
|
||||||
|
int64_t *position)
|
||||||
|
{
|
||||||
|
struct ctf_enum m = {
|
||||||
|
.ctf_enum_name = name,
|
||||||
|
.ctf_enum_val = value,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(gobuffer__ptr(&self->types, *position), &m, sizeof(m));
|
||||||
|
*position += sizeof(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *ctf__compress(void *orig_buf, unsigned int *size)
|
||||||
|
{
|
||||||
|
z_stream z = {
|
||||||
|
.zalloc = Z_NULL,
|
||||||
|
.zfree = Z_NULL,
|
||||||
|
.opaque = Z_NULL,
|
||||||
|
.avail_in = *size,
|
||||||
|
.next_in = (Bytef *)orig_buf,
|
||||||
|
};
|
||||||
|
void *bf = NULL;
|
||||||
|
unsigned int bf_size = 0;
|
||||||
|
|
||||||
|
if (deflateInit(&z, Z_BEST_COMPRESSION) != Z_OK)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
#define _GOBUFFER__ZCHUNK 16384 * 1024
|
||||||
|
|
||||||
|
do {
|
||||||
|
const unsigned int new_bf_size = bf_size + _GOBUFFER__ZCHUNK;
|
||||||
|
void *nbf = realloc(bf, new_bf_size);
|
||||||
|
|
||||||
|
if (nbf == NULL)
|
||||||
|
goto out_close_and_free;
|
||||||
|
|
||||||
|
bf = nbf;
|
||||||
|
z.avail_out = _GOBUFFER__ZCHUNK;
|
||||||
|
z.next_out = (Bytef *)bf + bf_size;
|
||||||
|
bf_size = new_bf_size;
|
||||||
|
if (deflate(&z, Z_FULL_FLUSH) == Z_STREAM_ERROR)
|
||||||
|
goto out_close_and_free;
|
||||||
|
printf("%s: size=%d, bf_size=%d, total_out=%ld, total_in=%ld\n", __func__, *size, bf_size, z.total_out, z.total_in);
|
||||||
|
} while (z.total_in != *size);
|
||||||
|
|
||||||
|
if (deflate(&z, Z_FINISH) == Z_STREAM_ERROR)
|
||||||
|
goto out_close_and_free;
|
||||||
|
|
||||||
|
deflateEnd(&z);
|
||||||
|
*size = z.total_out;
|
||||||
|
out:
|
||||||
|
return bf;
|
||||||
|
|
||||||
|
out_close_and_free:
|
||||||
|
deflateEnd(&z);
|
||||||
|
free(bf);
|
||||||
|
bf = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctf__encode(struct ctf *self, uint8_t flags)
|
||||||
|
{
|
||||||
|
struct ctf_header *hdr;
|
||||||
|
unsigned int size;
|
||||||
|
const void *bf;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
size = gobuffer__size(&self->types) + gobuffer__size(self->strings);
|
||||||
|
self->size = sizeof(*hdr) + size;
|
||||||
|
self->buf = malloc(self->size);
|
||||||
|
|
||||||
|
if (self->buf == NULL) {
|
||||||
|
printf("%s: malloc failed!\n", __func__);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = self->buf;
|
||||||
|
memset(hdr, 0, sizeof(*hdr));
|
||||||
|
hdr->ctf_magic = CTF_MAGIC;
|
||||||
|
hdr->ctf_version = 2;
|
||||||
|
hdr->ctf_flags = flags;
|
||||||
|
hdr->ctf_type_off = 0;
|
||||||
|
hdr->ctf_str_off = gobuffer__size(&self->types);
|
||||||
|
hdr->ctf_str_len = gobuffer__size(self->strings);
|
||||||
|
|
||||||
|
memcpy(self->buf + sizeof(*hdr) + hdr->ctf_type_off,
|
||||||
|
gobuffer__entries(&self->types),
|
||||||
|
gobuffer__size(&self->types));
|
||||||
|
memcpy(self->buf + sizeof(*hdr) + hdr->ctf_str_off,
|
||||||
|
gobuffer__entries(self->strings),
|
||||||
|
gobuffer__size(self->strings));
|
||||||
|
|
||||||
|
*(char *)(self->buf + sizeof(*hdr) + hdr->ctf_str_off) = '\0';
|
||||||
|
if (flags & CTF_FLAGS_COMPR) {
|
||||||
|
bf = ctf__compress(self->buf + sizeof(*hdr), &size);
|
||||||
|
if (bf == NULL) {
|
||||||
|
printf("%s: ctf__compress failed!\n", __func__);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bf = self->buf;
|
||||||
|
size = self->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\ntypes:\n entries: %d\n size: %u"
|
||||||
|
"\nstrings:\n entries: %u\n size: %u\ncompressed size: %d\n",
|
||||||
|
self->type_index,
|
||||||
|
gobuffer__size(&self->types),
|
||||||
|
gobuffer__nr_entries(self->strings),
|
||||||
|
gobuffer__size(self->strings), size);
|
||||||
|
|
||||||
|
char pathname[PATH_MAX];
|
||||||
|
snprintf(pathname, sizeof(pathname), "%s.SUNW_ctf", self->filename);
|
||||||
|
fd = creat(pathname, S_IRUSR | S_IWUSR);
|
||||||
|
if (fd == -1) {
|
||||||
|
fprintf(stderr, "%s: open(%s) failed!\n", __func__, pathname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
write(fd, hdr, sizeof(*hdr));
|
||||||
|
write(fd, bf, size);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
27
libctf.h
27
libctf.h
|
@ -1,7 +1,9 @@
|
||||||
#ifndef _LIBCTF_H
|
#ifndef _LIBCTF_H
|
||||||
#define _LIBCTF_H
|
#define _LIBCTF_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
struct ctf *ctf__new(const char *filename, void *buf, size_t size);
|
struct ctf *ctf__new(const char *filename, void *buf, size_t size);
|
||||||
void ctf__delete(struct ctf *ctf);
|
void ctf__delete(struct ctf *ctf);
|
||||||
|
@ -14,4 +16,29 @@ void ctf__put32(struct ctf *self, uint32_t *p, uint32_t val);
|
||||||
void *ctf__get_buffer(struct ctf *self);
|
void *ctf__get_buffer(struct ctf *self);
|
||||||
size_t ctf__get_size(struct ctf *self);
|
size_t ctf__get_size(struct ctf *self);
|
||||||
|
|
||||||
|
int ctf__add_base_type(struct ctf *self, uint32_t name, uint16_t size);
|
||||||
|
int ctf__add_fwd_decl(struct ctf *self, uint32_t name);
|
||||||
|
int ctf__add_short_type(struct ctf *self, uint16_t kind, uint16_t type,
|
||||||
|
uint32_t name);
|
||||||
|
void ctf__add_short_member(struct ctf *self, uint32_t name, uint16_t type,
|
||||||
|
uint16_t offset, int64_t *position);
|
||||||
|
void ctf__add_full_member(struct ctf *self, uint32_t name, uint16_t type,
|
||||||
|
uint64_t offset, int64_t *position);
|
||||||
|
int ctf__add_struct(struct ctf *self, uint16_t kind, uint32_t name,
|
||||||
|
uint64_t size, uint16_t nr_members, int64_t *position);
|
||||||
|
int ctf__add_array(struct ctf *self, uint16_t type, uint16_t index_type,
|
||||||
|
uint32_t nelems);
|
||||||
|
void ctf__add_parameter(struct ctf *self, uint16_t type, int64_t *position);
|
||||||
|
int ctf__add_function_type(struct ctf *self, uint16_t type,
|
||||||
|
uint16_t nr_parameters, int64_t *position);
|
||||||
|
int ctf__add_enumeration_type(struct ctf *self, uint32_t name,
|
||||||
|
uint16_t nr_entries, int64_t *position);
|
||||||
|
void ctf__add_enumerator(struct ctf *self, uint32_t name, uint32_t value,
|
||||||
|
int64_t *position);
|
||||||
|
|
||||||
|
struct gobuffer;
|
||||||
|
|
||||||
|
void ctf__set_strings(struct ctf *self, struct gobuffer *strings);
|
||||||
|
int ctf__encode(struct ctf *self, uint8_t flags);
|
||||||
|
|
||||||
#endif /* _LIBCTF_H */
|
#endif /* _LIBCTF_H */
|
||||||
|
|
23
pahole.c
23
pahole.c
|
@ -20,6 +20,9 @@
|
||||||
#include "dwarves_reorganize.h"
|
#include "dwarves_reorganize.h"
|
||||||
#include "dwarves.h"
|
#include "dwarves.h"
|
||||||
#include "dutil.h"
|
#include "dutil.h"
|
||||||
|
#include "ctf_encoder.h"
|
||||||
|
|
||||||
|
static bool ctf_encode;
|
||||||
|
|
||||||
static uint8_t class__include_anonymous;
|
static uint8_t class__include_anonymous;
|
||||||
static uint8_t class__include_nested_anonymous;
|
static uint8_t class__include_nested_anonymous;
|
||||||
|
@ -886,6 +889,11 @@ static const struct argp_option pahole__options[] = {
|
||||||
.arg = "WORD_SIZE",
|
.arg = "WORD_SIZE",
|
||||||
.doc = "change the arch word size to WORD_SIZE"
|
.doc = "change the arch word size to WORD_SIZE"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "ctf_encode",
|
||||||
|
.key = 'Z',
|
||||||
|
.doc = "Encode as CTF",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = NULL,
|
.name = NULL,
|
||||||
}
|
}
|
||||||
|
@ -953,6 +961,9 @@ static error_t pahole__options_parser(int key, char *arg,
|
||||||
if (!global_verbose)
|
if (!global_verbose)
|
||||||
formatter = class_name_formatter;
|
formatter = class_name_formatter;
|
||||||
break;
|
break;
|
||||||
|
case 'Z':
|
||||||
|
ctf_encode = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ARGP_ERR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
@ -996,6 +1007,16 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
||||||
if (!cu__filter(cu))
|
if (!cu__filter(cu))
|
||||||
goto dump_it;
|
goto dump_it;
|
||||||
|
|
||||||
|
if (ctf_encode) {
|
||||||
|
cu__encode_ctf(cu);
|
||||||
|
/*
|
||||||
|
* We still have to get the type signature code merged to eliminate
|
||||||
|
* dups, reference another CTF file, etc, so for now just encode the
|
||||||
|
* first cu that is let thru by cu__filter.
|
||||||
|
*/
|
||||||
|
goto dump_and_stop;
|
||||||
|
}
|
||||||
|
|
||||||
if (defined_in) {
|
if (defined_in) {
|
||||||
if (class_sname == 0)
|
if (class_sname == 0)
|
||||||
class_sname = strings__find(strings, class_name);
|
class_sname = strings__find(strings, class_name);
|
||||||
|
@ -1097,7 +1118,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
||||||
tag__fprintf(class, cu, &conf, stdout);
|
tag__fprintf(class, cu, &conf, stdout);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
dump_and_stop:
|
||||||
cu__delete(cu);
|
cu__delete(cu);
|
||||||
return LSK__STOP_LOADING;
|
return LSK__STOP_LOADING;
|
||||||
dump_it:
|
dump_it:
|
||||||
|
|
Loading…
Reference in New Issue