sysprof r405 - in trunk: . module



Author: ssp
Date: Sat Mar 29 16:00:33 2008
New Revision: 405
URL: http://svn.gnome.org/viewvc/sysprof?rev=405&view=rev

Log:
Sat Mar 29 11:14:38 2008  SÃren Sandmann  <sandmann redhat com>

        * unwind.[ch], testunwind.c: Beginning of a dwarf unwinder.




Added:
   trunk/testunwind.c
   trunk/unwind.c
   trunk/unwind.h
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/binparser.h
   trunk/elfparser.c
   trunk/elfparser.h
   trunk/module/sysprof-module.c

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Sat Mar 29 16:00:33 2008
@@ -3,12 +3,6 @@
 
 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 @@
 	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 @@
 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)

Modified: trunk/binparser.h
==============================================================================
--- trunk/binparser.h	(original)
+++ trunk/binparser.h	Sat Mar 29 16:00:33 2008
@@ -27,7 +27,7 @@
  *    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)

Modified: trunk/elfparser.c
==============================================================================
--- trunk/elfparser.c	(original)
+++ trunk/elfparser.c	Sat Mar 29 16:00:33 2008
@@ -470,16 +470,20 @@
 	    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 @@
 }
 
 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)

Modified: trunk/elfparser.h
==============================================================================
--- trunk/elfparser.h	(original)
+++ trunk/elfparser.h	Sat Mar 29 16:00:33 2008
@@ -28,6 +28,7 @@
 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);
 
 

Modified: trunk/module/sysprof-module.c
==============================================================================
--- trunk/module/sysprof-module.c	(original)
+++ trunk/module/sysprof-module.c	Sat Mar 29 16:00:33 2008
@@ -223,7 +223,11 @@
 	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;
 	

Added: trunk/testunwind.c
==============================================================================
--- (empty file)
+++ trunk/testunwind.c	Sat Mar 29 16:00:33 2008
@@ -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;
+}

Added: trunk/unwind.c
==============================================================================
--- (empty file)
+++ trunk/unwind.c	Sat Mar 29 16:00:33 2008
@@ -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);
+}
+

Added: trunk/unwind.h
==============================================================================
--- (empty file)
+++ trunk/unwind.h	Sat Mar 29 16:00:33 2008
@@ -0,0 +1,3 @@
+#include <glib.h>
+
+void unwind (const guchar *data);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]