mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
Beginning of a dwarf unwinder.
Sat Mar 29 11:14:38 2008 Søren Sandmann <sandmann@redhat.com> * unwind.[ch], testunwind.c: Beginning of a dwarf unwinder. svn path=/trunk/; revision=405
This commit is contained in:
committed by
Søren Sandmann Pedersen
parent
72ef8ca8c6
commit
d2a6151f8d
@ -1,3 +1,7 @@
|
||||
Sat Mar 29 11:14:38 2008 Søren Sandmann <sandmann@redhat.com>
|
||||
|
||||
* unwind.[ch], testunwind.c: Beginning of a dwarf unwinder.
|
||||
|
||||
Sat Mar 29 08:05:46 2008 Søren Sandmann <sandmann@redhat.com>
|
||||
|
||||
* module/sysprof-module.c: x86 merge happened in 2.6.25
|
||||
|
||||
42
Makefile.am
42
Makefile.am
@ -3,12 +3,6 @@ DIST_SUBDIRS = module
|
||||
|
||||
bin_PROGRAMS = sysprof-text
|
||||
|
||||
noinst_PROGRAMS = testelf
|
||||
testelf_SOURCES = testelf.c demangle.c elfparser.c elfparser.h binparser.c binparser.h
|
||||
testelf_CPPFLAGS = \
|
||||
$(CORE_DEP_CFLAGS)
|
||||
testelf_LDADD = $(CORE_DEP_LIBS)
|
||||
|
||||
if BUILD_GUI
|
||||
bin_PROGRAMS += sysprof
|
||||
endif
|
||||
@ -33,9 +27,12 @@ SYSPROF_CORE = \
|
||||
sformat.c \
|
||||
stackstash.h \
|
||||
stackstash.c \
|
||||
module/sysprof-module.h \
|
||||
unwind.h \
|
||||
unwind.c \
|
||||
watch.h \
|
||||
watch.c
|
||||
watch.c \
|
||||
\
|
||||
module/sysprof-module.h
|
||||
|
||||
#
|
||||
# GUI version
|
||||
@ -92,3 +89,32 @@ EXTRA_DIST = \
|
||||
insert-module:
|
||||
/sbin/modprobe -r sysprof-module
|
||||
/sbin/modprobe sysprof-module
|
||||
|
||||
#
|
||||
# Test programs
|
||||
#
|
||||
noinst_PROGRAMS = testelf testunwind
|
||||
|
||||
# testunwind
|
||||
testunwind_SOURCES = \
|
||||
testunwind.c \
|
||||
demangle.c \
|
||||
elfparser.c \
|
||||
elfparser.h \
|
||||
binparser.c \
|
||||
binparser.h \
|
||||
unwind.c \
|
||||
unwind.h
|
||||
testunwind_CPPFLAGS = $(CORE_DEP_CFLAGS)
|
||||
testunwind_LDADD = $(CORE_DEP_LIBS)
|
||||
|
||||
# testelf
|
||||
testelf_SOURCES = \
|
||||
testelf.c \
|
||||
demangle.c \
|
||||
elfparser.c \
|
||||
elfparser.h \
|
||||
binparser.c \
|
||||
binparser.h
|
||||
testelf_CPPFLAGS = $(CORE_DEP_CFLAGS)
|
||||
testelf_LDADD = $(CORE_DEP_LIBS)
|
||||
|
||||
@ -27,7 +27,7 @@ typedef struct BinField BinField;
|
||||
* manipulated with methods
|
||||
*
|
||||
* goto - go to absolute position from file start
|
||||
* goto_rel - go to relative positio
|
||||
* goto_rel - go to relative position
|
||||
* goto_record_rel - skip the given number of records
|
||||
* align - move forward until aligned to given width
|
||||
* save/restore - save/restore the current offset (stack)
|
||||
|
||||
35
elfparser.c
35
elfparser.c
@ -470,16 +470,20 @@ read_table (ElfParser *parser,
|
||||
n_functions++;
|
||||
|
||||
#if 0
|
||||
g_print (" symbol: %s: %lx\n", get_string_indirect (parser->parser,
|
||||
parser->sym_format, "st_name",
|
||||
str_table->offset), addr - parser->text_section->load_address);
|
||||
g_print (" sym %d in %p (info: %d:%d) (func:global %d:%d)\n", addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
|
||||
g_print (" symbol: %s: %lx\n",
|
||||
get_string_indirect (parser->parser,
|
||||
parser->sym_format, "st_name",
|
||||
str_table->offset),
|
||||
addr - parser->text_section->load_address);
|
||||
g_print (" sym %d in %p (info: %d:%d) (func:global %d:%d)\n",
|
||||
addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
|
||||
#endif
|
||||
}
|
||||
else if (addr != 0)
|
||||
{
|
||||
#if 0
|
||||
g_print (" rejecting %d in %p (info: %d:%d) (func:global %d:%d)\n", addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
|
||||
g_print (" rejecting %d in %p (info: %d:%d) (func:global %d:%d)\n",
|
||||
addr, parser, info & 0xf, info >> 4, STT_FUNC, STB_GLOBAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -653,16 +657,29 @@ elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
|
||||
}
|
||||
|
||||
const guchar *
|
||||
elf_parser_get_eh_frame (ElfParser *parser)
|
||||
get_section (ElfParser *parser,
|
||||
const char *name)
|
||||
{
|
||||
const Section *eh_frame = find_section (parser, ".eh_frame", SHT_PROGBITS);
|
||||
const Section *section = find_section (parser, name, SHT_PROGBITS);
|
||||
|
||||
if (eh_frame)
|
||||
return bin_parser_get_data (parser->parser) + eh_frame->offset;
|
||||
if (section)
|
||||
return bin_parser_get_data (parser->parser) + section->offset;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const guchar *
|
||||
elf_parser_get_eh_frame (ElfParser *parser)
|
||||
{
|
||||
return get_section (parser, ".eh_frame");
|
||||
}
|
||||
|
||||
const guchar *
|
||||
elf_parser_get_debug_frame (ElfParser *parser)
|
||||
{
|
||||
return get_section (parser, ".debug_frame");
|
||||
}
|
||||
|
||||
const char *
|
||||
elf_parser_get_sym_name (ElfParser *parser,
|
||||
const ElfSym *sym)
|
||||
|
||||
@ -28,6 +28,7 @@ void elf_parser_free (ElfParser *parser);
|
||||
const char * elf_parser_get_debug_link (ElfParser *parser,
|
||||
guint32 *crc32);
|
||||
const guchar *elf_parser_get_eh_frame (ElfParser *parser);
|
||||
const guchar *elf_parser_get_debug_frame (ElfParser *parser);
|
||||
gulong elf_parser_get_text_offset (ElfParser *parser);
|
||||
|
||||
|
||||
|
||||
@ -223,7 +223,11 @@ trace_kernel (struct pt_regs *regs,
|
||||
bp = 0;
|
||||
#endif
|
||||
|
||||
dump_trace(NULL, regs, stack, bp, &backtrace_ops, &info);
|
||||
dump_trace(NULL, regs, stack,
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
|
||||
bp,
|
||||
#endif
|
||||
&backtrace_ops, &info);
|
||||
|
||||
trace->n_kernel_words = info.pos;
|
||||
|
||||
|
||||
27
testunwind.c
Normal file
27
testunwind.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include "elfparser.h"
|
||||
#include "unwind.h"
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
const guchar *data;
|
||||
ElfParser *elf;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
g_print ("no arg\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
elf = elf_parser_new (argv[1], NULL);
|
||||
|
||||
if (!elf)
|
||||
{
|
||||
g_print ("NO ELF!!!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unwind (elf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
306
unwind.c
Normal file
306
unwind.c
Normal file
@ -0,0 +1,306 @@
|
||||
#include "elfparser.h"
|
||||
#include "binparser.h"
|
||||
#include <string.h>
|
||||
|
||||
/* FIXME: endianness, 64 bit */
|
||||
|
||||
static guint64
|
||||
get_length (const guchar **data)
|
||||
{
|
||||
guint64 len;
|
||||
|
||||
len = *(guint32 *)*data;
|
||||
|
||||
*data += 4;
|
||||
|
||||
if (len == 0xffffffff)
|
||||
{
|
||||
len = *(guint64 *)data;
|
||||
*data += 8;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static guint64
|
||||
decode_uleb128 (const guchar **data)
|
||||
{
|
||||
guint64 result;
|
||||
int shift;
|
||||
guchar b;
|
||||
|
||||
result = 0;
|
||||
shift = 0;
|
||||
do
|
||||
{
|
||||
b = *(*data)++;
|
||||
result |= (b & 0x7f) << shift;
|
||||
shift += 7;
|
||||
|
||||
} while (b & 0x80);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gint64
|
||||
decode_sleb128 (const guchar **data)
|
||||
{
|
||||
gint64 result;
|
||||
int shift;
|
||||
guchar b;
|
||||
|
||||
result = 0;
|
||||
shift = 0;
|
||||
do
|
||||
{
|
||||
b = *(*data)++;
|
||||
result |= (b & 0x7f) << shift;
|
||||
shift += 7;
|
||||
} while (b & 0x80);
|
||||
|
||||
if (b & 0x40 && shift < 64)
|
||||
result |= - (1 << shift);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
decode_block (const guchar **data)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* FIXME */
|
||||
|
||||
len = decode_uleb128 (data);
|
||||
|
||||
(*data) += len;
|
||||
}
|
||||
|
||||
static gulong
|
||||
decode_address (const guchar **data)
|
||||
{
|
||||
/* FIXME */
|
||||
gulong r;
|
||||
|
||||
r = *(guint32 *)*data;
|
||||
(*data) += 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char *
|
||||
decode_instruction (const guchar **data)
|
||||
{
|
||||
int opcode = *(*data)++;
|
||||
int high2 = (opcode & 0xc0) >> 6;
|
||||
int low6 = (opcode & 0x3f);
|
||||
|
||||
if (high2 == 0x01)
|
||||
{
|
||||
return "DW_CFA_advance_loc";
|
||||
}
|
||||
else if (high2 == 0x02)
|
||||
{
|
||||
g_print ("register: %d\n", low6);
|
||||
g_print ("offset: %llu\n", decode_uleb128 (data));
|
||||
|
||||
return "DW_CFA_offset";
|
||||
}
|
||||
else if (high2 == 0x03)
|
||||
{
|
||||
return "DW_CFA_restore";
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert ((opcode & 0xc0) == 0);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x0:
|
||||
return "DW_CFA_nop";
|
||||
|
||||
case 0x01:
|
||||
g_print ("addr: %p\n", (void *)decode_address (data));
|
||||
return "DW_CFA_set_loc";
|
||||
|
||||
case 0x02:
|
||||
(*data)++;
|
||||
return "DW_CFA_advance_loc1";
|
||||
|
||||
case 0x03:
|
||||
(*data) += 2;
|
||||
return "DW_CFA_advance_loc2";
|
||||
|
||||
case 0x04:
|
||||
(*data) += 4;
|
||||
return "DW_CFA_advance_loc4";
|
||||
|
||||
case 0x05:
|
||||
decode_uleb128 (data);
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_offset_extended";
|
||||
|
||||
case 0x06:
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_restore_extended";
|
||||
|
||||
case 0x07:
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_undefined";
|
||||
|
||||
case 0x08:
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_same_value";
|
||||
|
||||
case 0x09:
|
||||
decode_uleb128 (data);
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_register";
|
||||
|
||||
case 0x0a:
|
||||
return "DW_CFA_remember_state";
|
||||
|
||||
case 0x0b:
|
||||
return "DW_CFA_restore_state";
|
||||
|
||||
case 0x0c:
|
||||
g_print ("reg: %llu\n", decode_uleb128 (data));
|
||||
g_print ("off: %llu\n", decode_uleb128 (data));
|
||||
return "DW_CFA_def_cfa";
|
||||
|
||||
case 0x0d:
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_def_cfa_register";
|
||||
|
||||
case 0x0e:
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_def_cfa_offset";
|
||||
|
||||
case 0x0f:
|
||||
decode_block (data);
|
||||
return "DW_CFA_def_cfa_expression";
|
||||
|
||||
case 0x10:
|
||||
decode_uleb128 (data);
|
||||
decode_block (data);
|
||||
return "DW_CFA_expression";
|
||||
|
||||
case 0x11:
|
||||
decode_uleb128 (data);
|
||||
decode_sleb128 (data);
|
||||
return "DW_CFA_offset_extended_sf";
|
||||
|
||||
case 0x12:
|
||||
decode_uleb128 (data);
|
||||
decode_sleb128 (data);
|
||||
return "DW_CFA_def_cfa_sf";
|
||||
|
||||
case 0x13:
|
||||
decode_sleb128 (data);
|
||||
return "DW_CFA_def_cfa_offset_sf";
|
||||
|
||||
case 0x14:
|
||||
decode_uleb128 (data);
|
||||
decode_uleb128 (data);
|
||||
return "DW_CFA_val_offset";
|
||||
|
||||
case 0x15:
|
||||
decode_uleb128 (data);
|
||||
decode_sleb128 (data);
|
||||
return "DW_CFA_val_offset_sf";
|
||||
|
||||
case 0x16:
|
||||
decode_uleb128 (data);
|
||||
decode_block (data);
|
||||
return "DW_CFA_val_expression";
|
||||
|
||||
case 0x1c:
|
||||
return "DW_CFA_lo_user";
|
||||
|
||||
case 0x3f:
|
||||
return "DW_CFA_hi_user";
|
||||
|
||||
default:
|
||||
return "UNKNOWN INSTRUCTION";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
decode_entry (const guchar *data)
|
||||
{
|
||||
guint64 len, aug_len;
|
||||
const guchar *end;
|
||||
gboolean has_augmentation;
|
||||
|
||||
len = get_length (&data);
|
||||
|
||||
end = data + len;
|
||||
|
||||
g_print ("length: %llu\n", len);
|
||||
|
||||
/* CIE_id is 0 for eh frames, and 0xffffffff/0xffffffffffffffff for .debug_frame */
|
||||
|
||||
g_print ("id: %d\n", *(guint32 *)data);
|
||||
|
||||
data += 4;
|
||||
|
||||
g_print ("version: %d\n", *data);
|
||||
|
||||
data += 1;
|
||||
|
||||
g_print ("augmentation: %s\n", data);
|
||||
|
||||
has_augmentation = strchr (data, 'z');
|
||||
|
||||
data += strlen (data) + 1;
|
||||
|
||||
g_print ("code alignment: %llu\n", decode_uleb128 (&data));
|
||||
|
||||
g_print ("data alignment: %lld\n", decode_sleb128 (&data));
|
||||
|
||||
g_print ("return register: %llu\n", decode_uleb128 (&data));
|
||||
|
||||
if (has_augmentation)
|
||||
{
|
||||
g_print ("augmentation length: %llu\n", (aug_len = decode_uleb128 (&data)));
|
||||
|
||||
data += aug_len;
|
||||
}
|
||||
|
||||
while (data < end)
|
||||
g_print (" %s\n", decode_instruction (&data));
|
||||
}
|
||||
|
||||
/* The correct API is probably something like
|
||||
*
|
||||
* gboolean
|
||||
* unwind (ElfParser *parser,
|
||||
* gulong *regs
|
||||
* int n_regs,
|
||||
* MemoryReader reader,
|
||||
* gpointer data);
|
||||
*
|
||||
*/
|
||||
void
|
||||
unwind (ElfParser *elf)
|
||||
{
|
||||
const guchar *data;
|
||||
|
||||
if ((data = elf_parser_get_debug_frame (elf)))
|
||||
{
|
||||
g_print ("Using .debug_frame\n");
|
||||
}
|
||||
else if ((data = elf_parser_get_eh_frame (elf)))
|
||||
{
|
||||
g_print ("Using .eh_frame\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("no debug info found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
decode_entry (data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user