diff mbox

[v3] xen: Implement hypercall for tracing of program counters

Message ID 20170811152534.3536-1-eggi.innovations@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Felix Schmoll Aug. 11, 2017, 3:25 p.m. UTC
This commit makes the changes to the hypervisor, the build system as
well as libxc necessary in order to facilitate tracing of program counters.

A discussion of the design can be found in the mailing list:
https://lists.xen.org/archives/html/xen-devel/2017-05/threads.html#02210

The list of files to be included for tracing might still be too extensive,
resulting in indeterministic tracing output for some use cases.

Signed-off-by: Felix Schmoll <eggi.innovations@gmail.com>

---
Changed since v2:
 * Fix bug that hypercall wouldn't return -EFAULT
 * Adjust error return codes of hypercall
 * Add description to Kconfig
 * Move compile-option from Kconfig to Kconfig.debug
 * Formatting changes

---
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: George Dunlap <George.Dunlap@eu.citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
CC: Stefano Stabellini <sstabellini@kernel.org>
CC: Tim Deegan <tim@xen.org>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Julien Grall <julien.grall@arm.com>
CC: xen-devel@lists.xen.org
---
 xen/Kconfig.debug             |  7 +++-
 xen/Rules.mk                  |  4 ++
 xen/arch/arm/traps.c          |  1 +
 xen/arch/x86/Makefile         |  2 +
 xen/arch/x86/hvm/hypercall.c  |  1 +
 xen/arch/x86/hypercall.c      |  1 +
 xen/arch/x86/pv/Makefile      |  2 +
 xen/arch/x86/pv/hypercall.c   |  1 +
 xen/common/Makefile           | 13 ++++++
 xen/common/domain.c           |  4 ++
 xen/common/trace_pc.c         | 96 +++++++++++++++++++++++++++++++++++++++++++
 xen/common/trace_pc_stub.c    | 39 ++++++++++++++++++
 xen/include/public/trace_pc.h | 38 +++++++++++++++++
 xen/include/public/xen.h      |  1 +
 xen/include/xen/hypercall.h   |  7 ++++
 xen/include/xen/sched.h       |  6 +++
 xen/include/xen/trace_pc.h    | 31 ++++++++++++++
 17 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 xen/common/trace_pc.c
 create mode 100644 xen/common/trace_pc_stub.c
 create mode 100644 xen/include/public/trace_pc.h
 create mode 100644 xen/include/xen/trace_pc.h

Comments

Wei Liu Aug. 16, 2017, 2:38 p.m. UTC | #1
On Fri, Aug 11, 2017 at 05:25:34PM +0200, Felix Schmoll wrote:
> This commit makes the changes to the hypervisor, the build system as
> well as libxc necessary in order to facilitate tracing of program counters.
> 
> A discussion of the design can be found in the mailing list:
> https://lists.xen.org/archives/html/xen-devel/2017-05/threads.html#02210
> 
> The list of files to be included for tracing might still be too extensive,
> resulting in indeterministic tracing output for some use cases.
> 
> Signed-off-by: Felix Schmoll <eggi.innovations@gmail.com>

There are some styling issues in code. I have queued this patch up to
one of my branches and will fix those up.

It will be properly upstreamed once I or someone else gets around to
make the build system up to our task.
Jan Beulich Sept. 1, 2017, 4:10 p.m. UTC | #2
>>> On 11.08.17 at 17:25, <eggi.innovations@gmail.com> wrote:
> This commit makes the changes to the hypervisor, the build system as
> well as libxc necessary in order to facilitate tracing of program counters.

There are no libxc changes here afaics.

> A discussion of the design can be found in the mailing list:
> https://lists.xen.org/archives/html/xen-devel/2017-05/threads.html#02210 
> 
> The list of files to be included for tracing might still be too extensive,
> resulting in indeterministic tracing output for some use cases.

Criteria for how files were chose to (not) be traced should be
stated here, or else no-one can tell whether the ones you picked
make sense. For example, I'm surprised you use a white listing
approach instead of a black listing one.

> --- a/xen/Rules.mk
> +++ b/xen/Rules.mk
> @@ -170,6 +170,10 @@ clean:: $(addprefix _clean_, $(subdir-all))
>  _clean_%/: FORCE
>  	$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
>  
> +ifeq ($(CONFIG_TRACE_PC),y)
> +$(objs-need-tracing): CFLAGS += -fsanitize-coverage=trace-pc
> +endif
> +
>  %.o: %.c Makefile
>  	$(CC) $(CFLAGS) -c $< -o $@

Please find a better place for this than in the middle of rules.

> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -55,6 +55,8 @@ obj-y += tasklet.o
>  obj-y += time.o
>  obj-y += timer.o
>  obj-y += trace.o
> +obj-y += trace_pc.o
> +obj-$(CONFIG_TRACE_PC) += trace_pc_stub.o

Looking at the sources for these, why do you need two files?
trace_pc.c has a CONFIG_TRACE_PC conditional anyway, so I
see nothing wrong with it gaining a second one.

> +long do_trace_pc(domid_t dom, int mode, unsigned int size,

No plain int-s please unless you really mean a signed quantity.

> +                 XEN_GUEST_HANDLE_PARAM(uint64_t) buf)
> +{
> +#ifdef CONFIG_TRACE_PC
> +    int ret = 0;
> +    struct domain *d;
> +
> +    if ( dom == DOMID_SELF )
> +        d = current->domain;
> +    else
> +        d = get_domain_by_id(dom);

Any reason not to use the common rcu_lock_domain_by_any_id()?

> +    if ( !d )
> +        return -ESRCH; /* invalid domain */
> +
> +    switch ( mode )
> +    {
> +    case XEN_TRACE_PC_START:
> +    {
> +        if ( d->tracing_buffer )
> +        {
> +            ret = -EBUSY; /* domain already being traced */
> +            break;
> +        }
> +
> +        d->tracing_buffer_pos = 0;
> +        d->tracing_buffer_size = size;
> +        d->tracing_buffer = xmalloc_array(uint64_t, size);

What about two simultaneous requests for the same domain?

> --- /dev/null
> +++ b/xen/include/xen/trace_pc.h
> @@ -0,0 +1,31 @@
> +/******************************************************************************
> + * trace_pc.h
> + *
> + * Declarations for the program counter tracing hypercall
> + *
> + * Copyright (C) 2017 Felix Schmoll <eggi.innovations@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms and conditions of the GNU General Public
> + * License, version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with this program; If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __TRACE_PC_H__
> +#define __TRACE_PC_H__
> +
> +#include <xen/sched.h>
> +#include <xen/types.h>
> +
> +#include <asm/current.h>
> +
> +void __sanitizer_cov_trace_pc(void);

Given this single declaration, what do you need the three includes
for?

Jan
diff mbox

Patch

diff --git a/xen/Kconfig.debug b/xen/Kconfig.debug
index 689f2974c0..d87dcd78f4 100644
--- a/xen/Kconfig.debug
+++ b/xen/Kconfig.debug
@@ -98,7 +98,6 @@  config PERF_ARRAYS
 	---help---
 	  Enables software performance counter array histograms.
 
-
 config VERBOSE_DEBUG
 	bool "Verbose debug messages"
 	default DEBUG
@@ -114,6 +113,12 @@  config DEVICE_TREE_DEBUG
 	  logged in the Xen ring buffer.
 	  If unsure, say N here.
 
+config TRACE_PC
+    bool "Enable pc-tracing"
+    default false
+    ---help---
+	  Adds tracing support to the hypervisor (needed for the trace_pc hypercall).
+
 endif # DEBUG || EXPERT
 
 endmenu
diff --git a/xen/Rules.mk b/xen/Rules.mk
index 77bcd44922..dde14e3228 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -170,6 +170,10 @@  clean:: $(addprefix _clean_, $(subdir-all))
 _clean_%/: FORCE
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
 
+ifeq ($(CONFIG_TRACE_PC),y)
+$(objs-need-tracing): CFLAGS += -fsanitize-coverage=trace-pc
+endif
+
 %.o: %.c Makefile
 	$(CC) $(CFLAGS) -c $< -o $@
 
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index c07999b518..247a68c964 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1419,6 +1419,7 @@  static arm_hypercall_t arm_hypercall_table[] = {
     HYPERCALL(platform_op, 1),
     HYPERCALL_ARM(vcpu_op, 3),
     HYPERCALL(vm_assist, 2),
+    HYPERCALL(trace_pc, 4),
 };
 
 #ifndef NDEBUG
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 93ead6e5dd..b283c3e22c 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -74,6 +74,8 @@  efi-y := $(shell if [ ! -r $(BASEDIR)/include/xen/compile.h -o \
                       -O $(BASEDIR)/include/xen/compile.h ]; then \
                          echo '$(TARGET).efi'; fi)
 
+objs-need-tracing := cpuid.o hypercall.o
+
 ifneq ($(build_id_linker),)
 notes_phdrs = --notes
 else
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce293..b59d7d481e 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -132,6 +132,7 @@  static const hypercall_table_t hvm_hypercall_table[] = {
     COMPAT_CALL(mmuext_op),
     HYPERCALL(xenpmu_op),
     COMPAT_CALL(dm_op),
+    HYPERCALL(trace_pc),
     HYPERCALL(arch_1)
 };
 
diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c
index e30181817a..672ffe7ef5 100644
--- a/xen/arch/x86/hypercall.c
+++ b/xen/arch/x86/hypercall.c
@@ -68,6 +68,7 @@  const hypercall_args_t hypercall_args_table[NR_hypercalls] =
     ARGS(xenpmu_op, 2),
     ARGS(dm_op, 3),
     ARGS(mca, 1),
+    ARGS(trace_pc, 4),
     ARGS(arch_1, 1),
 };
 
diff --git a/xen/arch/x86/pv/Makefile b/xen/arch/x86/pv/Makefile
index 4e15484471..8c3eccdfd7 100644
--- a/xen/arch/x86/pv/Makefile
+++ b/xen/arch/x86/pv/Makefile
@@ -11,3 +11,5 @@  obj-y += traps.o
 
 obj-bin-y += dom0_build.init.o
 obj-bin-y += gpr_switch.o
+
+objs-need-tracing += hypercall.o
diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c
index f79f7eef62..13eb2e86a2 100644
--- a/xen/arch/x86/pv/hypercall.c
+++ b/xen/arch/x86/pv/hypercall.c
@@ -80,6 +80,7 @@  static const hypercall_table_t pv_hypercall_table[] = {
     HYPERCALL(xenpmu_op),
     COMPAT_CALL(dm_op),
     HYPERCALL(mca),
+    HYPERCALL(trace_pc),
     HYPERCALL(arch_1),
 };
 
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 26c5a64337..4e39dc66e0 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -55,6 +55,8 @@  obj-y += tasklet.o
 obj-y += time.o
 obj-y += timer.o
 obj-y += trace.o
+obj-y += trace_pc.o
+obj-$(CONFIG_TRACE_PC) += trace_pc_stub.o
 obj-y += version.o
 obj-y += virtual_region.o
 obj-y += vm_event.o
@@ -80,3 +82,14 @@  subdir-$(CONFIG_GCOV) += gcov
 
 subdir-y += libelf
 subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
+
+objs-need-tracing := bsearch.o \
+    decompress.o device_tree.o domain.o domctl.o earlycpio.o grant_table.o \
+    guestcopy.o gunzip.o inflate.o kernel.o kexec.o keyhandler.o kimage.o \
+    lib.o livepatch.o lzo.o mem_access.o memory.o multicall.o notifier.o \
+    page_alloc.o pdx.o perfc.o radix_tree.o rangeset.o \
+    rbtree.o shutdown.o sort.o stop_machine.o \
+    symbols.o symbols-dummy.o sysctl.o time.o tmem.o \
+    tmem_control.o tmem_xen.o trace.o unlz4.o unlzo.o unxz.o version.o \
+    virtual_region.o vmap.o vm_event.o warning.o xenoprof.o \
+    xmalloc_tlsf.o
diff --git a/xen/common/domain.c b/xen/common/domain.c
index b22aacc57e..c98a0a94ec 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -874,6 +874,10 @@  void domain_destroy(struct domain *d)
     rcu_assign_pointer(*pd, d->next_in_hashbucket);
     spin_unlock(&domlist_update_lock);
 
+#ifdef CONFIG_TRACE_PC
+    xfree(d->tracing_buffer);
+#endif
+
     /* Schedule RCU asynchronous completion of domain destroy. */
     call_rcu(&d->rcu, complete_domain_destroy);
 }
diff --git a/xen/common/trace_pc.c b/xen/common/trace_pc.c
new file mode 100644
index 0000000000..722572c500
--- /dev/null
+++ b/xen/common/trace_pc.c
@@ -0,0 +1,96 @@ 
+/******************************************************************************
+ * trace_pc.c
+ *
+ * Implementation of the program counter tracing hypercall.
+ *
+ * Copyright (c) 2017 Felix Schmoll <eggi.innovations@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <xen/xmalloc.h>
+#include <public/trace_pc.h>
+
+long do_trace_pc(domid_t dom, int mode, unsigned int size,
+                 XEN_GUEST_HANDLE_PARAM(uint64_t) buf)
+{
+#ifdef CONFIG_TRACE_PC
+    int ret = 0;
+    struct domain *d;
+
+    if ( dom == DOMID_SELF )
+        d = current->domain;
+    else
+        d = get_domain_by_id(dom);
+
+    if ( !d )
+        return -ESRCH; /* invalid domain */
+
+    switch ( mode )
+    {
+    case XEN_TRACE_PC_START:
+    {
+        if ( d->tracing_buffer )
+        {
+            ret = -EBUSY; /* domain already being traced */
+            break;
+        }
+
+        d->tracing_buffer_pos = 0;
+        d->tracing_buffer_size = size;
+        d->tracing_buffer = xmalloc_array(uint64_t, size);
+
+        if ( !d->tracing_buffer )
+            ret = -ENOMEM;
+        break;
+    }
+
+    case XEN_TRACE_PC_STOP:
+    {
+        uint64_t *temp = d->tracing_buffer;
+        d->tracing_buffer = NULL;
+
+        if ( copy_to_guest(buf, temp, d->tracing_buffer_pos) )
+            ret = -EFAULT;
+        else
+            ret = d->tracing_buffer_pos;
+
+        xfree(temp);
+
+        break;
+    }
+
+    default:
+        ret = -ENOSYS;
+    }
+
+    if ( dom != DOMID_SELF )
+        put_domain(d);
+
+    return ret;
+#else
+    return -EOPNOTSUPP;
+#endif
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/trace_pc_stub.c b/xen/common/trace_pc_stub.c
new file mode 100644
index 0000000000..4aba7dba9f
--- /dev/null
+++ b/xen/common/trace_pc_stub.c
@@ -0,0 +1,39 @@ 
+/******************************************************************************
+ * trace_pc_stub.c
+ *
+ * Edge function/stub for the program counter tracing hypercall.
+ *
+ * Copyright (c) 2017 Felix Schmoll <eggi.innovations@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/trace_pc.h>
+#include <xen/kernel.h>
+
+void __sanitizer_cov_trace_pc(void)
+{
+    struct domain *d;
+
+    if ( system_state < SYS_STATE_active )
+        return;
+
+    d = current->domain;
+
+    if ( d->tracing_buffer &&
+        (d->tracing_buffer_pos < d->tracing_buffer_size) )
+    {
+        d->tracing_buffer[d->tracing_buffer_pos++] =
+            (uint64_t) __builtin_return_address(0);
+    }
+}
diff --git a/xen/include/public/trace_pc.h b/xen/include/public/trace_pc.h
new file mode 100644
index 0000000000..54e430a561
--- /dev/null
+++ b/xen/include/public/trace_pc.h
@@ -0,0 +1,38 @@ 
+/******************************************************************************
+ * trace_pc.h
+ *
+ * Macros for program counter tracing hypercall.
+ *
+ * Copyright (C) 2017 Felix Schmoll <eggi.innovations@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef __XEN_PUBLIC_TRACE_PC_H__
+#define __XEN_PUBLIC_TRACE_PC_H__
+
+#if defined(__XEN__) || defined(__XEN_TOOLS__)
+
+#define XEN_TRACE_PC_START 0
+#define XEN_TRACE_PC_STOP 1
+
+#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
+
+#endif /* __XEN_PUBLIC_TRACE_PC_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 2ac6b1e24d..95d83c21ce 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -121,6 +121,7 @@  DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
 #define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
 #define __HYPERVISOR_xenpmu_op            40
 #define __HYPERVISOR_dm_op                41
+#define __HYPERVISOR_trace_pc             42
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h
index cc99aea57d..aa6269e7b7 100644
--- a/xen/include/xen/hypercall.h
+++ b/xen/include/xen/hypercall.h
@@ -83,6 +83,13 @@  do_xen_version(
     XEN_GUEST_HANDLE_PARAM(void) arg);
 
 extern long
+do_trace_pc(
+    domid_t dom_id,
+    int mode,
+    unsigned int size,
+    XEN_GUEST_HANDLE_PARAM(uint64_t) buf);
+
+extern long
 do_console_io(
     int cmd,
     int count,
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 6673b27d88..4bd3fe2417 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -483,6 +483,12 @@  struct domain
         unsigned int guest_request_enabled       : 1;
         unsigned int guest_request_sync          : 1;
     } monitor;
+
+#ifdef CONFIG_TRACE_PC
+    uint64_t* tracing_buffer;
+    unsigned int tracing_buffer_pos;
+    unsigned int tracing_buffer_size;
+#endif
 };
 
 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
diff --git a/xen/include/xen/trace_pc.h b/xen/include/xen/trace_pc.h
new file mode 100644
index 0000000000..631815de30
--- /dev/null
+++ b/xen/include/xen/trace_pc.h
@@ -0,0 +1,31 @@ 
+/******************************************************************************
+ * trace_pc.h
+ *
+ * Declarations for the program counter tracing hypercall
+ *
+ * Copyright (C) 2017 Felix Schmoll <eggi.innovations@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TRACE_PC_H__
+#define __TRACE_PC_H__
+
+#include <xen/sched.h>
+#include <xen/types.h>
+
+#include <asm/current.h>
+
+void __sanitizer_cov_trace_pc(void);
+
+#endif /* __TRACE_PC_H__ */