dwarves/ctf_encoder.c

365 lines
8.9 KiB
C
Raw Normal View History

/*
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"
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
#include "hash.h"
#include "elf_symtab.h"
#include <inttypes.h>
static int tag__check_id_drift(const struct tag *tag,
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(tag->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 *tag, uint16_t core_id,
struct ctf *ctf)
{
struct base_type *bt = tag__base_type(tag);
int ctf_id = ctf__add_base_type(ctf, bt->name, bt->bit_size);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
return 0;
}
static int pointer_type__encode(struct tag *tag, uint16_t core_id,
struct ctf *ctf)
{
int ctf_id = ctf__add_short_type(ctf, dwarf_to_ctf_type(tag->tag),
tag->type, 0);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
return 0;
}
static int typedef__encode(struct tag *tag, uint16_t core_id, struct ctf *ctf)
{
int ctf_id = ctf__add_short_type(ctf, CTF_TYPE_KIND_TYPDEF, tag->type,
tag__namespace(tag)->name);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
return 0;
}
static int fwd_decl__encode(struct tag *tag, uint16_t core_id, struct ctf *ctf)
{
int ctf_id = ctf__add_fwd_decl(ctf, tag__namespace(tag)->name);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
return 0;
}
static int structure_type__encode(struct tag *tag, uint16_t core_id,
struct ctf *ctf)
{
struct type *type = tag__type(tag);
int64_t position;
int ctf_id = ctf__add_struct(ctf, dwarf_to_ctf_type(tag->tag),
type->namespace.name, type->size,
type->nr_members, &position);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
const bool is_short = type->size < CTF_SHORT_MEMBER_LIMIT;
struct class_member *pos;
type__for_each_data_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 *tag)
{
int i;
uint32_t nelem = 1;
struct array_type *array = tag__array_type(tag);
for (i = array->dimensions - 1; i >= 0; --i)
nelem *= array->nr_entries[i];
return nelem;
}
static int array_type__encode(struct tag *tag, uint16_t core_id,
struct ctf *ctf)
{
const uint32_t nelems = array_type__nelems(tag);
int ctf_id = ctf__add_array(ctf, tag->type, 0, nelems);
if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id))
return -1;
return 0;
}
static int subroutine_type__encode(struct tag *tag, uint16_t core_id,
struct ctf *ctf)
{
struct parameter *pos;
int64_t position;
struct ftype *ftype = tag__ftype(tag);
int ctf_id = ctf__add_function_type(ctf, tag->type, ftype->nr_parms,
ftype->unspec_parms, &position);
if (ctf_id < 0 || tag__check_id_drift(tag, 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 *tag, uint16_t core_id,
struct ctf *ctf)
{
struct type *etype = tag__type(tag);
int64_t position;
int ctf_id = ctf__add_enumeration_type(ctf, etype->namespace.name,
etype->size, etype->nr_members,
&position);
if (ctf_id < 0 || tag__check_id_drift(tag, 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 *tag, uint16_t core_id, struct ctf *ctf)
{
switch (tag->tag) {
case DW_TAG_base_type:
base_type__encode(tag, 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(tag, core_id, ctf);
break;
case DW_TAG_typedef:
typedef__encode(tag, core_id, ctf);
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type:
if (tag__type(tag)->declaration)
fwd_decl__encode(tag, core_id, ctf);
else
structure_type__encode(tag, core_id, ctf);
break;
case DW_TAG_array_type:
array_type__encode(tag, core_id, ctf);
break;
case DW_TAG_subroutine_type:
subroutine_type__encode(tag, core_id, ctf);
break;
case DW_TAG_enumeration_type:
enumeration_type__encode(tag, core_id, ctf);
break;
}
}
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
#define HASHADDR__BITS 8
#define HASHADDR__SIZE (1UL << HASHADDR__BITS)
#define hashaddr__fn(key) hash_64(key, HASHADDR__BITS)
static struct function *hashaddr__find_function(const struct hlist_head hashtable[],
const uint64_t addr)
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
{
struct function *function;
struct hlist_node *pos;
uint16_t bucket = hashaddr__fn(addr);
const struct hlist_head *head = &hashtable[bucket];
hlist_for_each_entry(function, pos, head, tool_hnode) {
if (function->lexblock.ip.addr == addr)
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
return function;
}
return NULL;
}
static struct variable *hashaddr__find_variable(const struct hlist_head hashtable[],
const uint64_t addr)
{
struct variable *variable;
struct hlist_node *pos;
uint16_t bucket = hashaddr__fn(addr);
const struct hlist_head *head = &hashtable[bucket];
hlist_for_each_entry(variable, pos, head, tool_hnode) {
if (variable->ip.addr == addr)
return variable;
}
return NULL;
}
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
/*
* FIXME: Its in the DWARF loader, we have to find a better handoff
* mechanizm...
*/
extern struct strings *strings;
int cu__encode_ctf(struct cu *cu, int verbose)
{
int err = -1;
struct ctf *ctf = ctf__new(cu->filename, cu->elf);
if (ctf == NULL)
goto out;
if (cu__cache_symtab(cu) < 0)
goto out_delete;
ctf__set_strings(ctf, &strings->gb);
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
uint32_t id;
struct tag *pos;
cu__for_each_type(cu, id, pos)
tag__encode_ctf(pos, id, ctf);
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
struct hlist_head hash_addr[HASHADDR__SIZE];
for (id = 0; id < HASHADDR__SIZE; ++id)
INIT_HLIST_HEAD(&hash_addr[id]);
struct function *function;
cu__for_each_function(cu, id, function) {
uint64_t addr = function->lexblock.ip.addr;
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
struct hlist_head *head = &hash_addr[hashaddr__fn(addr)];
hlist_add_head(&function->tool_hnode, head);
}
uint64_t addr;
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
GElf_Sym sym;
const char *sym_name;
cu__for_each_cached_symtab_entry(cu, id, sym, sym_name) {
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
if (ctf__ignore_symtab_function(&sym, sym_name))
continue;
addr = elf_sym__value(&sym);
int64_t position;
function = hashaddr__find_function(hash_addr, addr);
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
if (function == NULL) {
if (verbose)
fprintf(stderr,
"function %4d: %-20s %#" PRIx64 " %5u NOT FOUND!\n",
id, sym_name, addr,
elf_sym__size(&sym));
err = ctf__add_function(ctf, 0, 0, 0, &position);
if (err != 0)
goto out_err_ctf;
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
continue;
}
const struct ftype *ftype = &function->proto;
err = ctf__add_function(ctf, function->proto.tag.type,
ftype->nr_parms,
ftype->unspec_parms, &position);
if (err != 0)
goto out_err_ctf;
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
struct parameter *pos;
ftype__for_each_parameter(ftype, pos)
ctf__add_function_parameter(ctf, pos->tag.type, &position);
}
for (id = 0; id < HASHADDR__SIZE; ++id)
INIT_HLIST_HEAD(&hash_addr[id]);
struct variable *var;
cu__for_each_variable(cu, id, pos) {
var = tag__variable(pos);
if (variable__scope(var) != VSCOPE_GLOBAL)
continue;
struct hlist_head *head = &hash_addr[hashaddr__fn(var->ip.addr)];
hlist_add_head(&var->tool_hnode, head);
}
cu__for_each_cached_symtab_entry(cu, id, sym, sym_name) {
if (ctf__ignore_symtab_object(&sym, sym_name))
continue;
addr = elf_sym__value(&sym);
var = hashaddr__find_variable(hash_addr, addr);
if (var == NULL) {
if (verbose)
fprintf(stderr,
"variable %4d: %-20s %#" PRIx64 " %5u NOT FOUND!\n",
id, sym_name, addr,
elf_sym__size(&sym));
err = ctf__add_object(ctf, 0);
if (err != 0)
goto out_err_ctf;
continue;
}
err = ctf__add_object(ctf, var->ip.tag.type);
if (err != 0)
goto out_err_ctf;
}
ctf__encode(ctf, CTF_FLAGS_COMPR);
err = 0;
ctf_encoder: Convert DWARF functions to CTF Finally we can use the Elf file already opened in dwarf_load, call cu__for_each_cached_symtab_entry to iterate over the symtab entries, this iterator will first call dwfl_module_getsymtab, that will do the relocation that will allow us to go from the symtab address to the one in the DWARF DW_TAG_subprogram tag DW_AT_low_pc attribute. And voila, for a relatively complex single unit Linux kernel object file, kernel/sched.o, we go from: Just DWARF (gcc -g): $ ls -la kernel/sched.o 1979011 kernel/sched.o Then we run this to encode the CTF section: $ pahole -Z kernel/sched.o And get a file with both DWARF and CTF ELF sections: $ ls -la kernel/sched.o 2019848 kernel/sched.o We still need to encode the "OBJECTS", i.e. variables, but this gets us from 1979011 (just DWARF) to: $ strip--strip-debug kernel/sched.o $ ls -la kernel/sched.o -rw-rw-r-- 1 acme acme 507008 2009-03-30 23:01 kernel/sched.o 25% of the original size. Of course we don't have inline expansion information, parameter names, goto labels, etc, but should be good enough for most use cases. See, without DWARF data, if we ask for it to use DWARF, nothing will be printed, if we don't speficy the format, it will try first DWARF, it will not find anything, it will try CTF: $ pahole -F dwarf kernel/sched.o $ pahole -C seq_operations kernel/sched.o struct seq_operations { void * (*start)(struct seq_file *, loff_t *); /* 0 8 */ void (*stop)(struct seq_file *, void *); /* 8 8 */ void * (*next)(struct seq_file *, void *, loff_t *); /* 16 8 */ int (*show)(struct seq_file *, void *); /* 24 8 */ /* size: 32, cachelines: 1, members: 4 */ /* last cacheline: 32 bytes */ }; $ $ pfunct -Vi -f schedule kernel/sched.o void schedule(void); { /* low_pc=0xe01 */ }/* size: 83 */ $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-31 03:54:29 +02:00
out_delete:
ctf__delete(ctf);
out:
return err;
out_err_ctf:
fprintf(stderr,
"%4d: %-20s %#llx %5u failed encoding, "
"ABORTING!\n", id, sym_name,
(unsigned long long)addr, elf_sym__size(&sym));
goto out_delete;
}