xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit)
@ 2010-05-07 20:01 Tej
  2010-05-10 14:53 ` [Xen-devel] " Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 4+ messages in thread
From: Tej @ 2010-05-07 20:01 UTC (permalink / raw)
  To: George Dunlap; +Cc: xen-devel, xen-users, parkash.tej

[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]

All,

Here are the latest patches to expreiment with gcov profiler for xen
hypervisor. I have tested current patches on Intel i686.
System Details:
gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)
gcov (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Kernel 2.6.28-11-generic
Distribution: Ubuntu jaunty 9.04

There are some design issue which i would like to highlight here:
1. To create gcov proc dir user /proc/xen, we are explicitly exported
xen_base symbol. I want to know your thoughts.
2. XEN_GCOV_PROC config is set as not selected. So someone has to be
configured manually as M/Y


Known Issues:
File vmac.c throw some fault while using with lcov/gcov. This is due
to some raw count copy between xen and kernel. I could not able to
reproduce it many times, may be someone can try on 64 bit m/c.
"My take on this is that zero length array element in gcov_info
structure has to be copied separately between xen and kernel. How? I
dont know."

I am still debugging this issue.

If you get fault and fail to proceed please apply the above patch in
linux-wa-v1.patch in Linux 2.6.18.8 and recompile. This time vmac.gcda
file wont appear in /proc/xen/gcov/crypto


HOWTO Test using lcov
1.  install lcov from repo
     # sudo apt-get install lcov
2. vi /etc/lcovrc
    Change line: lcov_gcov_dir = /proc/gcov to lcov_gcov_dir = /proc/xen/gcov
3. # cd  /tmp; lcov -c -o kernel.info
4. # genhtml kernel.info
5, # firefox index.html

lcov README and screenshot is attached.

HTH

Note:
For any other detail required please CC me to parkash.tej@gmail.com

[-- Attachment #2: linux-2.6.18-gcov-v1.patch --]
[-- Type: text/x-patch, Size: 44147 bytes --]

diff -r 86d6c6417cf9 drivers/xen/Kconfig
--- a/drivers/xen/Kconfig	Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/Kconfig	Sun Feb 07 00:13:40 2010 +0530
@@ -311,6 +311,13 @@
 	help
 	  Xen hypervisor attributes will show up under /sys/hypervisor/.
 
+config XEN_GCOV_PROC
+       tristate "Code covarage for hypervisor"
+       help
+         Select to profile Xen Hypervisor only. Create /proc/xen/gcov entry
+         which provides access to the current code coverage state of xen hypervisor
+
+
 choice
 	prompt "Xen version compatibility"
 	default XEN_COMPAT_030002_AND_LATER
diff -r 86d6c6417cf9 drivers/xen/Makefile
--- a/drivers/xen/Makefile	Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/Makefile	Sun Feb 07 00:13:40 2010 +0530
@@ -3,6 +3,7 @@
 obj-y	+= evtchn/
 obj-y	+= xenbus/
 obj-y	+= char/
+obj-y   += gcov/
 
 obj-y	+= util.o
 obj-$(CONFIG_XEN_BALLOON)		+= balloon/
diff -r 86d6c6417cf9 drivers/xen/core/xen_proc.c
--- a/drivers/xen/core/xen_proc.c	Thu Feb 04 13:08:27 2010 +0000
+++ b/drivers/xen/core/xen_proc.c	Sun Feb 07 00:13:40 2010 +0530
@@ -3,7 +3,7 @@
 #include <linux/proc_fs.h>
 #include <xen/xen_proc.h>
 
-static struct proc_dir_entry *xen_base;
+struct proc_dir_entry *xen_base;
 
 struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode)
 {
@@ -20,4 +20,5 @@
 	remove_proc_entry(name, xen_base);
 }
 
+EXPORT_SYMBOL(xen_base);
 EXPORT_SYMBOL_GPL(remove_xen_proc_entry); 
diff -r 86d6c6417cf9 drivers/xen/gcov/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/gcov/Makefile	Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_GCOV_PROC) := xen-gcov-proc.o
diff -r 86d6c6417cf9 drivers/xen/gcov/xen-gcov-proc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/gcov/xen-gcov-proc.c	Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,1235 @@
+/**
+ *  @file xen-gcov-proc.c
+ *
+ *  @Author: Hubertus Franke <frankeh@us.ibm.com>
+ *           Rajan Ravindran <rajancr@us.ibm.com>
+ *           Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ *           Paul Larson
+ *
+ *  Modified by tej parkash and team for Xen (tej.parkash@hcl.in)
+ *                
+ */
+/***************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/xen-gcov.h>
+#include <xen/evtchn.h>
+#include <xen/xen_proc.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+
+MODULE_LICENSE("GPL");
+
+#define GCOV_PROC_HEADER    "xen-gcov-proc: "
+#define GCOV_PROC_ROOT        "gcov"
+#define GCOV_PROC_VMLINUX    "vmlinux"
+#define PAD8(x)            (((x) + 7) & ~7)
+
+#define FILE_LENGTH  	100
+
+/*
+ * If set to non-zero, create links to additional files(.c and .gcno) in proc 
+ * filesystem entries. 
+ */
+static int xen_gcov_link = 1;
+
+/* Count update frequency */
+static int xen_gcov_update = 5;
+
+#ifdef MODULE
+/* Parameter handling. */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+/* module_param is a 2.6 thing (though there are compat macros since 2.4.25) */
+MODULE_PARM(xen_gcov_link, "i");
+MODULE_PARM(xen_gcov_update, "i");
+#else
+module_param(xen_gcov_link, int, 0400);
+module_param(xen_gcov_update, int, 0400);
+#endif                /* LINUX_VERSION_CODE */
+
+MODULE_PARM_DESC(xen_gcov_link, "If set to non-zero, create links to additional "
+         "files in proc filesystem entries");
+MODULE_PARM_DESC(xen_gcov_update, "decides the frequency of hypervisor count"
+         "update and default value is 5sec.");
+#else                /* MODULE */
+/* Called when 'xen_gcov_link' is specified on the kernel command line. */
+static int __init xen_gcov_link_setup(char *str)
+{
+    xen_gcov_link = (int)simple_strtol(str, NULL, 10);
+    return 1;
+}
+
+__setup("xen_gcov_link=", xen_gcov_link_setup);
+
+static int __init xen_gcov_update_setup(char *str)
+{
+    xen_gcov_update = (int)simple_strtol(str, NULL, 10);
+    return 1;
+}
+
+__setup("xen_gcov_update=", xen_gcov_update_setup);
+
+#endif                /* MODULE */
+
+/*
+ *  create sysclt entry @/proc/sys/xen 
+ * accomplish the count update frequency
+ * perform: echo <num> >/proc/sys/xen/xen_gcov_update
+ */
+#ifdef CONFIG_SYSCTL
+static ctl_table gcov_table[] = {
+    {
+        .ctl_name     = 4,
+    .procname     = "xen_gcov_update",
+    .data         = &xen_gcov_update,
+    .maxlen     = sizeof(xen_gcov_update),
+    .mode         = 0644,
+    .proc_handler     = proc_dointvec,
+    }
+    ,
+    {.ctl_name = 0}
+};
+
+static ctl_table gcov_root_table[] = {
+    {
+        .ctl_name     = 123,
+        .procname     = "xen",
+        .mode         = 0555,
+        .child        = gcov_table},
+    {.ctl_name = 0}
+};
+
+/*sysclt table specific declaration*/
+static struct ctl_table_header *gcov_table_header;
+
+#endif /* CONFIG_SYSCTL */
+
+/* Protect global variables from concurrent access. */
+static DEFINE_MUTEX(read_mutex);
+static DEFINE_MUTEX(write_mutex);
+
+/* workqueue function */
+static void xeno_prof(void *);
+
+/* workqueue for the calling hypervisor count head */
+static DECLARE_WORK(work, xeno_prof, NULL);
+
+/* Filesystem entry for /proc/gcov/vmlinux */
+static struct proc_dir_entry *proc_vmlinux = NULL;
+
+/* First leaf node. */
+static struct gcov_ftree_node *leaf_nodes = NULL;
+
+/* Cached node used to speed up sequential reads in /proc/vmlinux. */
+static struct gcov_ftree_node *cached_node = NULL;
+
+/* Root node for internal data tree. */
+static struct gcov_ftree_node tree_root;
+
+struct node_info *node_info = NULL;
+
+/* Filename extension for data files. */
+static const char *da_ending = "gcda";
+
+/* Array of filename endings to use when creating links. */
+static const char *endings[] = { "gcno", "c" };
+
+/* Info which keeps no if file in xen info to be profile */
+unsigned int xen_file_nos;
+
+/* head of xen-gcov-info linked list */
+struct gcov_info *list_head = NULL;
+
+/* xen_sourcepath length */
+static int sourcepath_len;
+
+/* gcov version no */
+unsigned long xen_gcov_version;
+
+
+/* Determine whether counter TYPE is active in BB. */
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+    return (1 << type) & bb->ctr_mask;
+}
+
+/* Return the number of active counter types for BB. */
+static inline unsigned int
+num_counter_active(struct gcov_info *bb)
+{
+    unsigned int i;
+    unsigned int result;
+
+    result = 0;
+    for (i=0; i < GCOV_COUNTERS; i++)
+        if (counter_active(bb, i))
+            result++;
+    return result;
+}
+
+/*
+ * Get number of bytes used for one entry in the gcov_fn_info array pointed to
+ * by BB->functions.
+ */
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+    unsigned int stride;
+
+    stride = sizeof(struct gcov_fn_info) + num_counter_active(bb) *
+             sizeof(unsigned int);
+    if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
+    {
+        stride += __alignof__(struct gcov_fn_info) - 1;
+        stride &= ~(__alignof__(struct gcov_fn_info) - 1);
+    }
+    return stride;
+}
+
+/* Get the address of gcov_fn_info for function FUNC of BB. */
+static inline struct gcov_fn_info *
+get_fn_info(struct gcov_info *bb, unsigned int func)
+{
+    return (struct gcov_fn_info *)
+        ((char *)bb->functions + func * get_fn_stride(bb));
+}
+
+/*
+ * Create xen_gcov_info linked list by creating nodes for all gcda files
+ * based on n_files value 
+ */
+static inline int create_bb_list(void)
+{
+    struct gcov_info *node = NULL, *tmp_node = NULL;
+    int i, j, len=0, active;
+    
+    for (i = 0; i < node_info->n_files; i++) 
+    {
+        /* Allocate memory for struct gcov_info */
+        active = node_info->active_counters[i];   
+        len = sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info)*active;
+        node = (struct gcov_info *) kmalloc(len, GFP_KERNEL);
+        for (j=0; j < active; j++) {
+	    len =sizeof(gcov_type) * node_info->ctr_num[i][j];
+            node->counts[j].values = kmalloc(len, GFP_KERNEL);
+        }
+
+        /* Allocate memory for array of struct gcov_fn_info */
+        len = (sizeof(struct gcov_fn_info) + active*sizeof(unsigned int)) * 
+               node_info->n_funcs[i];
+        node->functions = (struct gcov_fn_info *) kmalloc(len,GFP_KERNEL);
+        node->filename   = (char *) kmalloc(FILE_SIZE*sizeof(char),GFP_KERNEL);
+        node->next = NULL;
+
+        if (list_head == NULL) 
+        {
+            list_head = node;
+            tmp_node = node;
+        } 
+        else 
+        {
+            tmp_node->next = node;
+            tmp_node = node;
+        }
+    }
+    return 0;
+}
+
+/* free memory allocated for gcov_info list */
+static inline int free_bb_list(void)
+{
+    struct gcov_info *node = NULL;
+    struct gcov_info *temp = list_head;
+    int active,i;
+
+    for (;temp!=NULL;temp = temp->next) 
+    {
+        node = temp;
+        active=num_counter_active(node);
+        for(i=0; i < active; i++) 
+            kfree(node->counts[i].values);
+        kfree(node->functions);
+        kfree(node);
+    }
+
+    return 0;
+}
+
+/*
+ * Store a portable representation of VALUE in DEST using BYTES*8-1 bits.
+ * Return a non-zero value if VALUE requires more than BYTES*8-1 bits
+ * to store (adapted from gcc/gcov-io.h).
+ */
+static int store_gcov_type(gcov_type value, char *dest, size_t bytes)
+{
+    int upper_bit = (value < 0 ? 128 : 0);
+    size_t i;
+    if (value < 0) 
+    {
+        gcov_type oldvalue = value;
+        value = -value;
+        if (oldvalue != -value)
+            return 1;
+    }
+
+    for (i = 0; i < (sizeof(value) < bytes ? sizeof(value) : bytes); i++) 
+    {
+        dest[i] = value & (i == (bytes - 1) ? 127 : 255);
+        value = value / 256;
+    }
+
+    if (value && value != -1)
+        return 1;
+
+    for (; i < bytes; i++)
+        dest[i] = 0;
+    dest[bytes - 1] |= upper_bit;
+
+    return 0;
+}
+
+/* Return size of .gcda counter section. */
+static size_t
+sizeof_counter_data(struct gcov_info *bb, unsigned int row,
+            unsigned int col)
+{
+
+    struct gcov_fn_info *func = get_fn_info(bb,row);
+
+    if (counter_active(bb, col)) 
+    {
+        return /* tag */ 4 + /* length */ 4 +
+            /* counters */ func->n_ctrs[col] * 8;
+    } 
+    else
+        return 0;
+}
+
+/* Return size of .gcda data section associated with FUNC.  */
+static size_t sizeof_func_data(struct gcov_info *bb, unsigned int row)
+{
+    size_t result;
+    unsigned int type;
+
+    result =
+        /* tag */ 4 + /* length */ 4 + /* ident */ 4 + /* checksum */ 4;
+    for (type = 0; type < GCOV_COUNTERS; type++)
+        result += sizeof_counter_data(bb, row, type);
+    return result;
+}
+
+/* Get size of .gcda file associated with BB. */
+static size_t sizeof_da_file(struct gcov_info *bb)
+{
+    size_t result;
+    unsigned int i;
+
+    result = /* magic */ 4 + /* version */ 4 + /* stamp */ 4;
+    for (i = 0; i < bb->n_functions; i++)
+        result += sizeof_func_data(bb, i);
+    return result;
+}
+
+/*
+ * Store a 32 bit unsigned integer value in GCOV format to memory at address
+ * BUF.
+ */
+static void store_int32(uint32_t i, char *buf)
+{
+    uint32_t *p;
+    p = (int *)buf;
+    *p = i;
+
+}
+
+/*
+ * Store a 64 bit unsigned integer value in GCOV format to memory at address
+ * BUF.
+ */
+static void store_int64(uint64_t i, char *buf)
+{
+    store_int32((uint32_t) (i & 0xffff), buf);
+    store_int32((uint32_t) (i >> 32), buf + 4);
+}
+
+/*
+ * Store a gcov counter in GCOV format to memory at address BUF. The counter is
+ * identified by BB, FUNC, TYPE and COUNTER.
+ */
+static void
+store_counter(struct gcov_info *bb, unsigned int func, unsigned int type,
+          unsigned int counter, char *buf)
+{
+    unsigned int counter_off;
+    unsigned int type_off;
+    unsigned int i;
+    struct gcov_fn_info *func_ptr;
+    /* Get offset into counts array */
+    type_off = 0;
+    for (i = 0; i < type; i++)
+        if (counter_active(bb, i))
+        type_off++;
+    /* Get offset into values array. */
+    counter_off = counter;
+    for (i = 0; i < func; i++) 
+    {
+        func_ptr = get_fn_info(bb,i);
+        counter_off += func_ptr->n_ctrs[type];
+    }
+    /* Create in temporary storage */
+    store_int64(bb->counts[type_off].values[counter_off], buf);
+}
+
+/*
+ * Store a counter section in userspace memory. The counter section is
+ * identified by BB, FUNC and TYPE. The destination address is BUF. Store at
+ * most COUNT bytes beginning at OFFSET. Return the number of bytes stored or a
+ * negative value on error.
+ */
+static ssize_t
+store_counter_data(struct gcov_info *bb, unsigned int func,
+           unsigned int type, char *buf, size_t count, loff_t offset)
+{
+    struct gcov_fn_info *func_ptr;
+    char data[8]; 
+    char *from;
+    size_t len;
+    ssize_t result;
+    unsigned int i;
+
+    func_ptr = get_fn_info(bb,func);
+    result = 0;
+    while (count > 0) 
+    {
+        if (offset < 4) 
+        {
+            /* Tag ID */
+            store_int32((uint32_t) GCOV_TAG_FOR_COUNTER(type),
+               data);
+            len = 4 - offset;
+            from = data + offset;
+        } 
+        else if (offset < 8) 
+        {
+            /* Tag length in groups of 4 bytes */
+            store_int32((uint32_t)
+            func_ptr->n_ctrs[type] * 2, data);
+            len = 4 - (offset - 4);
+            from = data + (offset - 4);
+        } 
+        else 
+        {
+            /* Actual counter data */
+            i = (offset - 8) / 8;
+            /* Check for EOF */
+            if (i >= func_ptr->n_ctrs[type])
+                break;
+            store_counter(bb, func, type, i, data);
+            len = 8 - (offset - 8) % 8;
+            from = data + (offset - 8) % 8;
+        }
+        if (len > count)
+        len = count;
+        if (copy_to_user(buf, from, len))
+        return -EFAULT;
+        count -= len;
+        buf += len;
+        offset += len;
+        result += len;
+    }
+
+    return result;
+}
+
+/* 
+ * Store a function section and associated counter sections in userspace memory.
+ * The function section is identified by BB and FUNC. The destination address is
+ * BUF. Store at most COUNT bytes beginning at OFFSET. Return the number of
+ * bytes stored or a negative value on error.
+ */
+static ssize_t
+store_func_data(struct gcov_info *bb, unsigned int func, char *buf,
+        size_t count, loff_t offset)
+{
+    struct gcov_fn_info *func_ptr;
+    char data[4];
+    char *from;
+    size_t len;
+    unsigned int i;
+    loff_t off;
+    size_t size;
+    ssize_t result;
+    ssize_t rc;
+
+    func_ptr = get_fn_info(bb, func); 
+    result = 0;
+    while (count > 0) 
+    {
+        if (offset < 16) 
+        {
+            if (offset < 4) 
+            {
+                /* Tag ID */
+                store_int32((uint32_t) GCOV_TAG_FUNCTION, data);
+                len = 4 - offset;
+                from = data + offset;
+            } 
+            else if (offset < 8) 
+            {
+                /* Tag length */
+                store_int32(2, data);
+                len = 4 - (offset - 4);
+                from = data + (offset - 4);
+            } 
+            else if (offset < 12) 
+            {
+                /* Function ident */
+                store_int32((uint32_t) func_ptr->ident ,data);
+              
+                len = 4 - (offset - 8);
+                from = data + (offset - 8);
+            } 
+            else 
+            {
+                /* Function checksum */
+                store_int32((uint32_t) func_ptr->checksum,data);
+                len = 4 - (offset - 12);
+                from = data + (offset - 12);
+            }
+            /* Do the actual store */
+            if (len > count)
+                len = count;
+            if (copy_to_user(buf, from, len))
+                return -EFAULT;
+        }  
+        else 
+        {
+            off = 16;
+            len = 0;
+            for (i = 0; i < GCOV_COUNTERS; i++) 
+            {
+                size = sizeof_counter_data(bb, func, i);
+                if (offset < off + size) 
+                {
+                    rc = store_counter_data(bb, func, i,
+                       buf, count,
+                       offset - off);
+                       if (rc < 0)
+                           return rc;
+                       len = rc;
+                       break;
+                }
+                off += size;
+            }
+            /* Check for EOF */
+            if (i == GCOV_COUNTERS)
+                break;
+         } 
+    count -= len;
+    buf += len;
+    offset += len;
+    result += len;
+    }
+
+    return result;
+}
+
+/*
+ * Store data of .gcda file associated with NODE to userspace memory at BUF.
+ * OFFSET specifies the offset inside the .da file. COUNT is the maximum
+ * number of bytes to store. Return the number of bytes stored, zero for
+ * EOF or a negative number in case of error.
+ */
+static ssize_t
+store_da_file(struct gcov_ftree_node *node, char *buf, size_t count,
+          loff_t offset)
+{
+
+    struct gcov_info *bb;
+    char data[4];
+    char *from;
+    size_t len;
+    unsigned int i;
+    loff_t off;
+    size_t size;
+    ssize_t result;
+    ssize_t rc;
+
+    bb = node->bb;
+    result = 0;
+    while (count > 0) 
+        {
+            if (offset < 12) 
+            {
+                if (offset < 4) 
+                {
+                    /* File magic */
+                    store_int32((uint32_t) GCOV_DATA_MAGIC, data);
+                    len = 4 - offset;
+                    from = data + offset;
+                } 
+                 else if (offset < 8) 
+                {
+                    /* File format/GCC version */
+                    store_int32(xen_gcov_version, data);
+                    len = 4 - (offset - 4);
+                    from = data + (offset - 4);
+                } 
+                else 
+                {
+                    /* Time stamp */
+                    store_int32((uint32_t) bb->stamp, data);
+                    len = 4 - (offset - 8);
+                    from = data + (offset - 8);
+                }
+            /* Do the actual store */
+            if (len > count)
+                len = count;
+            if (copy_to_user(buf, from, len))
+                return -EFAULT;
+            } 
+            else 
+            {
+                off = 12;
+                len = 0;
+                for (i = 0; i < bb->n_functions; i++) 
+                {
+
+                    size = sizeof_func_data(bb, i);
+                    if (offset < off + size) 
+                    {
+                        rc = store_func_data(bb, i, buf, count,
+                            offset - off);
+
+                        if (rc < 0)
+                            return rc;
+                        len = rc;
+                         break;
+                    }
+                    off += size;
+
+                }
+                /* Check for EOF */
+                if (i == bb->n_functions)
+                    break;
+            }
+            count -= len;
+            buf += len;
+            offset += len;
+            result += len;
+       }
+
+    return result;
+}
+
+/*
+ * Return size of header which precedes .da file entry associated with BB
+ * in the vmlinux file.
+ */
+static size_t sizeof_vmlinux_header(struct gcov_info *bb)
+{
+    return 8 + PAD8(strlen(bb->filename) + 1);
+}
+
+/*
+ * Store data of header which precedes .da file entry associated with NODE
+ * in the vmlinux file to userspace memory at BUF. OFFSET specifies the offset
+ * inside the header file. COUNT is the maximum number of bytes to store.
+ * Return the number of bytes stored, zero for EOF or a negative number in
+ * case of error.
+ */
+static ssize_t
+store_vmlinux_header(struct gcov_ftree_node *node, char *buf, size_t count,
+             loff_t offset)
+{
+    char data[8];
+    char *from;
+    size_t namelen;
+    ssize_t stored;
+    size_t len;
+
+    namelen = strlen(node->bb->filename);
+    stored = 0;
+    while (count > 0) 
+    {
+        if (offset < 8) 
+        {
+            /* Filename length */
+            if (store_gcov_type(PAD8(namelen + 1), data, 8))
+                return -EINVAL;
+            from = data + offset;
+            len = 8 - offset;
+        } 
+        else if (offset < 8 + namelen) 
+        {
+            /* Filename */
+            from = (char *)node->bb->filename + offset - 8;
+            len = namelen - (offset - 8);
+        } 
+        else if (offset < node->header_size) 
+        {
+            /* Nil byte padding */
+            memset(data, 0, 8);
+            from = data;
+            len = PAD8(namelen + 1) - (offset - 8);
+        }   
+        else
+            break;
+        if (len > count)
+            len = count;
+        if (copy_to_user(buf, from, len))
+            return -EFAULT;
+
+        stored += len;
+        count -= len;
+        offset += len;
+        buf += len;
+    }
+
+    return stored;
+}
+
+/* Update data related to vmlinux file. */
+static void update_vmlinux_data(void)
+{
+    struct gcov_ftree_node *node;
+    loff_t offset;
+
+    offset = 0;
+    for (node = leaf_nodes; node; node = node->next) 
+    {
+        node->offset = offset;
+        node->da_size = sizeof_da_file(node->bb);
+        node->header_size = sizeof_vmlinux_header(node->bb);
+        offset += node->header_size + node->da_size;
+    }
+    proc_vmlinux->size = offset;
+    cached_node = NULL;
+}
+
+/* Read .da or vmlinux file. */
+static ssize_t
+read_gcov(struct file *file, char *buf, size_t count, loff_t * pos)
+{
+    struct gcov_ftree_node *node;
+    struct proc_dir_entry *dir_entry;
+    ssize_t rc;
+
+    mutex_lock(&read_mutex);
+    dir_entry = PDE(file->f_dentry->d_inode);
+    rc = 0;
+    if (dir_entry == proc_vmlinux) 
+    {
+        /* Are we in a sequential read? */
+        if (cached_node && (*pos >= cached_node->offset))
+            node = cached_node;
+        else
+            node = leaf_nodes;
+            /* Find node corresponding to offset */
+        while (node && node->next && (*pos >= node->next->offset))
+            node = node->next;
+            cached_node = node;
+            if (node) 
+            {
+                if (*pos - node->offset < node->header_size)
+                    rc = store_vmlinux_header(node, buf, count,
+                    *pos - node->offset);
+                else
+                {
+                    rc = store_da_file(node, buf, count,
+                    *pos - node->offset -
+                    node->header_size);
+                }
+            }
+    } 
+    else 
+    {
+        node = (struct gcov_ftree_node *)dir_entry->data;
+        if (node) 
+        {
+            rc = store_da_file(node, buf, count, *pos);
+        }
+    }
+    if (rc > 0)
+        *pos += rc;
+    mutex_unlock(&read_mutex);
+    return rc;
+}
+
+/* Reset counters on write request. */
+static ssize_t
+write_gcov(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+    struct gcov_ftree_node *node;
+    struct proc_dir_entry *dir_entry;
+
+    mutex_lock(&write_mutex);
+    dir_entry = PDE(file->f_dentry->d_inode);
+    if (dir_entry == proc_vmlinux) 
+    {
+        /* Reset all nodes */
+        node = leaf_nodes;
+        if (HYPERVISOR_gcovprof_op(GCOVPROF_reset, NULL, !RESET_GCDA)) 
+        {
+            printk(KERN_ERR GCOV_PROC_HEADER
+                   "Failed to reset the vmlinux\n");
+            mutex_unlock(&write_mutex);
+            return EIO;
+        }
+    } 
+    else 
+    {
+        node = (struct gcov_ftree_node *)dir_entry->data;
+        if (HYPERVISOR_gcovprof_op
+            (GCOVPROF_reset, node->bb->filename, RESET_GCDA)) 
+        {
+            printk(KERN_ERR GCOV_PROC_HEADER
+                   "Failed to reset file %s\n", node->bb->filename);
+            mutex_unlock(&write_mutex);
+            return EIO;
+        }
+    }
+    mutex_unlock(&write_mutex);
+    return count;
+}
+
+/* Return a newly allocated copy of STRING. */
+static char *strdup(const char *string)
+{
+    char *result;
+
+    result = (char *)kmalloc(strlen(string) + 1, GFP_KERNEL);
+    if (result)
+        strcpy(result, string);
+    return result;
+}
+
+/* Allocate a new node and fill in NAME and BB. */
+static struct gcov_ftree_node *alloc_node(const char *name,
+                      struct gcov_info *bb)
+{
+    struct gcov_ftree_node *node;
+
+    node = (struct gcov_ftree_node *)
+        kmalloc(sizeof(struct gcov_ftree_node), GFP_KERNEL);
+    if (!node)
+        return NULL;
+    memset(node, 0, sizeof(struct gcov_ftree_node));
+    node->fname = strdup(name);
+    if (!node->fname) 
+    {
+        kfree(node);
+        return NULL;
+    }
+    node->bb = bb;
+    return node;
+}
+
+/* Free memory allocated for NODE. */
+static void free_node(struct gcov_ftree_node *node)
+{
+    if (node == &tree_root)
+        return;
+    if (node->fname)
+    kfree(node->fname);
+    kfree(node);
+}
+
+/* Remove proc filesystem entries associated with NODE. */
+static void delete_from_proc(struct gcov_ftree_node *node)
+{
+    struct proc_dir_entry *parent;
+    int i;
+
+    if (node->parent)
+        parent = node->parent->proc[0];
+    else
+        parent = xen_base;
+    for (i = 0; i < sizeof(node->proc) / sizeof(node->proc[0]); i++)
+        if (node->proc[i])
+            remove_proc_entry(node->proc[i]->name, parent);
+}
+
+/*
+ * Release all resources associated with NODE. If NODE is a directory node,
+ * also clean up all children.
+ */
+static void cleanup_node(struct gcov_ftree_node *node)
+{
+    struct gcov_ftree_node *curr;
+    struct gcov_ftree_node *next;
+    struct gcov_ftree_node *prev;
+
+    next = node;
+    do 
+    {
+        /* Depth first traversal of all children */
+        curr = next;
+        while (curr->files)
+            curr = curr->files;
+        if (curr->sibling)
+            next = curr->sibling;
+        else
+            next = curr->parent;
+        /* Remove from tree */
+        if (curr->parent) 
+        {
+            if (curr->parent->files == curr)
+                curr->parent->files = curr->sibling;
+            else 
+            {
+                for (prev = curr->parent->files;
+                    prev->sibling != curr;
+                    prev = prev->sibling) ;
+                    prev->sibling = curr->sibling;
+            }
+        }
+        /* Remove from leaf node list if necessary */
+        if (curr->bb) 
+        {
+            if (leaf_nodes == curr)
+                leaf_nodes = curr->next;
+            else 
+            {
+                for (prev = leaf_nodes;
+                     prev && (prev->next != curr);
+                     prev = prev->next) ;
+                if (prev)
+                    prev->next = curr->next;
+            }
+        }
+        /* Delete node */
+        delete_from_proc(curr);
+        free_node(curr);
+    } while (node != curr);
+}
+
+/* Clean up NODE and containing path in case it would be left empty. */
+static void cleanup_node_and_path(struct gcov_ftree_node *node)
+{
+    while (node->parent &&
+        node->parent != &tree_root && !node->parent->files->sibling)
+    node = node->parent;
+    cleanup_node(node);
+}
+
+/*
+ * Create a new directory node named NAME under PARENT. Upon success return
+ * zero and update RESULT to point to the newly created node. Return non-zero
+ * otherwise.
+ */
+static int
+create_dir_node(struct gcov_ftree_node *parent, char *name,
+        struct gcov_ftree_node **result)
+{
+    struct gcov_ftree_node *node;
+
+    /* Initialize new node */
+    node = alloc_node(name, NULL);
+    if (!node)
+        return -ENOMEM;
+    /* Create proc filesystem entry */
+    node->proc[0] = proc_mkdir(name, parent->proc[0]);
+    if (!node->proc[0]) 
+    {
+        free_node(node);
+        return -EIO;
+    }
+    /* Insert node into tree */
+    node->parent = parent;
+    node->sibling = parent->files;
+    parent->files = node;
+    *result = node;
+    return 0;
+}
+
+static struct file_operations proc_gcov_operations = {
+    .owner        = THIS_MODULE,
+    .read         = read_gcov,
+    .write        = write_gcov,
+};
+
+/*
+ * Create a new file node named NAME under PARENT. Associate node with BB.
+ * Return zero upon success, non-zero otherwise.
+ */
+static int
+create_file_node(struct gcov_ftree_node *parent, char *name,
+         struct gcov_info *bb)
+{
+    struct gcov_ftree_node *node;
+    char *link_target;
+    char *link_name;
+    int i;
+    /* Initialize new node */
+    node = alloc_node(name, bb);
+    if (!node)
+        return -ENOMEM;
+    /* Create proc filesystem entry */
+    node->proc[0] = create_proc_entry(name, S_IWUSR | S_IRUGO,
+                      parent->proc[0]);
+    if (!node->proc[0]) 
+    {
+        free_node(node);
+        return -EIO;
+    }
+    node->proc[0]->data = node;
+    node->proc[0]->proc_fops = &proc_gcov_operations;
+    node->proc[0]->size = sizeof_da_file(bb);
+    /* Create symbolic links */
+    if (xen_gcov_link) 
+    {
+        /* Note: temp string length is calculated as upper limit */
+        link_target = (char *)kmalloc(strlen(bb->filename) +
+                          strlen(da_ending) +
+                          strlen(node_info->src_path),
+                          GFP_KERNEL);
+        if (!link_target) 
+        {
+            delete_from_proc(node);
+            free_node(node);
+            return -ENOMEM;
+        }
+        for (i = 0; i < sizeof(endings) / sizeof(endings[0]); i++) 
+        {
+
+            strcpy(link_target, bb->filename);
+            link_target[strlen(link_target) -
+                    strlen(da_ending)] = 0;
+            strcat(link_target, endings[i]);
+            link_name = strrchr(link_target, '/') + 1;
+            node->proc[i + 1] = proc_symlink(link_name,
+                             parent->proc[0],
+                             link_target);
+            if (!node->proc[i + 1]) 
+            {
+                kfree(link_target);
+                delete_from_proc(node);
+                free_node(node);
+                return -EIO;
+             }
+        }
+        kfree(link_target);
+    }
+    /* Insert node into tree */
+    node->parent = parent;
+    node->sibling = parent->files;
+    parent->files = node;
+    node->next = leaf_nodes;
+    leaf_nodes = node;
+    return 0;
+}
+
+/* Return proc filesystem entry name for FILENAME. */
+static inline char *get_proc_filename(const char *filename)
+{
+    char *result;
+
+    result = strdup(filename + sourcepath_len + 1);
+    return result;
+}
+
+/*
+ * Create tree node and proc filesystem entry for BB. Create subdirectories as
+ * necessary. Return zero upon success, non-zero otherwise.
+ */
+static int create_node(struct gcov_info *bb)
+{
+    struct gcov_ftree_node *parent;
+    struct gcov_ftree_node *node;
+    char *filename;
+    char *curr;
+    char *next;
+    int rc;
+
+    filename = get_proc_filename(bb->filename);
+    if (!filename)
+        return -ENOMEM;
+    /* Recreate directory path in proc filesystem */
+    parent = &tree_root;
+    for (curr = filename; (next = strchr(curr, '/')); curr = next + 1) 
+    {
+        /* Skip empty path components */
+        if (curr == next)
+            continue;
+        *next = 0;
+        /* Check whether directory already exists */
+        for (node = parent->files;
+             node && (strcmp(node->fname, curr) != 0);
+             node = node->sibling) ;
+        if (!node) 
+        {
+            /* Create directory node */
+            rc = create_dir_node(parent, curr, &node);
+            if (rc) 
+            {
+                if (parent != &tree_root)
+                    cleanup_node_and_path(parent);
+                kfree(filename);
+                return rc;
+            }
+        }
+        parent = node;
+    }
+    rc = create_file_node(parent, curr, bb);
+    kfree(filename);
+    return rc;
+}
+
+static void xeno_prof(void *data)
+{
+    /*update linked list with profiling info and line counts */
+    WARN_ON(HYPERVISOR_gcovprof_op(GCOVPROF_start, list_head, 0));
+    
+    /*again schedule work */
+    schedule_delayed_work(&work, xen_gcov_update * HZ);
+
+}
+
+/* 
+ * Invokes hypercall to get all the necessary gcov information to construct 
+ * gcov linked list in Kernel
+ */
+static inline int get_list_info(void)
+{
+
+    int ret,i;
+    node_info = kmalloc(sizeof(struct node_info), GFP_KERNEL);
+    if ((ret =
+        HYPERVISOR_gcovprof_op(GCOVPROF_get_info, node_info, 0)) != 0)
+        return ret;
+    
+    xen_gcov_version = node_info->g_version;
+
+    node_info->ctr_num =  
+        kmalloc(node_info->n_files * sizeof(gcov_unsigned_t *), GFP_KERNEL);
+    for(i=0;i<node_info->n_files;i++){
+         node_info->ctr_num[i] =
+                kmalloc(GCOV_COUNTERS * sizeof(gcov_unsigned_t), GFP_KERNEL);
+    }
+
+    node_info->n_funcs = 
+        kmalloc(node_info->n_files * sizeof(gcov_unsigned_t), GFP_KERNEL);
+
+    node_info->active_counters = 
+        kmalloc(node_info->n_files * sizeof(unsigned int), GFP_KERNEL);
+    
+    if ((ret = 
+        HYPERVISOR_gcovprof_op(GCOVPROF_get_info, node_info, 1)) != 0)
+         return ret;
+
+    sourcepath_len = strlen(node_info->src_path);
+    return ret;
+}
+
+static int __init xen_gcov_init(void)
+{
+    struct gcov_info *bb;
+    int ret,rc = 0;
+
+    /* seek gcov core variable information & construct the gcov_info list */
+    ret = get_list_info();
+    if (ret) {
+        printk(KERN_ERR GCOV_PROC_HEADER
+           "No Core variable, Check if GCOV core is compiled in or not\n");
+        return -ENOENT;
+    }
+
+    /*add sys entry in /proc/sys/xen for count update tuning*/    
+#ifdef CONFIG_SYSCTL
+    gcov_table_header = register_sysctl_table(gcov_root_table, 0);
+    if (!gcov_table_header)
+        printk(KERN_INFO GCOV_PROC_HEADER
+              "no /proc/sys/xen added\n");
+#endif
+    printk(KERN_INFO GCOV_PROC_HEADER "xen_gcov_link=%d xen_gcov_update=%d\n", 
+                        xen_gcov_link, xen_gcov_update);
+
+
+    /* Create gcov_info linked list */
+    create_bb_list();
+    
+    /*populate the linked list with profiling info and line counts */
+    ret = HYPERVISOR_gcovprof_op(GCOVPROF_start, list_head, 0);
+    if (ret) {
+        printk(KERN_ERR GCOV_PROC_HEADER
+                "Failed to retrive hypervisor profiling info\n");
+        return ret;
+    }
+		
+    /* Initializing root node and /proc/gcov entry */
+    tree_root.fname = GCOV_PROC_ROOT;
+    tree_root.proc[0] = proc_mkdir(tree_root.fname, xen_base);
+    if (!tree_root.proc[0]) { 
+        printk(KERN_ERR GCOV_PROC_HEADER "init failed: could not "
+           "create root proc filesystem entry\n");
+        return -EIO;
+    }
+    /* Create /proc/gcov/vmlinux entry */
+    proc_vmlinux = create_proc_entry(GCOV_PROC_VMLINUX, S_IWUSR | S_IRUGO,
+                 tree_root.proc[0]);
+    if (!proc_vmlinux) 
+    {
+        printk(KERN_ERR GCOV_PROC_HEADER "init failed: could not "
+            "create proc filesystem entry %s\n", GCOV_PROC_VMLINUX);
+        cleanup_node(&tree_root);
+        return -EIO;
+    }
+    proc_vmlinux->proc_fops = &proc_gcov_operations;
+
+    /*populate /proc/xen/gcov entry with data files*/
+    for (bb = list_head; bb != NULL; bb = bb->next) 
+    {
+        rc = create_node(bb);
+        if (rc) 
+        {
+            printk(KERN_ERR GCOV_PROC_HEADER
+                "init failed: could not create node for %s (err=%d)\n",
+            bb->filename, rc);
+            remove_proc_entry(proc_vmlinux->name,
+                   tree_root.proc[0]);
+            cleanup_node(&tree_root);
+            return rc;
+        }
+    } /*done*/
+
+    update_vmlinux_data();
+
+    /*schedule for profiling update after <xen_gcov_update> secs*/
+    schedule_delayed_work(&work, xen_gcov_update * HZ);
+    printk(KERN_INFO GCOV_PROC_HEADER "init done\n");
+    kfree(node_info);
+    return 0;
+}
+
+/* Clean up module data. */
+static void __exit xen_gcov_cleanup(void)
+{
+    cancel_delayed_work(&work);
+    flush_scheduled_work();
+#ifdef CONFIG_SYSCTL
+    unregister_sysctl_table(gcov_table_header);
+#endif
+    remove_proc_entry(proc_vmlinux->name, tree_root.proc[0]);
+    cleanup_node(&tree_root);
+    free_bb_list();
+    printk(KERN_INFO GCOV_PROC_HEADER "Module is now unloaded\n");
+}
+
+module_init(xen_gcov_init);
+module_exit(xen_gcov_cleanup);
diff -r 86d6c6417cf9 include/asm-i386/mach-xen/asm/hypercall.h
--- a/include/asm-i386/mach-xen/asm/hypercall.h	Thu Feb 04 13:08:27 2010 +0000
+++ b/include/asm-i386/mach-xen/asm/hypercall.h	Sun Feb 07 00:13:40 2010 +0530
@@ -411,5 +411,12 @@
 	return _hypercall1(int, tmem_op, op);
 }
 
+static inline int __must_check
+HYPERVISOR_gcovprof_op(
+       int cmd, void *arg, int val)
+{
+       return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
 
 #endif /* __HYPERCALL_H__ */
diff -r 86d6c6417cf9 include/asm-x86_64/mach-xen/asm/hypercall.h
--- a/include/asm-x86_64/mach-xen/asm/hypercall.h	Thu Feb 04 13:08:27 2010 +0000
+++ b/include/asm-x86_64/mach-xen/asm/hypercall.h	Sun Feb 07 00:13:40 2010 +0530
@@ -419,4 +419,12 @@
 	return _hypercall1(int, tmem_op, op);
 }
 
+static inline int __must_check
+HYPERVISOR_gcovprof_op(
+       int cmd, void *arg, int val)
+{
+       return _hypercall3(int, gcovprof_op, cmd, arg, val);
+}
+
+
 #endif /* __HYPERCALL_H__ */
diff -r 86d6c6417cf9 include/xen/interface/xen-gcov.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/xen/interface/xen-gcov.h	Sun Feb 07 00:13:40 2010 +0530
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *  xen-gcov.h
+ *   
+ *  Interface for populating hypervisor profiling info under /proc/xen
+ *  
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *   
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *   
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *   
+ *  Author: tej parkash <tej.parkash@hcl.in>
+ *  Written by tej parkash and team
+ *  
+ */
+/******************************************************************************/
+
+#ifndef __XEN_PUBLIC_GCOVPROF_H__
+#define __XEN_PUBLIC_GCOVPROF_H__
+
+#include "xen.h"
+
+/*
+ * Commands to HYPERVISOR_gcovprof_op()
+ */
+#define GCOVPROF_get_info             0
+#define GCOVPROF_start		      1
+#define GCOVPROF_reset		      2
+#define GCOVPROF_last_op              3
+
+
+/*gcc specific macros*/
+#define GCOV_COUNTERS                 5
+#define GCOV_DATA_MAGIC     ((gcov_unsigned_t) 0x67636461)
+#define GCOV_TAG_FUNCTION   ((gcov_unsigned_t) 0x01000000)
+#define GCOV_TAG_COUNTER_BASE   ((gcov_unsigned_t) 0x01a10000)
+#define GCOV_TAG_FOR_COUNTER(COUNT)                 \
+    (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t) (COUNT) << 17))
+
+/*xen-gcov-proc specific macros*/
+#define RESET_GCDA      0
+
+#define FILE_SIZE       100
+
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
+typedef signed gcov_type __attribute__ ((mode (DI)));
+typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
+
+
+struct gcov_ftree_node
+{
+    char *fname;             	       /* Hierarchy-relative name */
+    struct gcov_ftree_node *sibling;   /* First sibling of this node */
+    struct gcov_ftree_node *files;     /* First child of this node */
+    struct gcov_ftree_node *parent;    /* Parent of this node */
+    struct proc_dir_entry *proc[4];    /* Entries for .da, .bb, .bbg, .c */
+    struct gcov_info *bb;              /* Associated struct bb */
+    loff_t offset;           	       /* Offset in vmlinux file */
+    size_t da_size;          	       /* Size of associated .da file */
+    size_t header_size;      	       /* Size of associated file header */
+    struct gcov_ftree_node *next;      /* Next leaf node */
+};
+
+
+struct gcov_fn_info
+{
+    gcov_unsigned_t ident;    	       /* unique ident of function */
+    gcov_unsigned_t checksum; 	       /* function checksum */
+    unsigned int n_ctrs[0];            /* instrumented counters */
+};
+typedef struct gcov_fn_info gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_fn_info_t);
+
+struct gcov_ctr_info
+{
+    gcov_unsigned_t num;      	       /* number of counters.  */
+    gcov_type *values;		       /* thier values. */
+    gcov_merge_fn merge;      	       /* merge function  */
+};
+typedef struct  gcov_ctr_info gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_ctr_info_t);
+
+/* Information about a single object file.  */
+struct gcov_info
+{
+    gcov_unsigned_t version;  	       /* expected version number */
+    struct gcov_info *next;   	       /* link to next, used by libgcov */
+
+    gcov_unsigned_t stamp;    	       /* uniquifying time stamp */
+    char *filename;
+
+    unsigned int n_functions;          /* number of functions */
+    struct gcov_fn_info *functions;    /* table of functions */
+
+    unsigned int ctr_mask;             /* mask of counters instrumented.  */
+    struct gcov_ctr_info counts[0];    /* count data */
+};
+typedef struct gcov_info gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_info_t);
+
+struct node_info
+{
+    char src_path[100];		       /* source path */
+    unsigned long g_version;	       /* gcov version */
+    unsigned int n_files;	       /* num of file in hypervisor code */
+    gcov_unsigned_t **ctr_num;	       /* count variables */
+    unsigned int *n_funcs;             /* num of funcs per bb struct */
+    unsigned int *active_counters;     /* No of gcov counters */
+	
+};
+typedef struct node_info node_info_t;
+DEFINE_XEN_GUEST_HANDLE(node_info_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r 86d6c6417cf9 include/xen/interface/xen.h
--- a/include/xen/interface/xen.h	Thu Feb 04 13:08:27 2010 +0000
+++ b/include/xen/interface/xen.h	Sun Feb 07 00:13:40 2010 +0530
@@ -93,6 +93,7 @@
 #define __HYPERVISOR_domctl               36
 #define __HYPERVISOR_kexec_op             37
 #define __HYPERVISOR_tmem_op              38
+#define __HYPERVISOR_gcovprof_op          39
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
diff -r 86d6c6417cf9 include/xen/xen_proc.h
--- a/include/xen/xen_proc.h	Thu Feb 04 13:08:27 2010 +0000
+++ b/include/xen/xen_proc.h	Sun Feb 07 00:13:40 2010 +0530
@@ -4,6 +4,7 @@
 
 #include <linux/proc_fs.h>
 
+extern struct proc_dir_entry *xen_base;
 extern struct proc_dir_entry *create_xen_proc_entry(
 	const char *name, mode_t mode);
 extern void remove_xen_proc_entry(

[-- Attachment #3: linux-wa-v1.patch --]
[-- Type: text/x-patch, Size: 497 bytes --]

diff -r b0a497fd3322 drivers/xen/gcov/xen-gcov-proc.c
--- a/drivers/xen/gcov/xen-gcov-proc.c	Thu May 06 06:55:42 2010 +0530
+++ b/drivers/xen/gcov/xen-gcov-proc.c	Thu May 06 06:57:08 2010 +0530
@@ -1193,7 +1193,7 @@
     proc_vmlinux->proc_fops = &proc_gcov_operations;
 
     /*populate /proc/xen/gcov entry with data files*/
-    for (bb = list_head; bb != NULL; bb = bb->next) 
+    for (bb = list_head->next; bb != NULL; bb = bb->next) 
     {
         rc = create_node(bb);
         if (rc) 

[-- Attachment #4: xen-unstable-gcov-v1.patch --]
[-- Type: text/x-patch, Size: 21400 bytes --]

diff -r efa1b905d893 xen/Rules.mk
--- a/xen/Rules.mk	Tue May 04 13:59:55 2010 +0100
+++ b/xen/Rules.mk	Thu May 06 06:53:09 2010 +0530
@@ -10,6 +10,14 @@
 crash_debug   ?= n
 gdbsx         ?= n
 frame_pointer ?= n
+# gcov profiler build for xen hypervisor only
+gcov          ?= n
+
+# xen source path to get update in .gcno files
+ifeq ($(gcov),y)
+xen_src := $(CURDIR)
+xentree := $(if $(xen_src),$(xen_src),$(CURDIR))
+endif
 
 XEN_ROOT=$(BASEDIR)/..
 include $(XEN_ROOT)/Config.mk
@@ -43,6 +51,7 @@
 ALL_OBJS-$(x86)          += $(BASEDIR)/crypto/built_in.o
 
 CFLAGS-y                += -g -D__XEN__
+CFLAGS-$(gcov)          += -fprofile-arcs -ftest-coverage -DCONFIG_XEN_GCOV
 CFLAGS-$(XSM_ENABLE)    += -DXSM_ENABLE
 CFLAGS-$(FLASK_ENABLE)  += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
 CFLAGS-$(FLASK_ENABLE)  += -DFLASK_DEVELOP -DFLASK_BOOTPARAM -DFLASK_AVC_STATS
@@ -107,12 +116,17 @@
 
 .PHONY: clean
 clean:: $(addprefix _clean_, $(subdir-all))
-	rm -f *.o *~ core $(DEPS)
+	rm -f *.o *.gcno *~ core $(DEPS)
 _clean_%/: FORCE
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
 
 %.o: %.c Makefile
+ifeq ($(gcov),y)
+	$(CC) $(CFLAGS) -c -o $@ \
+		$(if $(filter-out /%,$<),$(xentree)/$<,$<)
+else
 	$(CC) $(CFLAGS) -c $< -o $@
+endif
 
 %.o: %.S Makefile
 	$(CC) $(AFLAGS) -c $< -o $@
diff -r efa1b905d893 xen/arch/x86/mm/Makefile
--- a/xen/arch/x86/mm/Makefile	Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/Makefile	Thu May 06 06:53:09 2010 +0530
@@ -10,5 +10,18 @@
 obj-y += mem_paging.o
 obj-y += mem_sharing.o
 
+LN = /bin/ln
+num=$*.c
+
 guest_walk_%.o: guest_walk.c Makefile
+ifeq ($(gcov),y)
+	$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \
+		$(if $(filter-out /%,$<),$(xentree)/$<,$<)
+	$(LN) -f -s guest_walk.c guest_walk_$(num)
+else
 	$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
+endif
+
+.PHONY: clean
+clean::
+	rm -f guest_walk_*.c
diff -r efa1b905d893 xen/arch/x86/mm/hap/Makefile
--- a/xen/arch/x86/mm/hap/Makefile	Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/hap/Makefile	Thu May 06 06:53:09 2010 +0530
@@ -4,8 +4,22 @@
 obj-y += guest_walk_4level.o
 obj-y += p2m-ept.o
 
+LN = /bin/ln
+
 guest_levels  = $(subst level,,$(filter %level,$(subst ., ,$(subst _, ,$(1)))))
 guest_walk_defns = -DGUEST_PAGING_LEVELS=$(call guest_levels,$(1))
 
+num = $(call guest_levels,$(@F))level.c
+
 guest_walk_%level.o: guest_walk.c Makefile
+ifeq ($(gcov),y)
+	$(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c -o $@ \
+		$(if $(filter-out /%,$<),$(xentree)/$<,$<)
+	$(LN) -f -s guest_walk.c guest_walk_$(num)
+else
 	$(CC) $(CFLAGS) $(call guest_walk_defns,$(@F)) -c $< -o $@
+endif
+       
+.PHONY: clean
+clean::
+	rm -f guest_walk_*.c
diff -r efa1b905d893 xen/arch/x86/mm/shadow/Makefile
--- a/xen/arch/x86/mm/shadow/Makefile	Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/mm/shadow/Makefile	Thu May 06 06:53:09 2010 +0530
@@ -1,5 +1,18 @@
 obj-$(x86_32) += common.o guest_2.o guest_3.o
 obj-$(x86_64) += common.o guest_2.o guest_3.o guest_4.o
 
+LN = /bin/ln
+num=$*.c
+
 guest_%.o: multi.c Makefile
+ifeq ($(gcov),y)
+	$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c -o $@ \
+		$(if $(filter-out /%,$<),$(xentree)/$<,$<)
+	$(LN) -f -s multi.c guest_$(num)
+else
 	$(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@
+endif
+
+.PHONY: clean
+clean::
+	rm -f guest_*.c
diff -r efa1b905d893 xen/arch/x86/x86_32/entry.S
--- a/xen/arch/x86/x86_32/entry.S	Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/x86_32/entry.S	Thu May 06 06:53:09 2010 +0530
@@ -706,6 +706,9 @@
         .long do_domctl
         .long do_kexec_op
         .long do_tmem_op
+#ifdef CONFIG_XEN_GCOV
+        .long do_gcovprof_op
+#endif
         .rept __HYPERVISOR_arch_0-((.-hypercall_table)/4)
         .long do_ni_hypercall
         .endr
@@ -754,6 +757,9 @@
         .byte 1 /* do_domctl            */
         .byte 2 /* do_kexec_op          */
         .byte 1 /* do_tmem_op           */
+#ifdef CONFIG_XEN_GCOV
+        .byte 3 /* do_gcovprof_op      */
+#endif
         .rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
diff -r efa1b905d893 xen/arch/x86/x86_64/entry.S
--- a/xen/arch/x86/x86_64/entry.S	Tue May 04 13:59:55 2010 +0100
+++ b/xen/arch/x86/x86_64/entry.S	Thu May 06 06:53:09 2010 +0530
@@ -695,6 +695,9 @@
         .quad do_domctl
         .quad do_kexec_op
         .quad do_tmem_op
+#ifdef CONFIG_XEN_GCOV
+        .quad do_gcovprof_op
+#endif
         .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
         .quad do_ni_hypercall
         .endr
@@ -743,6 +746,9 @@
         .byte 1 /* do_domctl            */
         .byte 2 /* do_kexec             */
         .byte 1 /* do_tmem_op           */
+#ifdef CONFIG_XEN_GCOV
+        .byte 3 /* do_gcovprof_op       */
+#endif
         .rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
diff -r efa1b905d893 xen/common/Makefile
--- a/xen/common/Makefile	Tue May 04 13:59:55 2010 +0100
+++ b/xen/common/Makefile	Thu May 06 06:53:09 2010 +0530
@@ -40,6 +40,7 @@
 
 obj-$(CONFIG_X86) += decompress.o bunzip2.o unlzma.o
 
+obj-$(gcov)        += xen-gcov-core.o
 obj-$(perfc)       += perfc.o
 obj-$(crash_debug) += gdbstub.o
 obj-$(xenoprof)    += xenoprof.o
@@ -53,3 +54,6 @@
 subdir-$(ia64) += hvm
 
 subdir-y += libelf
+
+CFLAGS += -DSRC_PATH='"$(BASEDIR)"'
+
diff -r efa1b905d893 xen/common/xen-gcov-core.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xen-gcov-core.c	Thu May 06 06:53:09 2010 +0530
@@ -0,0 +1,389 @@
+/**
+ *  xen-gcov-core.c: arch dependent code for hypervisor profiling
+ *
+ *  Written by tej parkash and team(tej.parkash@hcl.in)
+ *                
+ */
+/***************************************************************************/
+#include <xen/init.h>
+#include <xen/kernel.h>
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/string.h>
+#include <public/xen-gcov.h>
+#include <xen/paging.h>
+#include <xsm/xsm.h>
+#include <xen/config.h>
+#include <xen/lib.h>
+
+
+#define XEN_GCOV_CORE    "xen-gcov-core:"
+#define FILE_SIZE	100
+
+/* No of XEN source files to profile */
+static int num_xen_files;
+
+gcov_unsigned_t gcov_version = 0;
+
+/* List head for gcov_info structure list */
+struct gcov_info *bb_head;
+
+/* head of xen-gcov-info linked list */
+struct gcov_info *bb_list_head = NULL;
+
+
+/* global constructor list */
+struct ctor_list 
+{
+    unsigned long num;
+    ctor_t ctor[];
+};
+
+/* Start of global constructor list. */
+extern struct ctor_list __CTOR_LIST__;
+
+/* 
+ * Determine whether counter TYPE is active in list node 
+ * For gcc 3.4 to 4.3 only counter 0 will be active
+ *  
+ */
+static inline int
+counter_active(struct gcov_info *bb, unsigned int type)
+{
+    return (1 << type) & bb->ctr_mask;
+}
+
+/* Return the number of active counter types for BB. */
+static inline unsigned int
+num_counter_active(struct gcov_info *bb)
+{
+        unsigned int i;
+        unsigned int result;
+
+        result = 0;
+        for (i=0; i < GCOV_COUNTERS; i++)
+                if (counter_active(bb, i))
+                        result++;
+        return result;
+}
+
+/* 
+ * Get number of bytes used for one entry in the gcov_fn_info array pointed to
+ * by BB->functions.
+ */
+static inline unsigned int
+get_fn_stride(struct gcov_info *bb)
+{
+    unsigned int stride;
+
+    stride = sizeof(struct gcov_fn_info) + num_counter_active(bb)*
+             sizeof(unsigned int);
+    if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int)) 
+    {
+        stride += __alignof__(struct gcov_fn_info) - 1;
+        stride &= ~(__alignof__(struct gcov_fn_info) - 1);
+    }
+    return stride;
+}
+
+/* Get the address of gcov_fn_info for function FUNC of BB. */
+static inline struct gcov_fn_info *
+get_fn_info(struct gcov_info *bb, unsigned int func)
+{
+    return (struct gcov_fn_info *)
+        ((char *)bb->functions + func * get_fn_stride(bb));
+}
+
+/* Reset the execution count values on each list node */
+static void reset(struct gcov_info *bb)
+{
+
+    unsigned int i;
+    struct gcov_ctr_info *ctr;
+    ctr = bb->counts;
+    for (i=0; i < GCOV_COUNTERS; i++)
+    {
+        if (counter_active(bb, i)) 
+        {
+            memset(ctr->values, 0, ctr->num * sizeof(gcov_type));
+            ctr++;
+        }
+    }
+}
+
+
+/*
+ * Create xen_gcov_info linked list by accessing kernel nodes
+ * based on num of xen file to be profiled, This list act 
+ * as temporary variable between Xen bb_head and kernel list_head 
+ */
+
+static inline int create_bb_list(void) 
+{
+    struct gcov_info *node = NULL, *tmp_node = NULL, *bb = bb_head;
+    int i, j, len=0, active, len1=0;
+
+    for (i = 0; i < num_xen_files; i++)
+    {
+        /* Allocate memory for struct gcov_info */
+	active = num_counter_active(bb);
+        len = sizeof(struct gcov_info) + sizeof(struct gcov_ctr_info)*active;
+        node = (struct gcov_info *) xmalloc_bytes(len);
+        for (j=0; j < active; j++) 
+	{
+            len1 = sizeof(gcov_type) *bb->counts[j].num;
+            node->counts[j].values = xmalloc_bytes(len1);
+            memset(node->counts[j].values, 0, len1);
+        }
+
+        /* Allocate memory for array of struct gcov_fn_info */
+        len = (sizeof(struct gcov_fn_info) + active*sizeof(unsigned int)) *
+               bb->n_functions;
+        node->functions = (struct gcov_fn_info *) xmalloc_bytes(len);
+        node->filename   = (char *) xmalloc_bytes(FILE_SIZE*sizeof(char));
+        node->next = NULL;
+
+        if (bb_list_head == NULL) 
+        {
+            bb_list_head = node;
+            tmp_node = node;
+        }
+        else
+        {
+            tmp_node->next = node;
+            tmp_node = node;
+        }
+	bb = bb->next;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Func to reset the execution counts. Reset all nodes count 
+ * if mul defined else reset single file count specified in arg.
+ */
+
+static int reset_counts(XEN_GUEST_HANDLE(void) arg, int mul)
+{
+    struct gcov_info *tmp=bb_head;
+    char bb_file[100];
+
+    if (!mul)
+    {
+        /* reset single data file */
+        if ( copy_from_guest(&bb_file, arg, 1) )
+            return -EFAULT;
+        for(;tmp!=NULL;tmp=tmp->next)
+        {
+            if(!strcmp(tmp->filename, bb_file))
+            {
+                reset(tmp);
+                break;
+            }
+            else
+                continue;
+        }
+    }
+    else
+    {
+        /* reset all data files */
+        for(;tmp!=NULL;tmp=tmp->next)
+            reset(tmp);
+    }
+    return 0;
+}
+
+/* 
+ * Func copies metadata in each gcov_info list nodes to guest. 
+ * with this metadeta, guest populates and update the /proc 
+ * with gcov data files (*.gcda)
+ */
+
+static int ret_profiled_data(XEN_GUEST_HANDLE(void) arg, int val)
+{
+    struct gcov_info *bb, *tmp = bb_head;
+    struct gcov_fn_info *func,*fn_ptr;
+    int i, j, active,len;
+
+    bb = bb_list_head;
+    if (copy_from_guest(bb_list_head, arg, 1))
+   	     return -EFAULT;
+
+    /* iterate through list nodes to copy metadata in Guest nodes*/
+    for(;tmp!=NULL, bb!=NULL; tmp = tmp->next)
+    {
+	
+        bb->version  = tmp->version;
+        bb->stamp    = tmp->stamp;
+        len=strlen(tmp->filename)+1;
+        memcpy(bb->filename, tmp->filename,sizeof(char)*len);
+        bb->ctr_mask    = tmp->ctr_mask;
+        bb->n_functions = tmp->n_functions;
+
+        
+        active= num_counter_active(tmp); 
+        /* Copy functions data */        
+        for(i=0;i<tmp->n_functions;i++) 
+        {
+            fn_ptr= get_fn_info(bb,i);
+            func = get_fn_info(tmp,i);
+            fn_ptr->ident=func->ident;
+            fn_ptr->checksum=func->checksum;
+            for (j=0;j< active;j++) 
+                fn_ptr->n_ctrs[j]=func->n_ctrs[j];
+        }
+
+        /* Copy count data */
+        for (i=0; i < active; i++) {
+            bb->counts[i].num = tmp->counts[i].num;
+            bb->counts[i].merge = tmp->counts[i].merge;
+            len = sizeof(gcov_type)*tmp->counts[i].num;
+            memcpy(bb->counts[i].values, tmp->counts[i].values, len);
+         }   
+        /*increment the bb_head pointers*/
+        bb=bb->next;
+    }
+
+    if ( copy_to_guest(arg, bb_list_head, 1) )
+	        return -EFAULT;
+
+    return 0;
+}
+
+/* 
+ * Func to retrieve the inital gcov core information
+ * by Kernel 
+ * e.g source path, no. of files etc. 
+ */
+
+static int info_to_guest(XEN_GUEST_HANDLE(void) arg,int num)
+{
+    
+    struct gcov_info *bb = bb_head;
+    node_info_t *tmp  = xmalloc(struct node_info);
+    int i, j, active;
+    
+    if( copy_from_guest(tmp, arg, 1) )
+        return -EFAULT;
+    if ( num == 0 ) 
+    {
+        safe_strcpy(tmp->src_path,SRC_PATH);
+        tmp->g_version=gcov_version;
+        tmp->n_files=num_xen_files;
+
+    	/* Create the bb_list_head */
+	create_bb_list(); 
+    } 
+    else 
+    {
+       for(i=0;i<num_xen_files;i++)
+        {
+            tmp->n_funcs[i]=bb->n_functions;
+            active=num_counter_active(bb);
+            tmp->active_counters[i]= active;
+            for(j=0; j<GCOV_COUNTERS; j++) {
+                 tmp->ctr_num[i][j]= bb->counts[j].num;
+	    }
+
+	    bb=bb->next;
+        }
+    }
+
+    if( copy_to_guest(arg, tmp, 1) )
+        return -EFAULT;
+
+
+    return 0;
+}
+
+/*internal hyercall functions*/
+int do_gcovprof_op(int op, XEN_GUEST_HANDLE(void) arg, int val)
+{
+    int ret = 0;
+    if ((op < 0) || (op > GCOVPROF_last_op)) 
+    {
+        printk(KERN_ERR XEN_GCOV_CORE "Invalid operation %d\n", op);
+        return -EINVAL;
+    }
+    switch (op) 
+    {
+        case GCOVPROF_get_info:
+            ret = info_to_guest(arg, val);
+            break;
+
+        case GCOVPROF_start:
+            ret = ret_profiled_data(arg,val);
+            break;
+
+        case GCOVPROF_reset:
+            ret = reset_counts(arg,val);
+            break;
+
+        default:
+            ret = -ENOSYS;
+    }
+    return ret;
+}
+
+/* 
+ * Call constructors and create gcov_info linked list 
+ * List contains metadeta to construct gcov data files
+ * e.g data file name, execution counts etc. 
+ */
+void do_global_ctors(ctor_t ctor[], unsigned long num)
+{
+    unsigned long i;
+
+    /* Call constructors and create gcov_info linked list*/
+    for (i = 0; i < num && ctor[i]; i++)
+        ctor[i] ();
+    /* Holds number of executable scanned by constructor */
+    num_xen_files = i-1;
+}
+
+
+/*Register supplied struct BB. Called by each object code constructor. */
+void __gcov_init(struct gcov_info *bb)
+{
+    if (!bb->version)
+        return;
+    /*Check for compatible gcc version */
+    if (gcov_version == 0)
+        gcov_version = bb->version;
+    else if (bb->version != gcov_version) 
+    {
+        printk(KERN_WARNING XEN_GCOV_CORE "gcc version mismatch in "
+                  "file '%s'!\n", bb->filename);
+        return;
+    }
+    /*Set up linked list */
+    bb->version = 0;
+    bb->next = bb_head;
+    bb_head = bb;
+
+}
+
+static int __init gcov_init(void)
+{
+    do_global_ctors(__CTOR_LIST__.ctor, __CTOR_LIST__.num);
+    printk(KERN_INFO XEN_GCOV_CORE "init done\n");
+    return 0;
+}
+
+__initcall(gcov_init);
+
+/* Unused functions needed to prevent linker errors. */
+void __gcov_flush(void) {}
+void __gcov_merge_add(gcov_type * counters, unsigned int n_counters){}
+void __gcov_merge_single(gcov_type * counters, unsigned int n_counters){}
+void __gcov_merge_delta(gcov_type * counters, unsigned int n_counters){}
+
+EXPORT_SYMBOL(__gcov_init);
+EXPORT_SYMBOL(do_global_ctors);
+EXPORT_SYMBOL(__gcov_flush);
+EXPORT_SYMBOL(__gcov_merge_add);
+EXPORT_SYMBOL(__gcov_merge_single);
+EXPORT_SYMBOL(__gcov_merge_delta);
diff -r efa1b905d893 xen/include/public/xen-gcov.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xen-gcov.h	Thu May 06 06:53:09 2010 +0530
@@ -0,0 +1,109 @@
+/******************************************************************************
+ * xen-gcov.h
+ * 
+ * Interface for enabling and populating hypervisor profiling info.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: tej parkash <tej.parkash@hcl.in>
+ * Written by tej parkash and team
+ *
+ */
+/******************************************************************************/
+
+#ifndef __XEN_PUBLIC_GCOVPROF_H__
+#define __XEN_PUBLIC_GCOVPROF_H__
+
+#include "xen.h"
+
+/*
+ * Commands to HYPERVISOR_gcovprof_op()
+ */
+#define GCOVPROF_get_info           0
+#define GCOVPROF_start              1
+#define GCOVPROF_reset              2
+#define GCOVPROF_last_op            3
+
+/*gcc specific macros*/
+#define GCOV_COUNTERS               5
+#define GCOV_DATA_MAGIC     ((gcov_unsigned_t) 0x67636461)
+#define GCOV_TAG_FUNCTION   ((gcov_unsigned_t) 0x01000000)
+#define GCOV_TAG_COUNTER_BASE   ((gcov_unsigned_t) 0x01a10000)
+#define GCOV_TAG_FOR_COUNTER(COUNT)                 \
+    (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t) (COUNT) << 17))
+
+
+typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
+typedef signed gcov_type __attribute__ ((mode (DI)));
+typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
+typedef void (*ctor_t)(void);
+
+struct gcov_fn_info
+{
+    gcov_unsigned_t ident;             /* unique ident of function */
+    gcov_unsigned_t checksum;          /* function checksum */
+    unsigned n_ctrs[0];                /* instrumented counters */
+};
+typedef struct gcov_fn_info gcov_fn_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_fn_info_t);
+
+struct gcov_ctr_info
+{
+    gcov_unsigned_t num;               /* number of counters.  */
+    gcov_type *values;                 /* their values.  */
+    gcov_merge_fn merge;               /* The function used to merge them.  */
+};
+typedef struct  gcov_ctr_info gcov_ctr_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_ctr_info_t);
+
+/* Information about a single object file.  */
+struct gcov_info
+{
+    gcov_unsigned_t version;           /* expected version number */
+    struct gcov_info *next;            /* link to next, used by libgcov */
+
+    gcov_unsigned_t stamp;             /* uniquifying time stamp */
+    char *filename;
+
+    unsigned n_functions;              /* number of functions */
+    struct gcov_fn_info *functions;    /* table of functions */
+
+    unsigned ctr_mask;                 /* mask of counters instrumented.  */
+    struct gcov_ctr_info counts[0];    /* count data. The number of bits
+                                         set in the ctr_mask field
+                                         determines how big this array
+                                         is.  */
+};
+typedef struct gcov_info gcov_info_t;
+DEFINE_XEN_GUEST_HANDLE(gcov_info_t);
+
+/* info to construct guest Nodes */
+struct node_info 
+{
+    char src_path[100];		       /* xen source code path */
+    unsigned long g_version; 
+    unsigned int n_files;	       /* max. nodes */
+    gcov_unsigned_t **ctr_num;         /* count per node */
+    unsigned int *n_funcs;             /* funcs per node */
+    unsigned int *active_counters;     /* No of active gcov counters per BB */
+};
+typedef struct node_info node_info_t;
+DEFINE_XEN_GUEST_HANDLE(node_info_t);
+
+#endif /* __XEN_PUBLIC_GCOVPROF_H__ */
diff -r efa1b905d893 xen/include/xen/config.h
--- a/xen/include/xen/config.h	Tue May 04 13:59:55 2010 +0100
+++ b/xen/include/xen/config.h	Thu May 06 06:53:09 2010 +0530
@@ -95,4 +95,23 @@
 #define __cpuinitdata
 #define __cpuinit
 
+#ifdef CONFIG_XEN_GCOV
+#define SORT(x)        x
+#define CONSTRUCTORS                           \
+       __CTOR_LIST__ = .;                  \
+       LONG((__CTOR_END__ - __CTOR_LIST__) /           \
+           (__CTOR_LIST2__ - __CTOR_LIST__) - 2)       \
+       __CTOR_LIST2__ = .;                 \
+       *(SORT(.ctors))                     \
+       LONG(0)                         \
+       __CTOR_END__ = .;                   \
+       __DTOR_LIST__ = .;                  \
+       LONG((__DTOR_END__ - __DTOR_LIST__) /           \
+           (__CTOR_LIST2__ - __CTOR_LIST__) - 2)       \
+       *(SORT(.dtors))                     \
+       LONG(0)                         \
+       __DTOR_END__ = .;
+
+#endif /* CONFIG_XEN_GCOV */
+
 #endif /* __XEN_CONFIG_H__ */

[-- Attachment #5: README --]
[-- Type: application/octet-stream, Size: 3390 bytes --]


---------------------------------------------------------------
- README file for the GCOV extention (LCOV)
- Includes access of Kernel/HYPERVISOR/Userspace Program
---------------------------------------------------------------


Description
-----------

  LCOV is an extension of GCOV, a GNU tool which provides information about
  what parts of a program are actually executed (i.e. "covered") while running
  a particular test case. The functionality is HTML based output. Where coverage 
  rates are additionaly indicated using bar graphs and specific colors.

Contents
---------
1. About lcov config file (/etc/lcovrc)
2. An example of how to access kernel coverage data 
3. An example of how to access HYPERVISOR coverage data
4. An example of how to access coverage data for a user space program


1. About lcov config file (/etc/lcovrc)
----------------------------------------

 The LCOV package is available as either RPM or tarball from:
     
    http://ltp.sourceforge.net/coverage/lcov.php

 LCOV has been modified to support both kernel and xen hypervisor by editing lcov config file.
 LCOV config file will be located in /etc/lcovrc, there is variable called lcov_gcov_dir which
 has the directory path containing gcov kernel files. 

	* Kernel directory path lcov_gcov_dir = /proc/gcov
	* Xen hypervisor directory path lcov_gcov_dir = /proc/xen/gcov

 By defualt config file has kernel directory path (i.e /proc/gcov). User has to specify either 
 kernel path or xen hypervisor path. 	

2. An example of how to access kernel coverage data
----------------------------------------------------
Requirements: get and install gcov-kernel package

 User has to make sure that lcov_gcov_dir should hold the directory path "/proc/gcov" in LCOV 
 config file (i.e /etc/lcovrc).

  a) Capturing the current coverage state to a file

     lcov --capture --output-file kernel.info

  b) Resetting counters

     lcov --zerocounters

  c) Getting HTML output

     genhtml kernel.info

Point the web browser of your choice to the resulting index.html file.

3. An example of how to access HYPERVISOR coverage data
----------------------------------------------------
Requirements: get and install GCOV-HYPERVISOR package

 User has to make sure that lcov_gcov_dir should hold the directory path "/proc/xen/gcov" in LCOV 
 config file (i.e /etc/lcovrc). 

  a) Capturing the current coverage state to a file

     lcov --capture --output-file kernel.info

  b) Resetting counters

     lcov --zerocounters

  c) Getting HTML output

     genhtml kernel.info

Point the web browser of your choice to the resulting index.html file.

4. An example of how to access coverage data for a user space program
---------------------------------------------------------------------
Requirements: compile the program in question using GCC with the options
-fprofile-arcs and -ftest-coverage. Assuming the compile directory is called
"appdir", do the following:

  a) Resetting counters

     lcov --directory appdir --zerocounters

  b) Capturing the current coverage state to a file (works only after the
     application has been started and stopped at least once)

     lcov --directory appdir --capture --output-file app.info

  c) Getting HTML output

     genhtml app.info

Point the web browser of your choice to the resulting index.html file.





































 







[-- Attachment #6: lcov-screenshot --]
[-- Type: application/octet-stream, Size: 126300 bytes --]

[-- Attachment #7: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Xen-devel] Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit)
  2010-05-07 20:01 Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit) Tej
@ 2010-05-10 14:53 ` Konrad Rzeszutek Wilk
  2010-05-10 17:21   ` Tej
  2010-05-10 17:26   ` Tej
  0 siblings, 2 replies; 4+ messages in thread
From: Konrad Rzeszutek Wilk @ 2010-05-10 14:53 UTC (permalink / raw)
  To: Tej; +Cc: George Dunlap, xen-devel, xen-users, parkash.tej

On Sat, May 08, 2010 at 01:31:01AM +0530, Tej wrote:
> All,
> 
> Here are the latest patches to expreiment with gcov profiler for xen
> hypervisor. I have tested current patches on Intel i686.

Nice..

> System Details:
> gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)
> gcov (Ubuntu 4.3.3-5ubuntu4) 4.3.3
> Kernel 2.6.28-11-generic

Uhh? 2.6.28 or 2.6.18?

I hate to tell you this but development is happening in the pv-ops
kernel, not anymore in the XenLinux branches :-(

Any chance you can rebase those patches against the pv-ops kernel?

Looking briefly at the Linux patches, you need to remove those #ifdef
LINUX_VERSION_CODE, make the EXPORT_SYMBOL be EXPORT_SYMBOL_GPL, and
also run the patch through scripts/checkpatch.pl
> Distribution: Ubuntu jaunty 9.04
> 
> There are some design issue which i would like to highlight here:
> 1. To create gcov proc dir user /proc/xen, we are explicitly exported
> xen_base symbol. I want to know your thoughts.
> 2. XEN_GCOV_PROC config is set as not selected. So someone has to be
> configured manually as M/Y
> 
> 
> Known Issues:
> File vmac.c throw some fault while using with lcov/gcov. This is due
> to some raw count copy between xen and kernel. I could not able to
> reproduce it many times, may be someone can try on 64 bit m/c.
> "My take on this is that zero length array element in gcov_info
> structure has to be copied separately between xen and kernel. How? I
> dont know."
> 
> I am still debugging this issue.
> 
> If you get fault and fail to proceed please apply the above patch in
> linux-wa-v1.patch in Linux 2.6.18.8 and recompile. This time vmac.gcda
> file wont appear in /proc/xen/gcov/crypto
> 
> 
> HOWTO Test using lcov
> 1.  install lcov from repo
>      # sudo apt-get install lcov
> 2. vi /etc/lcovrc
>     Change line: lcov_gcov_dir = /proc/gcov to lcov_gcov_dir = /proc/xen/gcov
> 3. # cd  /tmp; lcov -c -o kernel.info
> 4. # genhtml kernel.info
> 5, # firefox index.html
> 
> lcov README and screenshot is attached.

22% coverege, eh? Is that just by booting the Dom0 kernel?

> 
> HTH
> 
> Note:
> For any other detail required please CC me to parkash.tej@gmail.com

> diff -r 86d6c6417cf9 drivers/xen/Kconfig
> --- a/drivers/xen/Kconfig	Thu Feb 04 13:08:27 2010 +0000
> +++ b/drivers/xen/Kconfig	Sun Feb 07 00:13:40 2010 +0530
> @@ -311,6 +311,13 @@
>  	help
>  	  Xen hypervisor attributes will show up under /sys/hypervisor/.
>  
> +config XEN_GCOV_PROC
> +       tristate "Code covarage for hypervisor"
                          ^^^^^ - coverage

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Xen-devel] Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit)
  2010-05-10 14:53 ` [Xen-devel] " Konrad Rzeszutek Wilk
@ 2010-05-10 17:21   ` Tej
  2010-05-10 17:26   ` Tej
  1 sibling, 0 replies; 4+ messages in thread
From: Tej @ 2010-05-10 17:21 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: George Dunlap, xen-devel, xen-users, parkash.tej

On Mon, May 10, 2010 at 8:23 PM, Konrad Rzeszutek Wilk
<konrad.wilk@oracle.com> wrote:
> On Sat, May 08, 2010 at 01:31:01AM +0530, Tej wrote:
>> All,
>>
>> Here are the latest patches to expreiment with gcov profiler for xen
>> hypervisor. I have tested current patches on Intel i686.
>
> Nice..
>
>> System Details:
>> gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)
>> gcov (Ubuntu 4.3.3-5ubuntu4) 4.3.3
>> Kernel 2.6.28-11-generic
>
> Uhh? 2.6.28 or 2.6.18?

2.6.18.8

>
> I hate to tell you this but development is happening in the pv-ops
> kernel, not anymore in the XenLinux branches :-(
>
> Any chance you can rebase those patches against the pv-ops kernel?

rebasing wont to much problem,

>
> Looking briefly at the Linux patches, you need to remove those #ifdef
> LINUX_VERSION_CODE, make the EXPORT_SYMBOL be EXPORT_SYMBOL_GPL, and
> also run the patch through scripts/checkpatch.pl
>> Distribution: Ubuntu jaunty 9.04
>>
>> There are some design issue which i would like to highlight here:
>> 1. To create gcov proc dir user /proc/xen, we are explicitly exported
>> xen_base symbol. I want to know your thoughts.
>> 2. XEN_GCOV_PROC config is set as not selected. So someone has to be
>> configured manually as M/Y
>>
>>
>> Known Issues:
>> File vmac.c throw some fault while using with lcov/gcov. This is due
>> to some raw count copy between xen and kernel. I could not able to
>> reproduce it many times, may be someone can try on 64 bit m/c.
>> "My take on this is that zero length array element in gcov_info
>> structure has to be copied separately between xen and kernel. How? I
>> dont know."
>>
>> I am still debugging this issue.
>>
>> If you get fault and fail to proceed please apply the above patch in
>> linux-wa-v1.patch in Linux 2.6.18.8 and recompile. This time vmac.gcda
>> file wont appear in /proc/xen/gcov/crypto
>>
>>
>> HOWTO Test using lcov
>> 1.  install lcov from repo
>>      # sudo apt-get install lcov
>> 2. vi /etc/lcovrc
>>     Change line: lcov_gcov_dir = /proc/gcov to lcov_gcov_dir = /proc/xen/gcov
>> 3. # cd  /tmp; lcov -c -o kernel.info
>> 4. # genhtml kernel.info
>> 5, # firefox index.html
>>
>> lcov README and screenshot is attached.
>
> 22% coverege, eh? Is that just by booting the Dom0 kernel?
>
>>
>> HTH
>>
>> Note:
>> For any other detail required please CC me to parkash.tej@gmail.com
>
>> diff -r 86d6c6417cf9 drivers/xen/Kconfig
>> --- a/drivers/xen/Kconfig     Thu Feb 04 13:08:27 2010 +0000
>> +++ b/drivers/xen/Kconfig     Sun Feb 07 00:13:40 2010 +0530
>> @@ -311,6 +311,13 @@
>>       help
>>         Xen hypervisor attributes will show up under /sys/hypervisor/.
>>
>> +config XEN_GCOV_PROC
>> +       tristate "Code covarage for hypervisor"
>                          ^^^^^ - coverage
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Xen-devel] Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit)
  2010-05-10 14:53 ` [Xen-devel] " Konrad Rzeszutek Wilk
  2010-05-10 17:21   ` Tej
@ 2010-05-10 17:26   ` Tej
  1 sibling, 0 replies; 4+ messages in thread
From: Tej @ 2010-05-10 17:26 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: George Dunlap, xen-devel, xen-users, parkash.tej

On Mon, May 10, 2010 at 8:23 PM, Konrad Rzeszutek Wilk
<konrad.wilk@oracle.com> wrote:
> On Sat, May 08, 2010 at 01:31:01AM +0530, Tej wrote:
>> All,
>>
>> Here are the latest patches to expreiment with gcov profiler for xen
>> hypervisor. I have tested current patches on Intel i686.
>
> Nice..
>
>> System Details:
>> gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)
>> gcov (Ubuntu 4.3.3-5ubuntu4) 4.3.3
>> Kernel 2.6.28-11-generic
>
> Uhh? 2.6.28 or 2.6.18?
>
> I hate to tell you this but development is happening in the pv-ops
> kernel, not anymore in the XenLinux branches :-(
>
> Any chance you can rebase those patches against the pv-ops kernel?
>
> Looking briefly at the Linux patches, you need to remove those #ifdef
> LINUX_VERSION_CODE, make the EXPORT_SYMBOL be EXPORT_SYMBOL_GPL, and
> also run the patch through scripts/checkpatch.pl

Thanks for your review/suggestion, will do all and get back but may be
after 2 weeks as i am off from the work, (only mails)

>> Distribution: Ubuntu jaunty 9.04
>>
>> There are some design issue which i would like to highlight here:
>> 1. To create gcov proc dir user /proc/xen, we are explicitly exported
>> xen_base symbol. I want to know your thoughts.
>> 2. XEN_GCOV_PROC config is set as not selected. So someone has to be
>> configured manually as M/Y
>>
>>
>> Known Issues:
>> File vmac.c throw some fault while using with lcov/gcov. This is due
>> to some raw count copy between xen and kernel. I could not able to
>> reproduce it many times, may be someone can try on 64 bit m/c.
>> "My take on this is that zero length array element in gcov_info
>> structure has to be copied separately between xen and kernel. How? I
>> dont know."
>>
>> I am still debugging this issue.
>>
>> If you get fault and fail to proceed please apply the above patch in
>> linux-wa-v1.patch in Linux 2.6.18.8 and recompile. This time vmac.gcda
>> file wont appear in /proc/xen/gcov/crypto
>>
>>
>> HOWTO Test using lcov
>> 1.  install lcov from repo
>>      # sudo apt-get install lcov
>> 2. vi /etc/lcovrc
>>     Change line: lcov_gcov_dir = /proc/gcov to lcov_gcov_dir = /proc/xen/gcov
>> 3. # cd  /tmp; lcov -c -o kernel.info
>> 4. # genhtml kernel.info
>> 5, # firefox index.html
>>
>> lcov README and screenshot is attached.
>
> 22% coverege, eh? Is that just by booting the Dom0 kernel?

Yes, but any operation on Xen which will reach to hypervisor is going
to change this number, since boot.

>
>>
>> HTH
>>
>> Note:
>> For any other detail required please CC me to parkash.tej@gmail.com
>
>> diff -r 86d6c6417cf9 drivers/xen/Kconfig
>> --- a/drivers/xen/Kconfig     Thu Feb 04 13:08:27 2010 +0000
>> +++ b/drivers/xen/Kconfig     Sun Feb 07 00:13:40 2010 +0530
>> @@ -311,6 +311,13 @@
>>       help
>>         Xen hypervisor attributes will show up under /sys/hypervisor/.
>>
>> +config XEN_GCOV_PROC
>> +       tristate "Code covarage for hypervisor"
>                          ^^^^^ - coverage

oops!!!!!! thanks for spotting the typo

>

-Tej

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-05-10 17:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-07 20:01 Xen GCOV Patches for latest Xen Unbstable and linux 2.6.18.8 kernel(32/64bit) Tej
2010-05-10 14:53 ` [Xen-devel] " Konrad Rzeszutek Wilk
2010-05-10 17:21   ` Tej
2010-05-10 17:26   ` Tej

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).