--- /dev/null
+#
+# Makefile for LTT New generation user interface : plugins.
+#
+# Created by Mathieu Desnoyers on May 6, 2003
+#
+
+SUBDIRS = convert
+
+libdir = ${lttlibdir}
+
+AM_CFLAGS = $(GLIB_CFLAGS)
+LIBS += $(GLIB_LIBS)
+
+lib_LTLIBRARIES = libtraceread.la
+libtraceread_la_SOURCES = event.c facility.c parser.c tracefile.c type.c
+noinst_HEADERS = parser.h ltt-private.h
+
+lttinclude_HEADERS = \
+ compiler.h\
+ event.h\
+ facility.h\
+ ltt.h\
+ time.h\
+ trace.h\
+ type.h\
+ ltt-types.h
+
+EXTRA_DIST = crc32.tab
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Mathieu Desnoyers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef COMPILER_H
+#define COMPILER_H
+
+/* Fast prediction if likely branches */
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#endif //COMPILER_H
--- /dev/null
+/*
+ * LTTTypes.h
+ *
+ * Copyright (C) 2000 Karim Yaghmour (karym@opersys.com).
+ *
+ * This is distributed under GPL.
+ *
+ * Header for LTT-secific types.
+ *
+ * History :
+ * K.Y. 07/09/2001, Added David Schleef's architecture independent ltt_set_bit/ltt_clear_bit/ltt_test_bit
+ * JAL, 05/01/2001, Modified PPC bit manipulation functions for x86 compatibility.
+ * (andy_lowe@mvista.com)
+ * K.Y., 31/05/2000, Initial typing.
+ */
+
+#ifndef __TRACE_TOOLKIT_TYPES_HEADER__
+#define __TRACE_TOOLKIT_TYPES_HEADER__
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#if defined(sun)
+
+typedef unsigned char u_int8_t;
+typedef unsigned short u_int16_t;
+typedef unsigned int u_int32_t;
+#ifdef _LP64
+typedef unsigned long u_int64_t;
+#else /* _ILP32 */
+#if __STDC__ - 0 == 0 && !defined(_NO_LONGLONG)
+typedef unsigned long long u_int64_t;
+#endif /* __STDC__ - 0 == 0 && !defined(_NO_LONGLONG) */
+#endif /* _LP64 */
+
+#endif /* defined(sun) */
+
+extern __inline__ int ltt_set_bit(int nr, void * addr)
+{
+ unsigned char *p = addr;
+ unsigned char mask = 1 << (nr&7);
+ unsigned char old;
+
+ p += nr>>3;
+ old = *p;
+ *p |= mask;
+
+ return ((old & mask) != 0);
+}
+
+extern __inline__ int ltt_clear_bit(int nr, void * addr)
+{
+ unsigned char *p = addr;
+ unsigned char mask = 1 << (nr&7);
+ unsigned char old;
+
+ p += nr>>3;
+ old = *p;
+ *p &= ~mask;
+
+ return ((old & mask) != 0);
+}
+
+extern __inline__ int ltt_test_bit(int nr,void *addr)
+{
+ unsigned char *p = addr;
+ unsigned char mask = 1 << (nr&7);
+
+ p += nr>>3;
+
+ return ((*p & mask) != 0);
+}
+
+/* Big-endian/little-endian conversion macros for cross-development. */
+#if TARGET_NATIVE
+/* For native development, these conversion macros aren't needed. */
+#define BREV16(x) (x)
+#define BREV32(x) (x)
+#define BREV64(x) (x)
+#define RFT8(db,x) (x)
+#define RFT16(db,x) (x)
+#define RFT32(db,x) (x)
+#define RFT64(db,x) (x)
+
+/* Non-native development */
+#else
+ /* BREV16: byte-reverse a 16-bit integer */
+#define BREV16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
+ /* BREV32: byte-reverse a 32-bit integer */
+#define BREV32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \
+ | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
+ /* BREV64: byte-reverse a 64-bit integer */
+#define BREV64(x) ((((x) & 0xff00000000000000) >> 56) \
+ | (((x) & 0x00ff000000000000) >> 40) \
+ | (((x) & 0x0000ff0000000000) >> 24) \
+ | (((x) & 0x000000ff00000000) >> 8) \
+ | (((x) & 0x00000000ff000000) << 8) \
+ | (((x) & 0x0000000000ff0000) << 24) \
+ | (((x) & 0x000000000000ff00) << 40) \
+ | (((x) & 0x00000000000000ff) << 56))
+ /* RFTn: Read From Trace
+ * Conditionally byte-reverse an 8-, 16-, 32-, or 64-bit integer
+ * based on the value of the ByteRev member of the trace database
+ * structure pointer passed as the first argument..
+ */
+#define RFT8(db,x) (x)
+#define RFT16(db,x) ((db)->ByteRev ? BREV16(x) : (x))
+#define RFT32(db,x) ((db)->ByteRev ? BREV32(x) : (x))
+#define RFT64(db,x) ((db)->ByteRev ? BREV64(x) : (x))
+#endif /* TRACE_TARGET_NATIVE */
+
+#if !defined(sun)
+/* Some type corrections, just in case */
+#ifndef uint8_t
+#define uint8_t u_int8_t
+#endif
+#ifndef uint16_t
+#define uint16_t u_int16_t
+#endif
+#ifndef uint32_t
+#define uint32_t u_int32_t
+#endif
+#ifndef uint64_t
+#define uint64_t u_int64_t
+#endif
+#endif /* !defined(sun) */
+
+/* Structure packing */
+#if LTT_UNPACKED_STRUCTS
+#define LTT_PACKED_STRUCT
+#else
+#define LTT_PACKED_STRUCT __attribute__ ((packed))
+#endif /* UNPACKED_STRUCTS */
+
+/* Trace mask */
+typedef uint64_t trace_event_mask;
+
+/* Boolean stuff */
+//#define TRUE 1
+//#define FALSE 0
+
+#endif /* __TRACE_TOOLKIT_TYPES_HEADER__ */
--- /dev/null
+/*
+ * LinuxEvents.h
+ *
+ * Copyright (C) 2000, 2001, 2002 Karim Yaghmour (karym@opersys.com).
+ *
+ * This header is distributed under GPL.
+ *
+ * Linux events being traced.
+ *
+ * History :
+ * K.Y., 31/05/1999, Initial typing.
+ *
+ */
+
+#ifndef __TRACE_TOOLKIT_LINUX_HEADER__
+#define __TRACE_TOOLKIT_LINUX_HEADER__
+
+#include "LTTTypes.h"
+
+/* Traced events */
+#define TRACE_START 0 /* This is to mark the trace's start */
+#define TRACE_SYSCALL_ENTRY 1 /* Entry in a given system call */
+#define TRACE_SYSCALL_EXIT 2 /* Exit from a given system call */
+#define TRACE_TRAP_ENTRY 3 /* Entry in a trap */
+#define TRACE_TRAP_EXIT 4 /* Exit from a trap */
+#define TRACE_IRQ_ENTRY 5 /* Entry in an irq */
+#define TRACE_IRQ_EXIT 6 /* Exit from an irq */
+#define TRACE_SCHEDCHANGE 7 /* Scheduling change */
+#define TRACE_KERNEL_TIMER 8 /* The kernel timer routine has been called */
+#define TRACE_SOFT_IRQ 9 /* Hit key part of soft-irq management */
+#define TRACE_PROCESS 10 /* Hit key part of process management */
+#define TRACE_FILE_SYSTEM 11 /* Hit key part of file system */
+#define TRACE_TIMER 12 /* Hit key part of timer management */
+#define TRACE_MEMORY 13 /* Hit key part of memory management */
+#define TRACE_SOCKET 14 /* Hit key part of socket communication */
+#define TRACE_IPC 15 /* Hit key part of inter-process communication */
+#define TRACE_NETWORK 16 /* Hit key part of network communication */
+
+#define TRACE_BUFFER_START 17 /* Mark the begining of a trace buffer */
+#define TRACE_BUFFER_END 18 /* Mark the ending of a trace buffer */
+#define TRACE_NEW_EVENT 19 /* New event type */
+#define TRACE_CUSTOM 20 /* Custom event */
+
+#define TRACE_CHANGE_MASK 21 /* Change in event mask */
+#define TRACE_HEARTBEAT 22 /* Heartbeat event */
+
+/* Number of traced events */
+#define TRACE_MAX TRACE_HEARTBEAT
+
+/* Architecture types */
+#define TRACE_ARCH_TYPE_I386 1 /* i386 system */
+#define TRACE_ARCH_TYPE_PPC 2 /* PPC system */
+#define TRACE_ARCH_TYPE_SH 3 /* SH system */
+#define TRACE_ARCH_TYPE_S390 4 /* S/390 system */
+#define TRACE_ARCH_TYPE_MIPS 5 /* MIPS system */
+#define TRACE_ARCH_TYPE_ARM 6 /* ARM system */
+
+/* Standard definitions for variants */
+#define TRACE_ARCH_VARIANT_NONE 0 /* Main architecture implementation */
+
+/* PowerPC variants */
+#define TRACE_ARCH_VARIANT_PPC_4xx 1 /* 4xx systems (IBM embedded series) */
+#define TRACE_ARCH_VARIANT_PPC_6xx 2 /* 6xx/7xx/74xx/8260/POWER3 systems (desktop flavor) */
+#define TRACE_ARCH_VARIANT_PPC_8xx 3 /* 8xx system (Motoral embedded series) */
+#define TRACE_ARCH_VARIANT_PPC_ISERIES 4 /* 8xx system (iSeries) */
+
+/* System types */
+#define TRACE_SYS_TYPE_VANILLA_LINUX 1 /* Vanilla linux kernel */
+#define TRACE_SYS_TYPE_RTAI_LINUX 2 /* RTAI patched linux kernel */
+
+/* The information logged when the tracing is started */
+#define TRACER_MAGIC_NUMBER 0x00D6B7ED /* That day marks an important historical event ... */
+#define TRACER_SUP_VERSION_MAJOR 2 /* Major version number */
+
+/* Minimum information contained in any trace start event */
+typedef struct _trace_start_any
+{
+ uint32_t MagicNumber; /* Magic number to identify a trace */
+ uint32_t ArchType; /* Type of architecture */
+ uint32_t ArchVariant; /* Variant of the given type of architecture */
+ uint32_t SystemType; /* Operating system type */
+ uint8_t MajorVersion; /* Major version of trace */
+ uint8_t MinorVersion; /* Minor version of trace */
+
+} LTT_PACKED_STRUCT trace_start_any;
+
+typedef struct _trace_start_2_2
+{
+ uint32_t MagicNumber; /* Magic number to identify a trace */
+ uint32_t ArchType; /* Type of architecture */
+ uint32_t ArchVariant; /* Variant of the given type of architecture */
+ uint32_t SystemType; /* Operating system type */
+ uint8_t MajorVersion; /* Major version of trace */
+ uint8_t MinorVersion; /* Minor version of trace */
+
+ uint32_t BufferSize; /* Size of buffers */
+ trace_event_mask EventMask; /* The event mask */
+ trace_event_mask DetailsMask; /* Are the event details logged */
+ uint8_t LogCPUID; /* Is the CPUID logged */
+ uint8_t UseTSC; /* Are we using TSCs or time deltas */
+
+} LTT_PACKED_STRUCT trace_start_2_2;
+
+typedef struct _trace_start_2_3
+{
+ uint32_t MagicNumber; /* Magic number to identify a trace */
+ uint32_t ArchType; /* Type of architecture */
+ uint32_t ArchVariant; /* Variant of the given type of architecture */
+ uint32_t SystemType; /* Operating system type */
+ uint8_t MajorVersion; /* Major version of trace */
+ uint8_t MinorVersion; /* Minor version of trace */
+
+ uint32_t BufferSize; /* Size of buffers */
+ trace_event_mask EventMask; /* The event mask */
+ trace_event_mask DetailsMask; /* Are the event details logged */
+ uint8_t LogCPUID; /* Is the CPUID logged */
+ uint8_t UseTSC; /* Are we using TSCs or time deltas */
+
+ uint8_t FlightRecorder; /* Is this a flight recorder trace ? */
+} LTT_PACKED_STRUCT trace_start_2_3;
+
+/* TRACE_SYSCALL_ENTRY */
+typedef struct _trace_syscall_entry
+{
+ uint8_t syscall_id; /* Syscall entry number in entry.S */
+ uint32_t address; /* Address from which call was made */
+} LTT_PACKED_STRUCT trace_syscall_entry;
+#define SYSCALL_EVENT(X) ((trace_syscall_entry*)X)
+
+/* TRACE_TRAP_ENTRY */
+typedef struct _trace_trap_entry
+{
+ uint16_t trap_id; /* Trap number */
+ uint32_t address; /* Address where trap occured */
+} LTT_PACKED_STRUCT trace_trap_entry;
+typedef struct _trace_trap_entry_s390
+{
+ uint64_t trap_id; /* Trap number */
+ uint32_t address; /* Address where trap occured */
+} LTT_PACKED_STRUCT trace_trap_entry_s390;
+#define TRAP_EVENT(X) ((trace_trap_entry*)X)
+#define TRAP_EVENT_S390(X) ((trace_trap_entry_s390*)X)
+
+/* TRACE_IRQ_ENTRY */
+typedef struct _trace_irq_entry
+{
+ uint8_t irq_id; /* IRQ number */
+ uint8_t kernel; /* Are we executing kernel code */
+} LTT_PACKED_STRUCT trace_irq_entry;
+#define IRQ_EVENT(X) ((trace_irq_entry*)X)
+
+/* TRACE_SCHEDCHANGE */
+typedef struct _trace_schedchange
+{
+ uint32_t out; /* Outgoing process */
+ uint32_t in; /* Incoming process */
+ uint32_t out_state; /* Outgoing process' state */
+} LTT_PACKED_STRUCT trace_schedchange;
+#define SCHED_EVENT(X) ((trace_schedchange*)X)
+
+/* TRACE_SOFT_IRQ */
+#define TRACE_SOFT_IRQ_BOTTOM_HALF 1 /* Conventional bottom-half */
+#define TRACE_SOFT_IRQ_SOFT_IRQ 2 /* Real soft-irq */
+#define TRACE_SOFT_IRQ_TASKLET_ACTION 3 /* Tasklet action */
+#define TRACE_SOFT_IRQ_TASKLET_HI_ACTION 4 /* Tasklet hi-action */
+typedef struct _trace_soft_irq
+{
+ uint8_t event_sub_id; /* Soft-irq event Id */
+ uint32_t event_data; /* Data associated with event */
+} LTT_PACKED_STRUCT trace_soft_irq;
+#define SOFT_IRQ_EVENT(X) ((trace_soft_irq*)X)
+
+/* TRACE_PROCESS */
+#define TRACE_PROCESS_KTHREAD 1 /* Creation of a kernel thread */
+#define TRACE_PROCESS_FORK 2 /* A fork or clone occured */
+#define TRACE_PROCESS_EXIT 3 /* An exit occured */
+#define TRACE_PROCESS_WAIT 4 /* A wait occured */
+#define TRACE_PROCESS_SIGNAL 5 /* A signal has been sent */
+#define TRACE_PROCESS_WAKEUP 6 /* Wake up a process */
+#define TRACE_PROCESS_RELEASE 7 /* A task struct has been released */
+
+typedef struct _trace_process
+{
+ uint8_t event_sub_id; /* Process event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2;
+} LTT_PACKED_STRUCT trace_process;
+#define PROC_EVENT(X) ((trace_process*)X)
+
+/* TRACE_FILE_SYSTEM */
+#define TRACE_FILE_SYSTEM_BUF_WAIT_START 1 /* Starting to wait for a data buffer */
+#define TRACE_FILE_SYSTEM_BUF_WAIT_END 2 /* End to wait for a data buffer */
+#define TRACE_FILE_SYSTEM_EXEC 3 /* An exec occured */
+#define TRACE_FILE_SYSTEM_OPEN 4 /* An open occured */
+#define TRACE_FILE_SYSTEM_CLOSE 5 /* A close occured */
+#define TRACE_FILE_SYSTEM_READ 6 /* A read occured */
+#define TRACE_FILE_SYSTEM_WRITE 7 /* A write occured */
+#define TRACE_FILE_SYSTEM_SEEK 8 /* A seek occured */
+#define TRACE_FILE_SYSTEM_IOCTL 9 /* An ioctl occured */
+#define TRACE_FILE_SYSTEM_SELECT 10 /* A select occured */
+#define TRACE_FILE_SYSTEM_POLL 11 /* A poll occured */
+typedef struct _trace_file_system
+{
+ uint8_t event_sub_id; /* File system event ID */
+ uint32_t event_data1; /* Event data */
+ uint32_t event_data2; /* Event data 2 */
+ char* file_name; /* Name of file operated on */
+} LTT_PACKED_STRUCT trace_file_system;
+#define FS_EVENT(X) ((trace_file_system*)X)
+#define FS_EVENT_FILENAME(X) ((char*) ((X) + sizeof(trace_file_system)))
+
+/* TRACE_TIMER */
+#define TRACE_TIMER_EXPIRED 1 /* Timer expired */
+#define TRACE_TIMER_SETITIMER 2 /* Setting itimer occurred */
+#define TRACE_TIMER_SETTIMEOUT 3 /* Setting sched timeout occurred */
+typedef struct _trace_timer
+{
+ uint8_t event_sub_id; /* Timer event ID */
+ uint8_t event_sdata; /* Short data */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2;
+} LTT_PACKED_STRUCT trace_timer;
+#define TIMER_EVENT(X) ((trace_timer*)X)
+
+/* TRACE_MEMORY */
+#define TRACE_MEMORY_PAGE_ALLOC 1 /* Allocating pages */
+#define TRACE_MEMORY_PAGE_FREE 2 /* Freing pages */
+#define TRACE_MEMORY_SWAP_IN 3 /* Swaping pages in */
+#define TRACE_MEMORY_SWAP_OUT 4 /* Swaping pages out */
+#define TRACE_MEMORY_PAGE_WAIT_START 5 /* Start to wait for page */
+#define TRACE_MEMORY_PAGE_WAIT_END 6 /* End to wait for page */
+typedef struct _trace_memory
+{
+ uint8_t event_sub_id; /* Memory event ID */
+ unsigned long event_data; /* Data associated with event */
+} LTT_PACKED_STRUCT trace_memory;
+#define MEM_EVENT(X) ((trace_memory*)X)
+
+/* TRACE_SOCKET */
+#define TRACE_SOCKET_CALL 1 /* A socket call occured */
+#define TRACE_SOCKET_CREATE 2 /* A socket has been created */
+#define TRACE_SOCKET_SEND 3 /* Data was sent to a socket */
+#define TRACE_SOCKET_RECEIVE 4 /* Data was read from a socket */
+typedef struct _trace_socket
+{
+ uint8_t event_sub_id; /* Socket event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2; /* Data associated with event */
+} LTT_PACKED_STRUCT trace_socket;
+#define SOCKET_EVENT(X) ((trace_socket*)X)
+
+/* TRACE_IPC */
+#define TRACE_IPC_CALL 1 /* A System V IPC call occured */
+#define TRACE_IPC_MSG_CREATE 2 /* A message queue has been created */
+#define TRACE_IPC_SEM_CREATE 3 /* A semaphore was created */
+#define TRACE_IPC_SHM_CREATE 4 /* A shared memory segment has been created */
+typedef struct _trace_ipc
+{
+ uint8_t event_sub_id; /* IPC event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2; /* Data associated with event */
+} LTT_PACKED_STRUCT trace_ipc;
+#define IPC_EVENT(X) ((trace_ipc*)X)
+
+/* TRACE_NETWORK */
+#define TRACE_NETWORK_PACKET_IN 1 /* A packet came in */
+#define TRACE_NETWORK_PACKET_OUT 2 /* A packet was sent */
+typedef struct _trace_network
+{
+ uint8_t event_sub_id; /* Network event ID */
+ uint32_t event_data; /* Event data */
+} LTT_PACKED_STRUCT trace_network;
+#define NET_EVENT(X) ((trace_network*)X)
+
+/* Start of trace buffer information */
+typedef struct _trace_buffer_start
+{
+ struct timeval Time; /* Time stamp of this buffer */
+ uint32_t TSC; /* TSC of this buffer, if applicable */
+ uint32_t ID; /* Unique buffer ID */
+} LTT_PACKED_STRUCT trace_buffer_start;
+
+/* End of trace buffer information */
+typedef struct _trace_buffer_end
+{
+ struct timeval Time; /* Time stamp of this buffer */
+ uint32_t TSC; /* TSC of this buffer, if applicable */
+} LTT_PACKED_STRUCT trace_buffer_end;
+
+/* Maximal size a custom event can have */
+#define CUSTOM_EVENT_MAX_SIZE 8192
+
+/* String length limits for custom events creation */
+#define CUSTOM_EVENT_TYPE_STR_LEN 20
+#define CUSTOM_EVENT_DESC_STR_LEN 100
+#define CUSTOM_EVENT_FORM_STR_LEN 256
+
+/* Type of custom event formats */
+#define CUSTOM_EVENT_FORMAT_TYPE_NONE 0
+#define CUSTOM_EVENT_FORMAT_TYPE_STR 1
+#define CUSTOM_EVENT_FORMAT_TYPE_HEX 2
+#define CUSTOM_EVENT_FORMAT_TYPE_XML 3
+#define CUSTOM_EVENT_FORMAT_TYPE_IBM 4
+
+typedef struct _trace_new_event
+{
+ /* Basics */
+ uint32_t id; /* Custom event ID */
+ char type[CUSTOM_EVENT_TYPE_STR_LEN]; /* Event type description */
+ char desc[CUSTOM_EVENT_DESC_STR_LEN]; /* Detailed event description */
+
+ /* Custom formatting */
+ uint32_t format_type; /* Type of formatting */
+ char form[CUSTOM_EVENT_FORM_STR_LEN]; /* Data specific to format */
+} LTT_PACKED_STRUCT trace_new_event;
+#define NEW_EVENT(X) ((trace_new_event*) X)
+
+typedef struct _trace_custom
+{
+ uint32_t id; /* Event ID */
+ uint32_t data_size; /* Size of data recorded by event */
+ void* data; /* Data recorded by event */
+} LTT_PACKED_STRUCT trace_custom;
+#define CUSTOM_EVENT(X) ((trace_custom*) X)
+
+/* TRACE_CHANGE_MASK */
+typedef struct _trace_change_mask
+{
+ trace_event_mask mask; /* Event mask */
+} LTT_PACKED_STRUCT trace_change_mask;
+#define CHMASK_EVENT(X) ((trace_change_mask*) X)
+
+#endif /* __TRACE_TOOLKIT_LINUX_HEADER__ */
--- /dev/null
+AM_CFLAGS = $(GLIB_CFLAGS)
+LIBS += $(GLIB_LIBS) $(M_LIBS)
+
+bin_PROGRAMS = convert
+
+convert_SOURCES = convert.c
+
+noinst_HEADERS = LTTTypes.h LinuxEvents.h
+
+EXTRA_DIST = core.xml sysInfo README
+convertdir = $(pkgdatadir)/convert
+convert_DATA = core.xml sysInfo README
--- /dev/null
+The application 'convert' is used to convert an old format tracefile into a new
+format tracefile. It has several commandline parameters, the first is process file
+name, the second is a number (the number of cpu in the machine), the third is
+the first tracefile name(corresponding to the first cpu), the fourth is the
+second tracefile name(corresponding to the second cpu), the fifth is ...,
+the last one is root directory for the new trace (this can be omitted,
+by default it is 'foo')
+
+The command line looks like this:
+ ./convert processfile_name the_number_of_cpu first_tracefile_name, ..., foo_dir
+
+There is also a script file 'sysInfo' which is used to get system information
+from your local machine, the information is saved in 'sysInfo.out' which will
+be read by 'convert' later. If the old tracefile is generated by other machine,
+then the 'sysInfo.out' should be gotten from that machine.
+
+'core.xml' is a facility file, after run 'convert', it needs to be copied to
+'foo_dir/eventdefs' directory
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include "LTTTypes.h"
+#include "LinuxEvents.h"
+
+#define TRACE_HEARTBEAT_ID 19
+#define PROCESS_FORK_ID 20
+#define PROCESS_EXIT_ID 21
+
+#define INFO_ENTRY 9
+#define OVERFLOW_FIGURE 0x100000000ULL
+
+typedef struct _new_process
+{
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2;
+} LTT_PACKED_STRUCT new_process;
+
+#define write_to_buffer(DEST, SRC, SIZE) \
+do\
+{\
+ memcpy(DEST, SRC, SIZE);\
+ DEST += SIZE;\
+} while(0);
+
+int readFile(int fd, void * buf, size_t size, char * mesg)
+{
+ ssize_t nbBytes = read(fd, buf, size);
+
+ if((size_t)nbBytes != size) {
+ if(nbBytes < 0) {
+ perror("Error in readFile : ");
+ } else {
+ printf("%s\n",mesg);
+ }
+ exit(1);
+ }
+ return 0;
+}
+
+void getDataEndianType(char * size, char * endian)
+{
+ int i = 1;
+ char c = (char) i;
+ int sizeInt=sizeof(int), sizeLong=sizeof(long), sizePointer=sizeof(void *);
+
+ if(c == 1) strcpy(endian,"LITTLE_ENDIAN");
+ else strcpy(endian, "BIG_ENDIAN");
+
+ if(sizeInt == 2 && sizeLong == 4 && sizePointer == 4)
+ strcpy(size,"LP32");
+ else if(sizeInt == 4 && sizeLong == 4 && sizePointer == 4)
+ strcpy(size,"ILP32");
+ else if(sizeInt == 4 && sizeLong == 8 && sizePointer == 8)
+ strcpy(size,"LP64");
+ else if(sizeInt == 8 && sizeLong == 8 && sizePointer == 8)
+ strcpy(size,"ILP64");
+ else strcpy(size,"UNKNOWN");
+}
+
+#define BUFFER_SIZE 80
+
+typedef struct _buffer_start{
+ uint32_t seconds;
+ uint32_t nanoseconds;
+ uint64_t cycle_count;
+ uint32_t block_id;
+} __attribute__ ((packed)) buffer_start;
+
+typedef struct _buffer_end{
+ uint32_t seconds;
+ uint32_t nanoseconds;
+ uint64_t cycle_count;
+ uint32_t block_id;
+} __attribute__ ((packed)) buffer_end;
+
+
+typedef struct _heartbeat{
+ uint32_t seconds;
+ uint32_t nanoseconds;
+ uint64_t cycle_count;
+} __attribute__ ((packed)) heartbeat;
+
+
+int main(int argc, char ** argv){
+
+ int fd, fdCpu;
+ FILE * fp;
+ int fdFac, fdIntr, fdProc;
+ char arch_size[BUFFER_SIZE];
+ char endian[BUFFER_SIZE];
+ char node_name[BUFFER_SIZE];
+ char domainname[BUFFER_SIZE];
+ char kernel_name[BUFFER_SIZE];
+ char kernel_release[BUFFER_SIZE];
+ char kernel_version[BUFFER_SIZE];
+ char machine[BUFFER_SIZE];
+ char processor[BUFFER_SIZE];
+ char hardware_platform[BUFFER_SIZE];
+ char operating_system[BUFFER_SIZE];
+ int cpu;
+ int ltt_block_size=0;
+ int ltt_major_version=0;
+ int ltt_minor_version=0;
+ int ltt_log_cpu;
+ guint ltt_trace_start_size = 0;
+ char buf[BUFFER_SIZE];
+ int i, k;
+
+ uint8_t cpu_id;
+
+ char foo[4*BUFFER_SIZE];
+ char foo_eventdefs[4*BUFFER_SIZE];
+ char foo_control[4*BUFFER_SIZE];
+ char foo_cpu[4*BUFFER_SIZE];
+ char foo_info[4*BUFFER_SIZE];
+
+ char foo_control_facilities[4*BUFFER_SIZE];
+ char foo_control_processes[4*BUFFER_SIZE];
+ char foo_control_interrupts[4*BUFFER_SIZE];
+ char foo_info_system[4*BUFFER_SIZE];
+
+ struct stat lTDFStat;
+ off_t file_size;
+ int block_number, block_size;
+ char * buffer, *buf_out, cpuStr[4*BUFFER_SIZE];
+ char * buf_fac, * buf_intr, * buf_proc;
+ void * write_pos, *write_pos_fac, * write_pos_intr, *write_pos_proc;
+ trace_start_any *tStart;
+ trace_buffer_start *tBufStart;
+ trace_buffer_end *tBufEnd;
+ trace_file_system * tFileSys;
+ uint16_t newId, startId, tmpId;
+ uint8_t evId;
+ uint32_t time_delta, startTimeDelta;
+ void * cur_pos, *end_pos;
+ buffer_start start, start_proc, start_intr;
+ buffer_end end, end_proc, end_intr;
+ heartbeat beat;
+ uint64_t adaptation_tsc; // (Mathieu)
+ uint32_t size_lost;
+ int reserve_size = sizeof(buffer_start) +
+ sizeof(buffer_end) + //buffer_end event
+ sizeof(uint32_t); //lost size
+ int nb_para;
+
+ new_process process;
+
+ if(argc < 4){
+ printf("Usage : ./convert processfile_name number_of_cpu tracefile1 tracefile2 ... trace_creation_directory\n");
+ printf("For more details, see README.\n");
+ exit(1);
+ }
+
+ cpu = atoi(argv[2]);
+ printf("cpu number = %d\n", cpu);
+ nb_para = 3 + cpu;
+
+ if(argc != nb_para && argc != nb_para+1){
+ printf("need trace files and cpu number or root directory for the new tracefile\n");
+ exit(1);
+ }
+
+ if(argc == nb_para){
+ strcpy(foo, "foo");
+ strcpy(foo_eventdefs, "foo/eventdefs");
+ strcpy(foo_control, "foo/control");
+ strcpy(foo_cpu, "foo/cpu");
+ strcpy(foo_info, "foo/info");
+ }else{
+ strcpy(foo, argv[nb_para]);
+ strcpy(foo_eventdefs, argv[nb_para]);
+ strcat(foo_eventdefs,"/eventdefs");
+ strcpy(foo_control, argv[nb_para]);
+ strcat(foo_control,"/control");
+ strcpy(foo_cpu, argv[nb_para]);
+ strcat(foo_cpu,"/cpu");
+ strcpy(foo_info, argv[nb_para]);
+ strcat(foo_info,"/info");
+ }
+ strcpy(foo_control_facilities, foo_control);
+ strcat(foo_control_facilities,"/facilities");
+ strcpy(foo_control_processes, foo_control);
+ strcat(foo_control_processes, "/processes");
+ strcpy(foo_control_interrupts, foo_control);
+ strcat(foo_control_interrupts, "/interrupts");
+ strcpy(foo_info_system, foo_info);
+ strcat(foo_info_system, "/system.xml");
+
+
+ getDataEndianType(arch_size, endian);
+ printf("Arch_size: %s, Endian: %s\n", arch_size, endian);
+
+ fp = fopen("sysInfo.out","r");
+ if(!fp){
+ g_error("Unable to open file sysInfo.out\n");
+ }
+
+ for(i=0;i<INFO_ENTRY;i++){
+ if(!fgets(buf,BUFFER_SIZE-1,fp))
+ g_error("The format of sysInfo.out is not right\n");
+ if(strncmp(buf,"node_name=",10)==0){
+ strcpy(node_name,&buf[10]);
+ node_name[strlen(node_name)-1] = '\0';
+ }else if(strncmp(buf,"domainname=",11)==0){
+ strcpy(domainname,&buf[11]);
+ domainname[strlen(domainname)-1] = '\0';
+ }else if(strncmp(buf,"kernel_name=",12)==0){
+ strcpy(kernel_name,&buf[12]);
+ kernel_name[strlen(kernel_name)-1] = '\0';
+ }else if(strncmp(buf,"kernel_release=",15)==0){
+ strcpy(kernel_release,&buf[15]);
+ kernel_release[strlen(kernel_release)-1] = '\0';
+ }else if(strncmp(buf,"kernel_version=",15)==0){
+ strcpy(kernel_version,&buf[15]);
+ kernel_version[strlen(kernel_version)-1] = '\0';
+ }else if(strncmp(buf,"machine=",8)==0){
+ strcpy(machine,&buf[8]);
+ machine[strlen(machine)-1] = '\0';
+ }else if(strncmp(buf,"processor=",10)==0){
+ strcpy(processor,&buf[10]);
+ processor[strlen(processor)-1] = '\0';
+ }else if(strncmp(buf,"hardware_platform=",18)==0){
+ strcpy(hardware_platform,&buf[18]);
+ hardware_platform[strlen(hardware_platform)-1] = '\0';
+ }else if(strncmp(buf,"operating_system=",17)==0){
+ strcpy(operating_system,&buf[17]);
+ operating_system[strlen(operating_system)-1] = '\0';
+ }
+ }
+ fclose(fp);
+
+ if(mkdir(foo, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH))
+ g_error("can not make %s directory", foo);
+ if(mkdir(foo_info, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH))
+ g_error("can not make %s directory", foo_info);
+ if(mkdir(foo_cpu, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH))
+ g_error("can not make %s directory", foo_cpu);
+ if(mkdir(foo_control, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH))
+ g_error("can not make %s directory", foo_control);
+ if(mkdir(foo_eventdefs, S_IFDIR | S_IRWXU | S_IRGRP | S_IROTH))
+ g_error("can not make %s directory", foo_eventdefs);
+
+ fp = fopen(foo_info_system,"w");
+ if(!fp){
+ g_error("Unable to open file system.xml\n");
+ }
+
+ fdFac = open(foo_control_facilities,O_CREAT | O_RDWR | O_TRUNC,S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH);
+ if(fdFac < 0){
+ g_error("Unable to open file facilities\n");
+ }
+ fdIntr = open(foo_control_interrupts,O_CREAT | O_RDWR | O_TRUNC,S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH);
+ if(fdIntr<0){
+ g_error("Unable to open file interrupts\n");
+ }
+ fdProc = open(foo_control_processes,O_CREAT | O_RDWR | O_TRUNC,S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH);
+ if(fdProc<0){
+ g_error("Unable to open file process\n");
+ }
+
+
+ for(k=0;k<cpu;k++){
+ fd = open(argv[nb_para-cpu+k], O_RDONLY, 0);
+ if(fd < 0){
+ g_error("Unable to open input data file %s\n", argv[nb_para-cpu+k]);
+ }
+
+ if(fstat(fd, &lTDFStat) < 0){
+ g_error("Unable to get the status of the input data file\n");
+ }
+ file_size = lTDFStat.st_size;
+
+ buffer = g_new(char, 4000);
+ readFile(fd,(void*)buffer, 3500, "Unable to read block header");
+
+ cur_pos= buffer;
+ evId = *(uint8_t *)cur_pos;
+ cur_pos += sizeof(uint8_t);
+ newId = evId;
+ time_delta = *(uint32_t*)cur_pos;
+ cur_pos += sizeof(uint32_t);
+ tBufStart = (trace_buffer_start*)cur_pos;
+ cur_pos += sizeof(trace_buffer_start);
+ cur_pos += sizeof(uint16_t); //Skip event size
+
+ evId = *(uint8_t *)cur_pos;
+ g_assert(evId == TRACE_START);
+ cur_pos += sizeof(uint8_t); //skip EvId
+ cur_pos += sizeof(uint32_t); //skip time delta
+ tStart = (trace_start_any*)cur_pos;
+ if(tStart->MagicNumber != TRACER_MAGIC_NUMBER)
+ g_error("Trace magic number does not match : %lx, should be %lx",
+ tStart->MagicNumber, TRACER_MAGIC_NUMBER);
+ if(tStart->MajorVersion != TRACER_SUP_VERSION_MAJOR)
+ g_error("Trace Major number does match : %hu, should be %u",
+ tStart->MajorVersion, TRACER_SUP_VERSION_MAJOR);
+
+ startId = newId;
+ startTimeDelta = time_delta;
+ start.seconds = tBufStart->Time.tv_sec;
+ /* Fix (Mathieu) */
+ start.nanoseconds = tBufStart->Time.tv_usec * 1000;
+ start.cycle_count = tBufStart->TSC;
+ start.block_id = tBufStart->ID;
+ end.block_id = start.block_id;
+
+
+ g_printf("Trace version %hu.%hu detected\n",
+ tStart->MajorVersion,
+ tStart->MinorVersion);
+ if(tStart->MinorVersion == 2) {
+ trace_start_2_2* tStart_2_2 = (trace_start_2_2*)tStart;
+ ltt_major_version = tStart_2_2->MajorVersion;
+ ltt_minor_version = tStart_2_2->MinorVersion;
+ ltt_block_size = tStart_2_2->BufferSize;
+ ltt_log_cpu = tStart_2_2->LogCPUID;
+ ltt_trace_start_size = sizeof(trace_start_2_2);
+ /* Verify if it's a broken 2.2 format */
+ if(*(uint8_t*)(cur_pos + sizeof(trace_start_2_2)) == 0) {
+ /* Cannot have two trace start events. We cannot detect the problem
+ * if the flight recording flag is set to 1, as it conflicts
+ * with TRACE_SYSCALL_ENTRY.
+ */
+ g_warning("This is a 2.3 trace format that has a 2.2 tag. Please upgrade your kernel");
+ g_printf("Processing the trace as a 2.3 format\n");
+
+ tStart->MinorVersion = 3;
+ }
+ }
+
+ if(tStart->MinorVersion == 3) {
+ trace_start_2_3* tStart_2_3 = (trace_start_2_3*)tStart;
+ ltt_major_version = tStart_2_3->MajorVersion;
+ ltt_minor_version = tStart_2_3->MinorVersion;
+ ltt_block_size = tStart_2_3->BufferSize;
+ ltt_log_cpu = tStart_2_3->LogCPUID;
+ ltt_trace_start_size = sizeof(trace_start_2_3);
+ /* We do not use the flight recorder information for now, because we
+ * never use the .proc file anyway */
+ }
+
+ if(ltt_trace_start_size == 0)
+ g_error("Minor version unknown : %hu. Supported minors : 2, 3",
+ tStart->MinorVersion);
+
+ block_size = ltt_block_size;//FIXME
+ block_number = file_size/ltt_block_size;
+
+ g_free(buffer);
+ buffer = g_new(char, ltt_block_size);
+ buf_fac = g_new(char, block_size);
+ write_pos_fac = buf_fac;
+ buf_intr = g_new(char, block_size);
+ write_pos_intr = buf_intr;
+ buf_proc = g_new(char, block_size);
+ write_pos_proc = buf_proc;
+
+ buf_out = g_new(char, block_size);
+ write_pos = buf_out;
+ sprintf(cpuStr,"%s/%d",foo_cpu,k);
+ fdCpu = open(cpuStr, O_CREAT | O_RDWR | O_TRUNC,S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH); //for cpu k
+ if(fdCpu < 0) g_error("Unable to open cpu file %d\n", k);
+ lseek(fd,0,SEEK_SET);
+
+ for(i=0;i<block_number;i++){
+ int event_count = 0;
+
+ memset((void*)buf_out, 0, block_size);
+ write_pos = buf_out;
+ memset((void*)buf_intr, 0, block_size);
+ memset((void*)buf_fac, 0, block_size);
+ memset((void*)buf_proc, 0, block_size);
+ write_pos_intr = buf_intr;
+ write_pos_fac = buf_fac;
+ write_pos_proc = buf_proc;
+
+ memset((void*)buffer,0,ltt_block_size);
+ readFile(fd,(void*)buffer, ltt_block_size, "Unable to read block header");
+
+ cur_pos= buffer;
+ evId = *(uint8_t *)cur_pos;
+ cur_pos += sizeof(uint8_t);
+ newId = evId;
+ time_delta = *(uint32_t*)cur_pos;
+ cur_pos += sizeof(uint32_t);
+ tBufStart = (trace_buffer_start*)cur_pos;
+ cur_pos += sizeof(trace_buffer_start);
+ cur_pos += sizeof(uint16_t); //Skip event size
+
+ startId = newId;
+ startTimeDelta = time_delta;
+ start.seconds = tBufStart->Time.tv_sec;
+ /* usec -> nsec (Mathieu) */
+ start.nanoseconds = tBufStart->Time.tv_usec * 1000;
+ start.block_id = tBufStart->ID;
+ end.block_id = start.block_id;
+
+ end_pos = buffer + ltt_block_size; //end of the buffer
+ size_lost = *(uint32_t*)(end_pos - sizeof(uint32_t));
+
+ end_pos = buffer + ltt_block_size - size_lost ; //buffer_end event
+ if(ltt_log_cpu){
+ tBufEnd = (trace_buffer_end*)(end_pos + 2 * sizeof(uint8_t)+sizeof(uint32_t));
+ }else{
+ tBufEnd = (trace_buffer_end*)(end_pos+sizeof(uint8_t)+sizeof(uint32_t));
+ }
+ end.seconds = tBufEnd->Time.tv_sec;
+ /* usec -> nsec (Mathieu) */
+ end.nanoseconds = tBufEnd->Time.tv_usec * 1000;
+ // only 32 bits :(
+ //end.cycle_count = tBufEnd->TSC;
+
+ //skip buffer start and trace start events
+ if(i==0) {
+ //the first block
+ adaptation_tsc = (uint64_t)tBufStart->TSC;
+ cur_pos = buffer + sizeof(trace_buffer_start)
+ + ltt_trace_start_size
+ + 2*(sizeof(uint8_t)
+ + sizeof(uint16_t)+sizeof(uint32_t));
+ } else {
+ //other blocks
+ cur_pos = buffer + sizeof(trace_buffer_start)
+ + sizeof(uint8_t)
+ + sizeof(uint16_t)+sizeof(uint32_t);
+
+ /* Fix (Mathieu) */
+ if(time_delta < (0xFFFFFFFFULL&adaptation_tsc)) {
+ /* Overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL)
+ + 0x100000000ULL
+ + (uint64_t)time_delta;
+ } else {
+ /* No overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL) + time_delta;
+ }
+
+ }
+ start.cycle_count = adaptation_tsc;
+
+ //write start block event
+ write_to_buffer(write_pos,(void*)&startId, sizeof(uint16_t));
+ write_to_buffer(write_pos,(void*)&startTimeDelta, sizeof(uint32_t));
+ write_to_buffer(write_pos,(void*)&start, sizeof(buffer_start));
+
+ //write start block event into processes and interrupts files
+ write_to_buffer(write_pos_intr,(void*)&startId, sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&startTimeDelta, sizeof(uint32_t));
+ start_intr = start;
+ start_intr.nanoseconds -= 20;
+ write_to_buffer(write_pos_intr,(void*)&start_intr, sizeof(buffer_start));
+
+ write_to_buffer(write_pos_proc,(void*)&startId, sizeof(uint16_t));
+ write_to_buffer(write_pos_proc,(void*)&startTimeDelta, sizeof(uint32_t));
+ start_proc = start;
+ start_proc.nanoseconds -= 40;
+ write_to_buffer(write_pos_proc,(void*)&start_proc, sizeof(buffer_start));
+
+ //parse *.proc file to get process and irq info
+ if(i == 0){
+ int lIntID; /* Interrupt ID */
+ int lPID, lPPID; /* Process PID and Parent PID */
+ char lName[256]; /* Process name */
+ FILE * fProc;
+ uint16_t defaultId;
+ trace_irq_entry irq;
+
+ fProc = fopen(argv[1],"r");
+ if(!fProc){
+ g_error("Unable to open file %s\n", argv[1]);
+ }
+
+ while(fscanf(fProc, "PID: %d; PPID: %d; NAME: %s\n", &lPID, &lPPID, lName) > 0){
+ defaultId = PROCESS_FORK_ID;
+ process.event_data1 = lPID;
+ process.event_data2 = lPPID;
+ write_to_buffer(write_pos_proc,(void*)&defaultId, sizeof(uint16_t));
+ write_to_buffer(write_pos_proc,(void*)&startTimeDelta, sizeof(uint32_t));
+ write_to_buffer(write_pos_proc,(void*)&process, sizeof(new_process));
+ }
+
+ while(fscanf(fProc, "IRQ: %d; NAME: ", &lIntID) > 0){
+ /* Read 'til the end of the line */
+ fgets(lName, 200, fProc);
+
+ defaultId = TRACE_IRQ_ENTRY;
+ irq.irq_id = lIntID;
+ irq.kernel = 1;
+ write_to_buffer(write_pos_intr,(void*)&defaultId, sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&startTimeDelta, sizeof(uint32_t));
+ write_to_buffer(write_pos_intr,(void*)&irq, sizeof(trace_irq_entry));
+ }
+ fclose(fProc);
+ }
+
+ while(1){
+ int event_size;
+ uint64_t timeDelta;
+ uint8_t subId;
+
+ if(ltt_log_cpu){
+ cpu_id = *(uint8_t*)cur_pos;
+ cur_pos += sizeof(uint8_t);
+ }
+ evId = *(uint8_t *)cur_pos;
+ newId = evId;
+ if(evId == TRACE_HEARTBEAT) {
+ newId = TRACE_HEARTBEAT_ID;
+ }
+ cur_pos += sizeof(uint8_t);
+ time_delta = *(uint32_t*)cur_pos;
+ cur_pos += sizeof(uint32_t);
+
+
+ //write event_id and time_delta
+ write_to_buffer(write_pos,(void*)&newId,sizeof(uint16_t));
+ write_to_buffer(write_pos,(void*)&time_delta, sizeof(uint32_t));
+
+ /* Fix (Mathieu) */
+ if(time_delta < (0xFFFFFFFFULL&adaptation_tsc)) {
+ /* Overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL) + 0x100000000ULL
+ + (uint64_t)time_delta;
+ } else {
+ /* No overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL) + time_delta;
+ }
+
+
+ if(evId == TRACE_BUFFER_END){
+#if 0
+ /* Fix (Mathieu) */
+ if(time_delta < (0xFFFFFFFFULL&adaptation_tsc)) {
+ /* Overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL) + 0x100000000ULL
+ + (uint64_t)time_delta;
+ } else {
+ /* No overflow */
+ adaptation_tsc = (adaptation_tsc&0xFFFFFFFF00000000ULL) + time_delta;
+ }
+#endif //0
+ end.cycle_count = adaptation_tsc;
+ int size = (void*)buf_out + block_size - write_pos
+ - sizeof(buffer_end) - sizeof(uint32_t);
+
+ /* size _lost_ ? */
+ //int size = (void*)buf_out + block_size - write_pos
+ // + sizeof(uint16_t) + sizeof(uint32_t);
+ g_assert((void*)write_pos < (void*)buf_out + block_size);
+ write_to_buffer(write_pos,(void*)&end,sizeof(buffer_end));
+ write_pos = buf_out + block_size - sizeof(uint32_t);
+ write_to_buffer(write_pos,(void*)&size, sizeof(uint32_t));
+ write(fdCpu,(void*)buf_out, block_size);
+
+ //write out processes and intrrupts files
+ {
+ int size_intr = block_size + (void*)buf_intr - write_pos_intr
+ - sizeof(buffer_end) - sizeof(uint32_t);
+ int size_proc = block_size + (void*)buf_proc - write_pos_proc
+ - sizeof(buffer_end) - sizeof(uint32_t);
+ //int size_intr = block_size - (write_pos_intr - (void*)buf_intr);
+ //int size_proc = block_size - (write_pos_proc - (void*)buf_proc);
+ write_to_buffer(write_pos_intr,(void*)&newId,sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&time_delta, sizeof(uint32_t));
+ end_intr = end;
+ end_intr.nanoseconds -= 20;
+ write_to_buffer(write_pos_intr,(void*)&end_intr,sizeof(buffer_start));
+
+ write_to_buffer(write_pos_proc,(void*)&newId,sizeof(uint16_t));
+ write_to_buffer(write_pos_proc,(void*)&time_delta, sizeof(uint32_t));
+ end_proc = end;
+ end_proc.nanoseconds -= 40;
+ write_to_buffer(write_pos_proc,(void*)&end_proc,sizeof(buffer_start));
+
+ write_pos_intr = buf_intr + block_size - sizeof(uint32_t);
+ write_pos_proc = buf_proc + block_size - sizeof(uint32_t);
+ write_to_buffer(write_pos_intr,(void*)&size_intr, sizeof(uint32_t));
+ write_to_buffer(write_pos_proc,(void*)&size_proc, sizeof(uint32_t));
+ //for now don't output processes and interrupt information
+ // write(fdIntr,(void*)buf_intr,block_size);
+ // write(fdProc,(void*)buf_proc,block_size);
+ }
+ break;
+ }
+
+ event_count++;
+ switch(evId){
+ case TRACE_SYSCALL_ENTRY:
+ event_size = sizeof(trace_syscall_entry);
+ break;
+ case TRACE_SYSCALL_EXIT:
+ event_size = 0;
+ break;
+ case TRACE_TRAP_ENTRY:
+ event_size = sizeof(trace_trap_entry);
+ break;
+ case TRACE_TRAP_EXIT:
+ event_size = 0;
+ break;
+ case TRACE_IRQ_ENTRY:
+ event_size = sizeof(trace_irq_entry);
+ timeDelta = time_delta;
+ write_to_buffer(write_pos_intr,(void*)&newId, sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&timeDelta, sizeof(uint32_t));
+ write_to_buffer(write_pos_intr,cur_pos, event_size);
+ break;
+ case TRACE_IRQ_EXIT:
+ event_size = 0;
+ timeDelta = time_delta;
+ write_to_buffer(write_pos_intr,(void*)&newId, sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&timeDelta, sizeof(uint32_t));
+ break;
+ case TRACE_SCHEDCHANGE:
+ event_size = sizeof(trace_schedchange);
+ break;
+ case TRACE_KERNEL_TIMER:
+ event_size = 0;
+ break;
+ case TRACE_SOFT_IRQ:
+ event_size = sizeof(trace_soft_irq);
+ // timeDelta = time_delta;
+ // write_to_buffer(write_pos_intr,(void*)&newId, sizeof(uint16_t));
+ // write_to_buffer(write_pos_intr,(void*)&timeDelta, sizeof(uint32_t));
+ // write_to_buffer(write_pos_intr,cur_pos, event_size);
+ break;
+ case TRACE_PROCESS:
+ event_size = sizeof(trace_process);
+ timeDelta = time_delta;
+ subId = *(uint8_t*)cur_pos;
+ if(subId == TRACE_PROCESS_FORK || subId ==TRACE_PROCESS_EXIT){
+ if( subId == TRACE_PROCESS_FORK)tmpId = PROCESS_FORK_ID;
+ else tmpId = PROCESS_EXIT_ID;
+ write_to_buffer(write_pos_proc,(void*)&tmpId, sizeof(uint16_t));
+ write_to_buffer(write_pos_proc,(void*)&timeDelta, sizeof(uint32_t));
+
+ process = *(new_process*)(cur_pos + sizeof(uint8_t));
+ write_to_buffer(write_pos_proc,(void*)&process, sizeof(new_process));
+ }
+ break;
+ case TRACE_FILE_SYSTEM:
+ event_size = sizeof(trace_file_system)- sizeof(char*);
+ break;
+ case TRACE_TIMER:
+ event_size = sizeof(trace_timer);
+ break;
+ case TRACE_MEMORY:
+ event_size = sizeof(trace_memory);
+ break;
+ case TRACE_SOCKET:
+ event_size = sizeof(trace_socket);
+ break;
+ case TRACE_IPC:
+ event_size = sizeof(trace_ipc);
+ break;
+ case TRACE_NETWORK:
+ event_size = sizeof(trace_network);
+ break;
+ case TRACE_HEARTBEAT:
+ beat.seconds = 0;
+ beat.nanoseconds = 0;
+ beat.cycle_count = adaptation_tsc;
+ event_size = 0;
+
+ write_to_buffer(write_pos_intr,(void*)&newId, sizeof(uint16_t));
+ write_to_buffer(write_pos_intr,(void*)&time_delta, sizeof(uint32_t));
+ write_to_buffer(write_pos_intr,(void*)&beat, sizeof(heartbeat));
+ write_to_buffer(write_pos_proc,(void*)&newId, sizeof(uint16_t));
+ write_to_buffer(write_pos_proc,(void*)&time_delta, sizeof(uint32_t));
+ write_to_buffer(write_pos_proc,(void*)&beat, sizeof(heartbeat));
+ break;
+ default:
+ event_size = -1;
+ break;
+ }
+ if(evId != TRACE_FILE_SYSTEM && event_size >=0){
+ write_to_buffer(write_pos, cur_pos, event_size);
+
+ if(evId == TRACE_HEARTBEAT){
+ write_to_buffer(write_pos, (void*)&beat, sizeof(heartbeat));
+ }
+
+ cur_pos += event_size + sizeof(uint16_t); //skip data_size
+ }else if(evId == TRACE_FILE_SYSTEM){
+ size_t nbBytes;
+ char c = '\0';
+ tFileSys = (trace_file_system*)cur_pos;
+ subId = tFileSys->event_sub_id;
+ if(subId == TRACE_FILE_SYSTEM_OPEN || subId == TRACE_FILE_SYSTEM_EXEC){
+ nbBytes = tFileSys->event_data2 +1;
+ }else nbBytes = 0;
+
+ write_to_buffer(write_pos, cur_pos, event_size);
+ cur_pos += event_size + sizeof(char*);
+ if(nbBytes){
+ write_to_buffer(write_pos, cur_pos, nbBytes);
+ }else{
+ write_to_buffer(write_pos, (void*)&c, 1);
+ }
+ cur_pos += nbBytes + sizeof(uint16_t); //skip data_size
+ }else if(event_size == -1){
+ printf("Unknown event: evId=%d, i=%d, event_count=%d\n", newId, i, event_count);
+ exit(1);
+ }
+ } //end while(1)
+ }
+ close(fd);
+ close(fdCpu);
+ g_free(buffer);
+ buffer = NULL;
+ g_free(buf_fac);
+ g_free(buf_intr);
+ g_free(buf_proc);
+ g_free(buf_out);
+ }
+
+
+
+
+
+ //write to system.xml
+ fprintf(fp,"<system \n");
+ fprintf(fp,"node_name=\"%s\" \n", node_name);
+ fprintf(fp,"domainname=\"%s\" \n", domainname);
+ fprintf(fp,"cpu=\"%d\" \n", cpu);
+ fprintf(fp,"arch_size=\"%s\" \n", arch_size);
+ fprintf(fp,"endian=\"%s\" \n",endian);
+ fprintf(fp,"kernel_name=\"%s\" \n",kernel_name);
+ fprintf(fp,"kernel_release=\"%s\" \n",kernel_release);
+ fprintf(fp,"kernel_version=\"%s\" \n",kernel_version);
+ fprintf(fp,"machine=\"%s\" \n",machine);
+ fprintf(fp,"processor=\"%s\" \n",processor);
+ fprintf(fp,"hardware_platform=\"%s\" \n",hardware_platform);
+ fprintf(fp,"operating_system=\"%s\" \n",operating_system);
+ fprintf(fp,"ltt_major_version=\"%d\" \n",ltt_major_version);
+ fprintf(fp,"ltt_minor_version=\"%d\" \n",ltt_minor_version);
+ fprintf(fp,"ltt_block_size=\"%d\" \n",ltt_block_size);
+ fprintf(fp,">\n");
+ fprintf(fp,"This is just a test\n");
+ fprintf(fp,"</system>\n");
+ fflush(fp);
+
+ close(fdFac);
+ close(fdIntr);
+ close(fdProc);
+ fclose(fp);
+
+ g_printf("Conversion completed. Don't forget to copy core.xml to eventdefs directory\n");
+
+ return 0;
+}
+
--- /dev/null
+<facility name=core>
+ <description>The core facility contains the basic events</description>
+
+ <event name=facility_load>
+ <description>Facility used in the trace</description>
+ <struct>
+ <field name="name"><string/></field>
+ <field name="checksum"><uint size=4/></field>
+ <field name="base_code"><uint size=4/></field>
+ </struct>
+ </event>
+
+ <event name=syscall_entry>
+ <description>Entry in a given system call</description>
+ <struct>
+ <field name="syscall_id"> <description>Syscall entry number in entry.S</description> <uint size=1/> </field>
+ <field name="address"> <description>Address from which call was made</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=syscall_exit>
+ <description>Exit from a given system call</description>
+ </event>
+
+ <event name=trap_entry>
+ <description>Entry in a trap</description>
+ <struct>
+ <field name="trap_id"> <description>Trap number</description> <uint size=2/> </field>
+ <field name="address"> <description>Address where trap occured</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=trap_exit>
+ <description>Exit from a trap</description>
+ </event>
+
+ <event name=irq_entry>
+ <description>Entry in an irq</description>
+ <struct>
+ <field name="irq_id"> <description>IRQ number</description> <uint size=1/> </field>
+ <field name="kernel"> <description>Are we executing kernel code</description> <uint size=1/> </field>
+ </struct>
+ </event>
+
+ <event name=irq_exit>
+ <description>Exit from an IRQ</description>
+ </event>
+
+ <event name=schedchange>
+ <description>Scheduling change</description>
+ <struct>
+ <field name="out"> <description>Outgoing process</description> <uint size=4/> </field>
+ <field name="in"> <description>Incoming process</description> <uint size=4/> </field>
+ <field name="out_state"> <description>Outgoing process' state</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=kernel_timer>
+ <description>The kernel timer routine has been called</description>
+ </event>
+
+ <event name=soft_irq>
+ <description>Hit key part of soft-irq management</description>
+ <struct>
+ <field name="event_sub_id"> <description>Soft-irq event Id</description>
+ <enum size=1>
+ <label name=TRACE_EV_SOFT_IRQ_BOTTOM_HALF value=1/>
+ <label name=TRACE_EV_SOFT_IRQ_SOFT_IRQ/>
+ <label name=TRACE_EV_SOFT_IRQ_TASKLET_ACTION/>
+ <label name=TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION/>
+ </enum>
+ </field>
+
+ <field name="event_data"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=process>
+ <description>Hit key part of process management</description>
+ <struct>
+ <field name="event_sub_id"> <description>Process event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_PROCESS_KTHREAD value=1/>
+ <label name=TRACE_EV_PROCESS_FORK/>
+ <label name=TRACE_EV_PROCESS_EXIT/>
+ <label name=TRACE_EV_PROCESS_WAIT/>
+ <label name=TRACE_EV_PROCESS_SIGNAL/>
+ <label name=TRACE_EV_PROCESS_WAKEUP/>
+ <label name=TRACE_EV_PROCESS_RELEASE/>
+ </enum>
+ </field>
+
+ <field name="event_data1"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=file_system>
+ <description>Hit key part of file system</description>
+ <struct>
+ <field name="event_sub_id"> <description>File system event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_FILE_SYSTEM_BUF_WAIT_START value=1/>
+ <label name=TRACE_EV_FILE_SYSTEM_BUF_WAIT_END/>
+ <label name=TRACE_EV_FILE_SYSTEM_EXEC/>
+ <label name=TRACE_EV_FILE_SYSTEM_OPEN/>
+ <label name=TRACE_EV_FILE_SYSTEM_CLOSE/>
+ <label name=TRACE_EV_FILE_SYSTEM_READ/>
+ <label name=TRACE_EV_FILE_SYSTEM_WRITE/>
+ <label name=TRACE_EV_FILE_SYSTEM_SEEK/>
+ <label name=TRACE_EV_FILE_SYSTEM_IOCTL/>
+ <label name=TRACE_EV_FILE_SYSTEM_SELECT/>
+ <label name=TRACE_EV_FILE_SYSTEM_POLL/>
+ </enum>
+ </field>
+
+ <field name="event_data1"> <description>Event data </description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Event data 2</description> <uint size=4/> </field>
+ <field name="file_name"> <description>Name of file operated on </description> <string/> </field>
+ </struct>
+ </event>
+
+ <event name=timer>
+ <description>Hit key part of timer management</description>
+ <struct>
+ <field name="event_sub_id"> <description>Timer event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_TIMER_EXPIRED value=1/>
+ <label name=TRACE_EV_TIMER_SETITIMER/>
+ <label name=TRACE_EV_TIMER_SETTIMEOUT/>
+ </enum>
+ </field>
+
+ <field name="event_sdata"> <description>Short data</description> <uint size=1/> </field>
+ <field name="event_data1"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=memory>
+ <description>Hit key part of memory management</description>
+ <struct>
+ <field name="event_sub_id"> <description>Memory event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_MEMORY_PAGE_ALLOC value=1/>
+ <label name=TRACE_EV_MEMORY_PAGE_FREE/>
+ <label name=TRACE_EV_MEMORY_SWAP_IN/>
+ <label name=TRACE_EV_MEMORY_SWAP_OUT/>
+ <label name=TRACE_EV_MEMORY_PAGE_WAIT_START/>
+ <label name=TRACE_EV_MEMORY_PAGE_WAIT_END/>
+ </enum>
+ </field>
+
+ <field name="event_data"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=socket>
+ <description>Hit key part of socket communication</description>
+ <struct>
+ <field name="event_sub_id"> <description>Memory event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_SOCKET_CALL value=1/>
+ <label name=TRACE_EV_SOCKET_CREATE/>
+ <label name=TRACE_EV_SOCKET_SEND/>
+ <label name=TRACE_EV_SOCKET_RECEIVE/>
+ </enum>
+ </field>
+
+ <field name="event_data1"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=ipc>
+ <description>Hit key part of System V IPC</description>
+ <struct>
+ <field name="event_sub_id"> <description>Memory event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_IPC_CALL value=1/>
+ <label name=TRACE_EV_IPC_MSG_CREATE/>
+ <label name=TRACE_EV_IPC_SEM_CREATE/>
+ <label name=TRACE_EV_IPC_SHM_CREATE/>
+ </enum>
+ </field>
+
+ <field name="event_data1"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=network>
+ <description>Hit key part of network communication</description>
+ <struct>
+ <field name="event_sub_id"> <description>Memory event ID</description>
+ <enum size=1>
+ <label name=TRACE_EV_NETWORK_PACKET_IN value=1/>
+ <label name=TRACE_EV_NETWORK_PACKET_OUT/>
+ </enum>
+ </field>
+
+ <field name="event_data"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=block_start>
+ <description>Block start timestamp</description>
+ <typeref name=block_timestamp/>
+ </event>
+
+ <event name=block_end>
+ <description>Block end timestamp</description>
+ <typeref name=block_timestamp/>
+ </event>
+
+ <event name=time_heartbeat>
+ <description>System time values sent periodically to minimize cycle counter
+ drift with respect to real time clock and to detect cycle counter roolovers
+ </description>
+ <typeref name=timestamp/>
+ </event>
+
+ <type name=block_timestamp>
+ <struct>
+ <field name=timestamp><typeref name=timestamp/></field>
+ <field name=block_id><uint size=4/></field>
+ </struct>
+ </type>
+
+ <type name=timestamp>
+ <struct>
+ <field name=time><typeref name=timespec/></field>
+ <field name="cycle_count"><uint size=8/></field>
+ </struct>
+ </type>
+
+ <type name=timespec>
+ <struct>
+ <field name="seconds"><uint size=4/></field>
+ <field name="nanoseconds"><uint size=4/></field>
+ </struct>
+ </type>
+
+
+ <event name=process_fork>
+ <description>Fork a new process</description>
+ <struct>
+ <field name="child_pid"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+ <event name=process_exit>
+ <description>Exit from a process</description>
+ <struct>
+ <field name="event_data1"> <description>Data associated with event</description> <uint size=4/> </field>
+ <field name="event_data2"> <description>Data associated with event</description> <uint size=4/> </field>
+ </struct>
+ </event>
+
+</facility>
+
+
--- /dev/null
+#!/bin/bash
+
+# DO NOT FORGET TO DISABLE ALL THE JAVA OPTIONS IN NETSCAPE
+# OTHERWISE IT WILL DIE ...
+
+outputFile=sysInfo.out
+
+NODE_NAME=`uname -n`
+echo "node_name="$NODE_NAME > $outputFile
+
+DOMAINNAME="`hostname --domain`"
+echo "domainname="$DOMAINNAME >> $outputFile
+
+KERNEL_NAME="`uname -s`"
+echo "kernel_name="$KERNEL_NAME >> $outputFile
+
+KERNEL_RELEASE="`uname -r`"
+echo "kernel_release="$KERNEL_RELEASE >> $outputFile
+
+KERNEL_VERSION="`uname -v`"
+echo "kernel_version="$KERNEL_VERSION >> $outputFile
+
+MACHINE="`uname -m`"
+echo "machine="$MACHINE >> $outputFile
+
+
+# not available anymore in uname version 5 and newer
+PROCESSOR="`uname -p`"
+echo "processor="$PROCESSOR >> $outputFile
+
+# not available anymore in uname version 5 and newer
+HARDWARE_PLATFORM="`uname -i`"
+echo "hardware_platform="$HARDWARE_PLATFORM >> $outputFile
+
+OPERATING_SYSTEM="`uname -o`"
+echo "operating_system="$OPERATING_SYSTEM >> $outputFile
+
+
+#export $NODE_NAME
+#export $NODE_NAME $DOMAINNAME $KERNEL_NAME $KERNEL_RELEASE $KERNEL_VERSION $MACHINE $PROCESSOR $HARDWARE_PLATFORM $OPERATING_SYSTEM
+
+
+
+#/sbin/lilo -C "$liloConf"
+
--- /dev/null
+ 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
+ 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
+ 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
+ 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
+ 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
+ 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
+ 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
+ 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
+ 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
+ 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
+ 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
+ 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
+ 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
+ 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
+ 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
+ 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
+ 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
+ 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
+ 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
+ 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
+ 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
+ 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
+ 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
+ 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
+ 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
+ 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
+ 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
+ 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
+ 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
+ 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
+ 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
+ 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
+ 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
+ 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
+ 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
+ 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
+ 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
+ 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
+ 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
+ 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
+ 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
+ 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
+ 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
+ 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
+ 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
+ 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
+ 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
+ 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
+ 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
+ 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
+ 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
+ 0x2d02ef8dU
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Xiangxiu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <asm/types.h>
+#include <linux/byteorder/swab.h>
+
+#include "parser.h"
+#include <ltt/ltt.h>
+#include "ltt-private.h"
+#include <ltt/event.h>
+#include <ltt/trace.h>
+#include <ltt/ltt-types.h>
+
+
+LttEvent *ltt_event_new()
+{
+ return g_new(LttEvent, 1);
+}
+
+void ltt_event_destroy(LttEvent *event)
+{
+ g_free(event);
+}
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_refresh_fields : refresh fields of an event
+ *Input params
+ * offsetRoot : offset from the root
+ * offsetParent : offset from the parent
+ * fld : field
+ * evD : event data
+ * reverse_byte_order : 1 or 0
+ *Return value
+ * int : size of the field
+ ****************************************************************************/
+
+int ltt_event_refresh_fields(int offsetRoot,int offsetParent,
+ LttField * fld, void *evD, gboolean reverse_byte_order)
+{
+ int size, size1, element_number, i, offset1, offset2;
+ LttType * type = fld->field_type;
+
+ switch(type->type_class) {
+ case LTT_ARRAY:
+ element_number = (int) type->element_number;
+ if(fld->field_fixed == 0){// has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += ltt_event_refresh_fields(offsetRoot+size,size,
+ fld->child[0], evD+size, reverse_byte_order);
+ }
+ }else size = fld->field_size;
+ break;
+
+ case LTT_SEQUENCE:
+ size1 = fld->sequ_number_size;
+ element_number = getIntNumber(reverse_byte_order,size1,evD);
+ type->element_number = element_number;
+ if(fld->element_size > 0){
+ size = element_number * fld->element_size;
+ }else{//sequence has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += ltt_event_refresh_fields(offsetRoot+size+size1,size+size1,
+ fld->child[0], evD+size+size1, reverse_byte_order);
+ }
+ size += size1;
+ }
+ break;
+
+ case LTT_STRING:
+ size = strlen((gchar*)evD) + 1; //include end : '\0'
+ break;
+
+ case LTT_STRUCT:
+ element_number = (int) type->element_number;
+ if(fld->field_fixed == 0){
+ offset1 = offsetRoot;
+ offset2 = 0;
+ for(i=0;i<element_number;i++){
+ size=ltt_event_refresh_fields(offset1,offset2,
+ fld->child[i],evD+offset2, reverse_byte_order);
+ offset1 += size;
+ offset2 += size;
+ }
+ size = offset2;
+ }else size = fld->field_size;
+ break;
+
+ case LTT_UNION:
+ size = fld->field_size;
+ break;
+
+ default:
+ size = fld->field_size;
+ }
+
+#if 0
+ if(type->type_class != LTT_STRUCT && type->type_class != LTT_ARRAY &&
+ type->type_class != LTT_SEQUENCE && type->type_class != LTT_STRING){
+ size = fld->field_size;
+ }else if(type->type_class == LTT_ARRAY){
+ element_number = (int) type->element_number;
+ if(fld->field_fixed == 0){// has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += ltt_event_refresh_fields(offsetRoot+size,size,
+ fld->child[0], evD+size);
+ }
+ }else size = fld->field_size;
+ }else if(type->type_class == LTT_SEQUENCE){
+ size1 = fld->sequ_number_size;
+ element_number = getIntNumber(size1,evD);
+ type->element_number = element_number;
+ if(fld->element_size > 0){
+ size = element_number * fld->element_size;
+ }else{//sequence has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += ltt_event_refresh_fields(offsetRoot+size+size1,size+size1,
+ fld->child[0], evD+size+size1);
+ }
+ size += size1;
+ }
+ }else if(type->type_class == LTT_STRING){
+ size = strlen((char*)evD) + 1; //include end : '\0'
+ }else if(type->type_class == LTT_STRUCT){
+ element_number = (int) type->element_number;
+ if(fld->field_fixed == 0){
+ offset1 = offsetRoot;
+ offset2 = 0;
+ for(i=0;i<element_number;i++){
+ size=ltt_event_refresh_fields(offset1,offset2,
+ fld->child[i],evD+offset2);
+ offset1 += size;
+ offset2 += size;
+ }
+ size = offset2;
+ }else size = fld->field_size;
+ }
+#endif //0
+ fld->offset_root = offsetRoot;
+ fld->offset_parent = offsetParent;
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+ fld->field_size = size;
+
+ return size;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_eventtype_id: get event type id
+ * (base id + position of the event)
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * unsigned : event type id
+ ****************************************************************************/
+
+unsigned ltt_event_eventtype_id(LttEvent *e)
+{
+ return (unsigned) e->event_id;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_facility : get the facility of the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * LttFacility * : the facility of the event
+ ****************************************************************************/
+
+LttFacility *ltt_event_facility(LttEvent *e)
+{
+ LttTrace * trace = e->tracefile->trace;
+ unsigned id = e->event_id;
+ return ltt_trace_facility_by_id(trace,id);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_eventtype : get the event type of the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * LttEventType * : the event type of the event
+ ****************************************************************************/
+
+LttEventType *ltt_event_eventtype(LttEvent *e)
+{
+ LttFacility* facility = ltt_event_facility(e);
+ if(!facility) return NULL;
+ return facility->events[e->event_id - facility->base_id];
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_field : get the root field of the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * LttField * : the root field of the event
+ ****************************************************************************/
+
+LttField *ltt_event_field(LttEvent *e)
+{
+ LttField * field;
+ LttEventType * event_type = ltt_event_eventtype(e);
+ if(unlikely(!event_type)) return NULL;
+ field = event_type->root_field;
+ if(unlikely(!field)) return NULL;
+
+ //check if the field need refresh
+ if(likely(e->which_block != event_type->latest_block ||
+ e->which_event != event_type->latest_event)){
+
+ event_type->latest_block = e->which_block;
+ event_type->latest_event = e->which_event;
+
+ if(unlikely(field->field_fixed != 1))
+ ltt_event_refresh_fields(0, 0, field, e->data,
+ e->tracefile->trace->reverse_byte_order);
+ }
+ return field;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_time : get the time of the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * LttTime : the time of the event
+ ****************************************************************************/
+
+LttTime ltt_event_time(LttEvent *e)
+{
+ return e->event_time;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_time : get the cycle count of the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * LttCycleCount : the cycle count of the event
+ ****************************************************************************/
+
+LttCycleCount ltt_event_cycle_count(LttEvent *e)
+{
+ return e->event_cycle_count;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_position : get the event's position
+ *Input params
+ * e : an instance of an event type
+ * ep : a pointer to event's position structure
+ ****************************************************************************/
+
+void ltt_event_position(LttEvent *e, LttEventPosition *ep)
+{
+ ep->block_num = e->which_block;
+ ep->event_num = e->which_event;
+ ep->event_time = e->event_time;
+ ep->event_cycle_count = e->event_cycle_count;
+ ep->heart_beat_number = e->tracefile->cur_heart_beat_number;
+ ep->old_position = TRUE;
+ ep->event_offset = e->data - e->tracefile->buffer - EVENT_HEADER_SIZE ;
+ ep->tf = e->tracefile;
+ ep->overflow_nsec = e->overflow_nsec;
+ /* This is a workaround for fast position seek */
+ ep->last_event_pos = e->last_event_pos;
+ ep->prev_block_end_time = e->prev_block_end_time;
+ ep->prev_event_time = e->prev_event_time;
+ ep->pre_cycle_count = e->pre_cycle_count;
+ ep->count = e->count;
+ ep->last_heartbeat = e->last_heartbeat;
+
+ /* end of workaround */
+}
+
+LttEventPosition * ltt_event_position_new()
+{
+ return g_new(LttEventPosition, 1);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_position_get : get the block number and index of the event
+ *Input params
+ * ep : a pointer to event's position structure
+ * block_number : the block number of the event
+ * index_in_block : the index of the event within the block
+ ****************************************************************************/
+
+void ltt_event_position_get(LttEventPosition *ep,
+ unsigned *block_number, unsigned *index_in_block, LttTracefile ** tf)
+{
+ *block_number = ep->block_num;
+ *index_in_block = ep->event_num;
+ *tf = ep->tf;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_position_set : set the block number and index of the event
+ * It does put the old_position gboolean to FALSE, as it is impossible
+ * to know the quick position to seek in the tracefile.
+ *Input params
+ * ep : a pointer to event's position structure
+ * block_number : the block number of the event
+ * index_in_block : the index of the event within the block
+ ****************************************************************************/
+
+void ltt_event_position_set(LttEventPosition *ep,
+ unsigned block_number, unsigned index_in_block)
+{
+ if(ep->block_num != block_number || ep->event_num != index_in_block)
+ ep->old_position = FALSE;
+
+ ep->block_num = block_number;
+ ep->event_num = index_in_block;
+
+}
+
+/*****************************************************************************
+ * Function name
+ * ltt_event_position_compare : compare two positions
+ * A NULL value is infinite.
+ * Input params
+ * ep1 : a pointer to event's position structure
+ * ep2 : a pointer to event's position structure
+ * Return
+ * -1 is ep1 < ep2
+ * 1 if ep1 > ep2
+ * 0 if ep1 == ep2
+ ****************************************************************************/
+
+
+gint ltt_event_position_compare(const LttEventPosition *ep1,
+ const LttEventPosition *ep2)
+{
+ if(ep1->tf != ep2->tf)
+ g_error("ltt_event_position_compare on different tracefiles makes no sense");
+ if(ep1 == NULL && ep2 == NULL)
+ return 0;
+ if(ep1 != NULL && ep2 == NULL)
+ return -1;
+ if(ep1 == NULL && ep2 != NULL)
+ return 1;
+
+ if(ep1->block_num < ep2->block_num)
+ return -1;
+ if(ep1->block_num > ep2->block_num)
+ return 1;
+ if(ep1->event_num < ep2->event_num)
+ return -1;
+ if(ep1->event_num > ep2->event_num)
+ return 1;
+ return 0;
+}
+
+/*****************************************************************************
+ * Function name
+ * ltt_event_event_position_compare : compare two positions, one in event,
+ * other in position opaque structure.
+ * Input params
+ * event : a pointer to event structure
+ * ep : a pointer to event's position structure
+ * Return
+ * -1 is event < ep
+ * 1 if event > ep
+ * 0 if event == ep
+ ****************************************************************************/
+
+gint ltt_event_event_position_compare(const LttEvent *event,
+ const LttEventPosition *ep)
+{
+ if(event == NULL && ep == NULL)
+ return 0;
+ if(event != NULL && ep == NULL)
+ return -1;
+ if(event == NULL && ep != NULL)
+ return 1;
+
+ g_assert(event->tracefile == ep->tf);
+
+ if(event->which_block < ep->block_num)
+ return -1;
+ if(event->which_block > ep->block_num)
+ return 1;
+ if(event->which_event < ep->event_num)
+ return -1;
+ if(event->which_event > ep->event_num)
+ return 1;
+ return 0;
+}
+
+/*****************************************************************************
+ * Function name
+ * ltt_event_position_copy : copy position
+ * Input params
+ * src : a pointer to event's position structure source
+ * dest : a pointer to event's position structure dest
+ * Return
+ * void
+ ****************************************************************************/
+void ltt_event_position_copy(LttEventPosition *dest,
+ const LttEventPosition *src)
+{
+ if(src == NULL)
+ dest = NULL;
+ else
+ *dest = *src;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_cpu_i: get the cpu id where the event happens
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * unsigned : the cpu id
+ ****************************************************************************/
+
+unsigned ltt_event_cpu_id(LttEvent *e)
+{
+ gchar * c1, * c2, * c3;
+ c1 = strrchr(e->tracefile->name,'\\');
+ c2 = strrchr(e->tracefile->name,'/');
+ if(c1 == NULL && c2 == NULL){
+ return (unsigned)atoi(e->tracefile->name);
+ }else if(c1 == NULL){
+ c2++;
+ return (unsigned)atoi(c2);
+ }else if(c2 == NULL){
+ c1++;
+ return (unsigned)atoi(c1);
+ }else{
+ c3 = (c1 > c2) ? c1 : c2;
+ c3++;
+ return (unsigned)atoi(c3);
+ }
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_data : get the raw data for the event
+ *Input params
+ * e : an instance of an event type
+ *Return value
+ * void * : pointer to the raw data for the event
+ ****************************************************************************/
+
+void *ltt_event_data(LttEvent *e)
+{
+ return e->data;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_field_element_number
+ * : The number of elements in a sequence field is specific
+ * to each event. This function returns the number of
+ * elements for an array or sequence field in an event.
+ *Input params
+ * e : an instance of an event type
+ * f : a field of the instance
+ *Return value
+ * unsigned : the number of elements for an array/sequence field
+ ****************************************************************************/
+
+unsigned ltt_event_field_element_number(LttEvent *e, LttField *f)
+{
+ if(f->field_type->type_class != LTT_ARRAY &&
+ f->field_type->type_class != LTT_SEQUENCE)
+ return 0;
+
+ if(f->field_type->type_class == LTT_ARRAY)
+ return f->field_type->element_number;
+ return (unsigned) getIntNumber(e->tracefile->trace->reverse_byte_order,
+ f->sequ_number_size, e + f->offset_root);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_event_field_element_select
+ * : Set the currently selected element for a sequence or
+ * array field
+ *Input params
+ * e : an instance of an event type
+ * f : a field of the instance
+ * i : the ith element
+ ****************************************************************************/
+
+void ltt_event_field_element_select(LttEvent *e, LttField *f, unsigned i)
+{
+ unsigned element_number;
+ LttField *fld;
+ unsigned int k;
+ int size;
+ void *evD;
+
+ if(f->field_type->type_class != LTT_ARRAY &&
+ f->field_type->type_class != LTT_SEQUENCE)
+ return ;
+
+ element_number = ltt_event_field_element_number(e,f);
+ /* Sanity check for i : 1..n only, and must be lower or equal element_number
+ */
+ if(element_number < i || i == 0) return;
+
+ fld = f->child[0];
+
+ evD = e->data + f->offset_root;
+ size = 0;
+ for(k=0;k<i;k++){
+ size += ltt_event_refresh_fields(f->offset_root+size,size, fld, evD+size,
+ e->tracefile->trace->reverse_byte_order);
+ }
+ f->current_element = i - 1;
+}
+
+/*****************************************************************************
+ * These functions extract data from an event after architecture specific
+ * conversions
+ ****************************************************************************/
+
+guint32 ltt_event_get_unsigned(LttEvent *e, LttField *f)
+{
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+
+ LttTypeEnum t = f->field_type->type_class;
+
+ g_assert(t == LTT_UINT || t == LTT_ENUM);
+
+ if(f->field_size == 1){
+ guint8 x = *(guint8 *)(e->data + f->offset_root);
+ return (guint32) x;
+ }else if(f->field_size == 2){
+ return (guint32)ltt_get_uint16(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 4){
+ return (guint32)ltt_get_uint32(reverse_byte_order, e->data + f->offset_root);
+ }
+#if 0
+ else if(f->field_size == 8){
+ guint64 x = *(guint64 *)(e->data + f->offset_root);
+ if(e->tracefile->trace->my_arch_endian == LTT_LITTLE_ENDIAN)
+ return (unsigned int) (revFlag ? GUINT64_FROM_BE(x): x);
+ else
+ return (unsigned int) (revFlag ? GUINT64_FROM_LE(x): x);
+ }
+#endif //0
+ g_critical("ltt_event_get_unsigned : field size %i unknown", f->field_size);
+ return 0;
+}
+
+gint32 ltt_event_get_int(LttEvent *e, LttField *f)
+{
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+
+ g_assert(f->field_type->type_class == LTT_INT);
+
+ if(f->field_size == 1){
+ gint8 x = *(gint8 *)(e->data + f->offset_root);
+ return (gint32) x;
+ }else if(f->field_size == 2){
+ return (gint32)ltt_get_int16(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 4){
+ return (gint32)ltt_get_int32(reverse_byte_order, e->data + f->offset_root);
+ }
+#if 0
+ else if(f->field_size == 8){
+ gint64 x = *(gint64 *)(e->data + f->offset_root);
+ if(e->tracefile->trace->my_arch_endian == LTT_LITTLE_ENDIAN)
+ return (int) (revFlag ? GINT64_FROM_BE(x): x);
+ else
+ return (int) (revFlag ? GINT64_FROM_LE(x): x);
+ }
+#endif //0
+ g_critical("ltt_event_get_int : field size %i unknown", f->field_size);
+ return 0;
+}
+
+guint64 ltt_event_get_long_unsigned(LttEvent *e, LttField *f)
+{
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+ LttTypeEnum t = f->field_type->type_class;
+
+ g_assert(t == LTT_UINT || t == LTT_ENUM);
+
+ if(f->field_size == 1){
+ guint8 x = *(guint8 *)(e->data + f->offset_root);
+ return (guint64) x;
+ }else if(f->field_size == 2){
+ return (guint64)ltt_get_uint16(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 4){
+ return (guint64)ltt_get_uint32(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 8){
+ return ltt_get_uint64(reverse_byte_order, e->data + f->offset_root);
+ }
+ g_critical("ltt_event_get_long_unsigned : field size %i unknown", f->field_size);
+ return 0;
+}
+
+gint64 ltt_event_get_long_int(LttEvent *e, LttField *f)
+{
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+
+ g_assert( f->field_type->type_class == LTT_INT);
+
+ if(f->field_size == 1){
+ gint8 x = *(gint8 *)(e->data + f->offset_root);
+ return (gint64) x;
+ }else if(f->field_size == 2){
+ return (gint64)ltt_get_int16(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 4){
+ return (gint64)ltt_get_int32(reverse_byte_order, e->data + f->offset_root);
+ }else if(f->field_size == 8){
+ return ltt_get_int64(reverse_byte_order, e->data + f->offset_root);
+ }
+ g_critical("ltt_event_get_long_int : field size %i unknown", f->field_size);
+ return 0;
+}
+
+float ltt_event_get_float(LttEvent *e, LttField *f)
+{
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+
+ g_assert(f->field_type->type_class == LTT_FLOAT && f->field_size == 4);
+
+ if(reverse_byte_order == 0) return *(float *)(e->data + f->offset_root);
+ else{
+ guint32 aInt;
+ memcpy((void*)&aInt, e->data + f->offset_root, 4);
+ aInt = ___swab32(aInt);
+ return ((float)aInt);
+ }
+}
+
+double ltt_event_get_double(LttEvent *e, LttField *f)
+{
+ gboolean reverse_byte_order = e->tracefile->trace->reverse_byte_order;
+ //int revFlag = e->tracefile->trace->my_arch_endian ==
+ // e->tracefile->trace->system_description->endian ? 0:1;
+
+ g_assert(f->field_type->type_class == LTT_FLOAT && f->field_size == 8);
+
+ if(reverse_byte_order == 0) return *(double *)(e->data + f->offset_root);
+ else{
+ guint64 aInt;
+ memcpy((void*)&aInt, e->data + f->offset_root, 8);
+ aInt = ___swab64(aInt);
+ return ((double)aInt);
+ }
+}
+
+/*****************************************************************************
+ * The string obtained is only valid until the next read from
+ * the same tracefile.
+ ****************************************************************************/
+
+char *ltt_event_get_string(LttEvent *e, LttField *f)
+{
+ g_assert(f->field_type->type_class == LTT_STRING);
+
+ return (gchar*)g_strdup((gchar*)(e->data + f->offset_root));
+}
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef EVENT_H
+#define EVENT_H
+
+#include <ltt/ltt.h>
+
+LttEvent *ltt_event_new();
+
+void ltt_event_destroy(LttEvent *event);
+
+/* Events and their content, including the raw data, are only valid
+ until reading another event from the same tracefile.
+ Indeed, since event reading is critical to the performance,
+ the memory associated with an event may be reused at each read. */
+
+/* Obtain the trace unique integer id associated with the type of
+ this event */
+
+unsigned ltt_event_eventtype_id(LttEvent *e);
+
+
+/* Facility and type for the event */
+
+LttFacility *ltt_event_facility(LttEvent *e);
+
+LttEventType *ltt_event_eventtype(LttEvent *e);
+
+
+/* Root field for the event */
+
+LttField *ltt_event_field(LttEvent *e);
+
+
+/* Time and cycle count for the event */
+
+LttTime ltt_event_time(LttEvent *e);
+
+LttCycleCount ltt_event_cycle_count(LttEvent *e);
+
+
+/* Obtain the position of the event within the tracefile. This
+ is used to seek back to this position later or to seek to another
+ position, computed relative to this position. The event position
+ structure is opaque and contains several fields, only two
+ of which are user accessible: block number and event index
+ within the block. */
+
+void ltt_event_position(LttEvent *e, LttEventPosition *ep);
+
+LttEventPosition * ltt_event_position_new();
+
+void ltt_event_position_get(LttEventPosition *ep,
+ unsigned *block_number, unsigned *index_in_block, LttTracefile ** tf);
+
+void ltt_event_position_set(LttEventPosition *ep,
+ unsigned block_number, unsigned index_in_block);
+
+gint ltt_event_position_compare(const LttEventPosition *ep1,
+ const LttEventPosition *ep2);
+
+gint ltt_event_event_position_compare(const LttEvent *event,
+ const LttEventPosition *ep);
+
+void ltt_event_position_copy(LttEventPosition *dest,
+ const LttEventPosition *src);
+
+/* CPU id of the event */
+
+unsigned ltt_event_cpu_id(LttEvent *e);
+
+
+/* Pointer to the raw data for the event. This should not be used directly
+ unless prepared to do all the architecture specific conversions. */
+
+void *ltt_event_data(LttEvent *e);
+
+
+/* The number of elements in a sequence field is specific to each event
+ instance. This function returns the number of elements for an array or
+ sequence field in an event. */
+
+unsigned ltt_event_field_element_number(LttEvent *e, LttField *f);
+
+
+/* Set the currently selected element for a sequence or array field. */
+
+void ltt_event_field_element_select(LttEvent *e, LttField *f, unsigned i);
+
+
+/* A union is like a structure except that only a single member at a time
+ is present depending on the specific event instance. This function tells
+ the active member for a union field in an event. */
+
+unsigned ltt_event_field_union_member(LttEvent *e, LttField *f);
+
+
+/* These functions extract data from an event after architecture specific
+ conversions. */
+
+guint32 ltt_event_get_unsigned(LttEvent *e, LttField *f);
+
+gint32 ltt_event_get_int(LttEvent *e, LttField *f);
+
+guint64 ltt_event_get_long_unsigned(LttEvent *e, LttField *f);
+
+gint64 ltt_event_get_long_int(LttEvent *e, LttField *f);
+
+float ltt_event_get_float(LttEvent *e, LttField *f);
+
+double ltt_event_get_double(LttEvent *e, LttField *f);
+
+
+/* The string obtained is only valid until the next read from
+ the same tracefile. */
+
+gchar *ltt_event_get_string(LttEvent *e, LttField *f);
+
+#endif // EVENT_H
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Xiangxiu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+
+#include "parser.h"
+#include <ltt/ltt.h>
+#include "ltt-private.h"
+#include <ltt/facility.h>
+
+#ifndef g_open
+#define g_open open
+#endif
+
+#define g_close close
+
+/* search for the (named) type in the table, if it does not exist
+ create a new one */
+LttType * lookup_named_type(LttFacility *fac, type_descriptor * td);
+
+/* construct directed acyclic graph for types, and tree for fields */
+void constructTypeAndFields(LttFacility * fac,type_descriptor * td,
+ LttField * fld);
+
+/* generate the facility according to the events belongin to it */
+void generateFacility(LttFacility * f, facility_t * fac,
+ LttChecksum checksum);
+
+/* functions to release the memory occupied by a facility */
+void freeFacility(LttFacility * facility);
+void freeEventtype(LttEventType * evType);
+void freeLttType(LttType ** type);
+void freeLttField(LttField * fld);
+void freeLttNamedType(LttType * type);
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_open : open facilities
+ *Input params
+ * t : the trace containing the facilities
+ * pathname : the path name of the facility
+ ****************************************************************************/
+
+void ltt_facility_open(LttTrace * t, gchar * pathname)
+{
+ gchar *token;
+ parse_file in;
+ gsize length;
+ facility_t * fac;
+ LttFacility * f;
+ LttChecksum checksum;
+ GError * error = NULL;
+ gchar buffer[BUFFER_SIZE];
+
+ in.buffer = &(buffer[0]);
+ in.lineno = 0;
+ in.error = error_callback;
+ in.name = pathname;
+
+ in.fd = g_open(in.name, O_RDONLY, 0);
+ if(in.fd < 0 ) in.error(&in,"cannot open input file");
+
+ in.channel = g_io_channel_unix_new(in.fd);
+ in.pos = 0;
+
+ while(1){
+ token = getToken(&in);
+ if(in.type == ENDFILE) break;
+
+ if(g_ascii_strcasecmp(token, "<")) in.error(&in,"not a facility file");
+ token = getName(&in);
+
+ if(g_ascii_strcasecmp("facility",token) == 0) {
+ fac = g_new(facility_t, 1);
+ fac->name = NULL;
+ fac->description = NULL;
+ sequence_init(&(fac->events));
+ table_init(&(fac->named_types));
+ sequence_init(&(fac->unnamed_types));
+
+ parseFacility(&in, fac);
+
+ //check if any namedType is not defined
+ g_assert(checkNamedTypesImplemented(&fac->named_types) == 0);
+
+ g_assert(generateChecksum(fac->name, &checksum, &fac->events) == 0);
+
+ f = g_new(LttFacility,1);
+ f->base_id = 0;
+ generateFacility(f, fac, checksum);
+
+ t->facility_number++;
+ g_ptr_array_add(t->facilities,f);
+
+ g_free(fac->name);
+ g_free(fac->description);
+ freeEvents(&fac->events);
+ sequence_dispose(&fac->events);
+ freeNamedType(&fac->named_types);
+ table_dispose(&fac->named_types);
+ freeTypes(&fac->unnamed_types);
+ sequence_dispose(&fac->unnamed_types);
+ g_free(fac);
+ }
+ else in.error(&in,"facility token was expected");
+ }
+
+ g_io_channel_shutdown(in.channel, FALSE, &error); /* No flush */
+ if(error != NULL) {
+ g_warning("Can not close file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+
+ g_close(in.fd);
+}
+
+
+/*****************************************************************************
+ *Function name
+ * generateFacility : generate facility, internal function
+ *Input params
+ * facility : LttFacilty structure
+ * fac : facility structure
+ * checksum : checksum of the facility
+ ****************************************************************************/
+
+void generateFacility(LttFacility *f, facility_t *fac,LttChecksum checksum)
+{
+ char * facilityName = fac->name;
+ sequence * events = &fac->events;
+ int i;
+ LttEventType * evType;
+ LttField * field;
+ LttType * type;
+
+ f->name = g_strdup(facilityName);
+ f->event_number = events->position;
+ f->checksum = checksum;
+
+ //initialize inner structures
+ f->events = g_new(LttEventType*,f->event_number);
+ f->named_types_number = fac->named_types.keys.position;
+ f->named_types = g_new(LttType*, fac->named_types.keys.position);
+ for(i=0;i<fac->named_types.keys.position;i++) f->named_types[i] = NULL;
+
+ //for each event, construct field tree and type graph
+ for(i=0;i<events->position;i++){
+ evType = g_new(LttEventType,1);
+ f->events[i] = evType;
+
+ evType->name = g_strdup(((event_t*)(events->array[i]))->name);
+ evType->description=g_strdup(((event_t*)(events->array[i]))->description);
+
+ field = g_new(LttField, 1);
+ evType->root_field = field;
+ evType->facility = f;
+ evType->index = i;
+
+ if(((event_t*)(events->array[i]))->type != NULL){
+ field->field_pos = 0;
+ type = lookup_named_type(f,((event_t*)(events->array[i]))->type);
+ field->field_type = type;
+ field->offset_root = 0;
+ field->fixed_root = 1;
+ field->offset_parent = 0;
+ field->fixed_parent = 1;
+ // field->base_address = NULL;
+ field->field_size = 0;
+ field->field_fixed = -1;
+ field->parent = NULL;
+ field->child = NULL;
+ field->current_element = 0;
+
+ //construct field tree and type graph
+ constructTypeAndFields(f,((event_t*)(events->array[i]))->type,field);
+ }else{
+ evType->root_field = NULL;
+ g_free(field);
+ }
+ }
+}
+
+
+/*****************************************************************************
+ *Function name
+ * constructTypeAndFields : construct field tree and type graph,
+ * internal recursion function
+ *Input params
+ * fac : facility struct
+ * td : type descriptor
+ * root_field : root field of the event
+ ****************************************************************************/
+
+void constructTypeAndFields(LttFacility * fac,type_descriptor * td,
+ LttField * fld)
+{
+ int i, flag;
+ type_descriptor * tmpTd;
+
+ // if(td->type == LTT_STRING || td->type == LTT_SEQUENCE)
+ // fld->field_size = 0;
+ // else fld->field_size = -1;
+
+ if(td->type == LTT_ENUM){
+ fld->field_type->element_number = td->labels.position;
+ fld->field_type->enum_strings = g_new(char*,td->labels.position);
+ for(i=0;i<td->labels.position;i++){
+ fld->field_type->enum_strings[i]
+ = g_strdup(((char*)(td->labels.array[i])));
+ }
+ }else if(td->type == LTT_ARRAY || td->type == LTT_SEQUENCE){
+ if(td->type == LTT_ARRAY)
+ fld->field_type->element_number = (unsigned)td->size;
+ fld->field_type->element_type = g_new(LttType*,1);
+ tmpTd = td->nested_type;
+ fld->field_type->element_type[0] = lookup_named_type(fac, tmpTd);
+ fld->child = g_new(LttField*, 1);
+ fld->child[0] = g_new(LttField, 1);
+
+ fld->child[0]->field_pos = 0;
+ fld->child[0]->field_type = fld->field_type->element_type[0];
+ fld->child[0]->offset_root = fld->offset_root;
+ fld->child[0]->fixed_root = fld->fixed_root;
+ fld->child[0]->offset_parent = 0;
+ fld->child[0]->fixed_parent = 1;
+ // fld->child[0]->base_address = NULL;
+ fld->child[0]->field_size = 0;
+ fld->child[0]->field_fixed = -1;
+ fld->child[0]->parent = fld;
+ fld->child[0]->child = NULL;
+ fld->child[0]->current_element = 0;
+ constructTypeAndFields(fac, tmpTd, fld->child[0]);
+ }else if(td->type == LTT_STRUCT){
+ fld->field_type->element_number = td->fields.position;
+
+ if(fld->field_type->element_type == NULL){
+ fld->field_type->element_type = g_new(LttType*, td->fields.position);
+ flag = 1;
+ }else{
+ flag = 0;
+ }
+
+ fld->child = g_new(LttField*, td->fields.position);
+ for(i=0;i<td->fields.position;i++){
+ tmpTd = ((type_fields*)(td->fields.array[i]))->type;
+
+ if(flag)
+ fld->field_type->element_type[i] = lookup_named_type(fac, tmpTd);
+ fld->child[i] = g_new(LttField,1);
+
+ fld->child[i]->field_pos = i;
+ fld->child[i]->field_type = fld->field_type->element_type[i];
+
+ if(flag){
+ fld->child[i]->field_type->element_name
+ = g_strdup(((type_fields*)(td->fields.array[i]))->name);
+ }
+
+ fld->child[i]->offset_root = -1;
+ fld->child[i]->fixed_root = -1;
+ fld->child[i]->offset_parent = -1;
+ fld->child[i]->fixed_parent = -1;
+ // fld->child[i]->base_address = NULL;
+ fld->child[i]->field_size = 0;
+ fld->child[i]->field_fixed = -1;
+ fld->child[i]->parent = fld;
+ fld->child[i]->child = NULL;
+ fld->child[i]->current_element = 0;
+ constructTypeAndFields(fac, tmpTd, fld->child[i]);
+ }
+ }
+}
+
+
+/*****************************************************************************
+ *Function name
+ * lookup_named_type: search named type in the table
+ * internal function
+ *Input params
+ * fac : facility struct
+ * td : type descriptor
+ *Return value
+ * : either find the named type, or create a new LttType
+ ****************************************************************************/
+
+LttType * lookup_named_type(LttFacility *fac, type_descriptor * td)
+{
+ LttType * lttType = NULL;
+ unsigned int i=0;
+ gchar * name;
+
+ if(td->type_name){
+ for(i=0;i<fac->named_types_number; i++){
+ if(fac->named_types[i] == NULL) break;
+ name = fac->named_types[i]->type_name;
+ if(g_ascii_strcasecmp(name, td->type_name)==0){
+ lttType = fac->named_types[i];
+ // if(lttType->element_name) g_free(lttType->element_name);
+ // lttType->element_name = NULL;
+ break;
+ }
+ }
+ }
+
+ if(!lttType){
+ lttType = g_new(LttType,1);
+ lttType->type_class = td->type;
+ if(td->fmt) lttType->fmt = g_strdup(td->fmt);
+ else lttType->fmt = NULL;
+ lttType->size = td->size;
+ lttType->enum_strings = NULL;
+ lttType->element_type = NULL;
+ lttType->element_number = 0;
+ lttType->element_name = NULL;
+ if(td->type_name){
+ lttType->type_name = g_strdup(td->type_name);
+ fac->named_types[i] = lttType; /* i is initialized, checked. */
+ }
+ else{
+ lttType->type_name = NULL;
+ }
+ }
+
+ return lttType;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_close : close a facility, decrease its usage count,
+ * if usage count = 0, release the memory
+ *Input params
+ * f : facility that will be closed
+ *Return value
+ * int : usage count ?? status
+ ****************************************************************************/
+
+int ltt_facility_close(LttFacility *f)
+{
+ //release the memory it occupied
+ freeFacility(f);
+
+ return 0;
+}
+
+/*****************************************************************************
+ * Functions to release the memory occupied by the facility
+ ****************************************************************************/
+
+void freeFacility(LttFacility * fac)
+{
+ unsigned int i;
+ g_free(fac->name); //free facility name
+
+ //free event types
+ for(i=0;i<fac->event_number;i++){
+ freeEventtype(fac->events[i]);
+ }
+ g_free(fac->events);
+
+ //free all named types
+ for(i=0;i<fac->named_types_number;i++){
+ freeLttNamedType(fac->named_types[i]);
+ fac->named_types[i] = NULL;
+ }
+ g_free(fac->named_types);
+
+ //free the facility itself
+ g_free(fac);
+}
+
+void freeEventtype(LttEventType * evType)
+{
+ LttType * root_type;
+ g_free(evType->name);
+ if(evType->description)
+ g_free(evType->description);
+ if(evType->root_field){
+ root_type = evType->root_field->field_type;
+ freeLttField(evType->root_field);
+ freeLttType(&root_type);
+ }
+
+ g_free(evType);
+}
+
+void freeLttNamedType(LttType * type)
+{
+ g_free(type->type_name);
+ type->type_name = NULL;
+ freeLttType(&type);
+}
+
+void freeLttType(LttType ** type)
+{
+ unsigned int i;
+ if(*type == NULL) return;
+ if((*type)->type_name){
+ return; //this is a named type
+ }
+ if((*type)->element_name)
+ g_free((*type)->element_name);
+ if((*type)->fmt)
+ g_free((*type)->fmt);
+ if((*type)->enum_strings){
+ for(i=0;i<(*type)->element_number;i++)
+ g_free((*type)->enum_strings[i]);
+ g_free((*type)->enum_strings);
+ }
+
+ if((*type)->element_type){
+ for(i=0;i<(*type)->element_number;i++)
+ freeLttType(&((*type)->element_type[i]));
+ g_free((*type)->element_type);
+ }
+ g_free(*type);
+ *type = NULL;
+}
+
+void freeLttField(LttField * fld)
+{
+ int i;
+ int size = 0;
+
+ if(fld->field_type){
+ if(fld->field_type->type_class == LTT_ARRAY ||
+ fld->field_type->type_class == LTT_SEQUENCE){
+ size = 1;
+ }else if(fld->field_type->type_class == LTT_STRUCT){
+ size = fld->field_type->element_number;
+ }
+ }
+
+ if(fld->child){
+ for(i=0; i<size; i++){
+ if(fld->child[i])freeLttField(fld->child[i]);
+ }
+ g_free(fld->child);
+ }
+ g_free(fld);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_name : obtain the facility's name
+ *Input params
+ * f : the facility that will be closed
+ *Return value
+ * char * : the facility's name
+ ****************************************************************************/
+
+gchar *ltt_facility_name(LttFacility *f)
+{
+ return f->name;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_checksum : obtain the facility's checksum
+ *Input params
+ * f : the facility that will be closed
+ *Return value
+ * LttChecksum : the checksum of the facility
+ ****************************************************************************/
+
+LttChecksum ltt_facility_checksum(LttFacility *f)
+{
+ return f->checksum;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_base_id : obtain the facility base id
+ *Input params
+ * f : the facility
+ *Return value
+ * : the base id of the facility
+ ****************************************************************************/
+
+unsigned ltt_facility_base_id(LttFacility *f)
+{
+ return f->base_id;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_eventtype_number: obtain the number of the event types
+ *Input params
+ * f : the facility that will be closed
+ *Return value
+ * unsigned : the number of the event types
+ ****************************************************************************/
+
+unsigned ltt_facility_eventtype_number(LttFacility *f)
+{
+ return (f->event_number);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_eventtype_get: obtain the event type according to event id
+ * from 0 to event_number - 1
+ *Input params
+ * f : the facility that will be closed
+ *Return value
+ * LttEventType * : the event type required
+ ****************************************************************************/
+
+LttEventType *ltt_facility_eventtype_get(LttFacility *f, unsigned i)
+{
+ return f->events[i];
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_facility_eventtype_get_by_name
+ * : obtain the event type according to event name
+ * event name is unique in the facility
+ *Input params
+ * f : the facility
+ * name : the name of the event
+ *Return value
+ * LttEventType * : the event type required
+ ****************************************************************************/
+
+LttEventType *ltt_facility_eventtype_get_by_name(LttFacility *f, gchar *name)
+{
+ unsigned int i;
+ LttEventType * ev = NULL;
+
+ for(i=0;i<f->event_number;i++){
+ LttEventType *iter_ev = f->events[i];
+ if(g_ascii_strcasecmp(iter_ev->name, name) == 0) {
+ ev = iter_ev;
+ break;
+ }
+ }
+ return ev;
+}
+
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FACILITY_H
+#define FACILITY_H
+
+#include <ltt/ltt.h>
+
+/* Facilities are obtained from an opened trace. The structures associated
+ with a facility are released when the trace is closed. Each facility
+ is characterized by its name and checksum. */
+
+GQuark ltt_facility_name(LttFacility *f);
+
+LttChecksum ltt_facility_checksum(LttFacility *f);
+
+/* open facility */
+void ltt_facility_open(LttTrace * t, GQuark facility_name);
+
+/* Discover the event types within the facility. The event type integer id
+ relative to the trace is from 0 to nb_event_types - 1. The event
+ type id within the trace is the relative id + the facility base event
+ id. */
+
+unsigned ltt_facility_base_id(LttFacility *f);
+
+unsigned ltt_facility_eventtype_number(LttFacility *f);
+
+LttEventType *ltt_facility_eventtype_get(LttFacility *f, unsigned i);
+
+LttEventType *ltt_facility_eventtype_get_by_name(LttFacility *f, GQuark name);
+
+int ltt_facility_close(LttFacility *f);
+
+/* Reserved facility names */
+
+static const char *ltt_facility_name_core = "core";
+
+#endif // FACILITY_H
+
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Xiangxiu Yang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LTT_PRIVATE_H
+#define LTT_PRIVATE_H
+
+#include <glib.h>
+#include <sys/types.h>
+#include <ltt/ltt.h>
+
+#define LTT_MAGIC_NUMBER 0x00D6B7ED
+#define LTT_REV_MAGIC_NUMBER 0xEDB7D600
+
+#define NSEC_PER_USEC 1000
+
+#define LTT_PACKED_STRUCT __attribute__ ((packed))
+
+#if 0
+/* enumeration definition */
+
+typedef enum _BuildinEvent{
+ TRACE_FACILITY_LOAD = 0,
+ TRACE_BLOCK_START = 17,
+ TRACE_BLOCK_END = 18,
+ TRACE_TIME_HEARTBEAT= 19
+} BuildinEvent;
+
+
+/* structure definition */
+
+typedef struct _FacilityLoad{
+ gchar * name;
+ LttChecksum checksum;
+ guint32 base_code;
+} LTT_PACKED_STRUCT FacilityLoad;
+
+typedef struct _BlockStart {
+ LttTime time; //Time stamp of this block
+ LttCycleCount cycle_count; //cycle count of the event
+ guint32 block_id; //block id
+} LTT_PACKED_STRUCT BlockStart;
+
+typedef struct _BlockEnd {
+ LttTime time; //Time stamp of this block
+ LttCycleCount cycle_count; //cycle count of the event
+ guint32 block_id; //block id
+} LTT_PACKED_STRUCT BlockEnd;
+#endif //0
+
+
+typedef guint8 uint8_t;
+typedef guint16 uint16_t;
+typedef guint32 uint32_t;
+typedef guint64 uint64_t;
+
+typedef struct _TimeHeartbeat {
+ LttTime time; //Time stamp of this block
+ uint64_t cycle_count; //cycle count of the event
+} LTT_PACKED_STRUCT TimeHeartbeat;
+
+struct ltt_event_header_hb {
+ uint32_t timestamp;
+ unsigned char facility_id;
+ unsigned char event_id;
+ uint16_t event_size;
+} __attribute((aligned(8)));
+
+struct ltt_event_header_nohb {
+ uint64_t timestamp;
+ unsigned char facility_id;
+ unsigned char event_id;
+ uint16_t event_size;
+} __attribute((aligned(8)));
+
+struct ltt_trace_header {
+ uint32_t magic_number;
+ uint32_t arch_type;
+ uint32_t arch_variant;
+ uint8_t arch_size;
+ //uint32_t system_type;
+ uint8_t major_version;
+ uint8_t minor_version;
+ uint8_t flight_recorder;
+ uint8_t has_heartbeat;
+ uint8_t has_alignment; /* Event header alignment */
+ uint8_t has_tsc;
+} __attribute((aligned(8)));
+
+
+struct ltt_block_start_header {
+ struct {
+ struct timeval timestamp;
+ uint64_t cycle_count;
+ } begin;
+ struct {
+ struct timeval timestamp;
+ uint64_t cycle_count;
+ } end;
+ uint32_t lost_size; /* Size unused at the end of the buffer */
+ uint32_t buf_size; /* The size of this sub-buffer */
+ struct ltt_trace_header trace;
+} __attribute((aligned(8)));
+
+
+struct _LttType{
+ GQuark type_name; //type name if it is a named type
+ GQuark element_name; //elements name of the struct
+ gchar * fmt;
+ unsigned int size;
+ LttTypeEnum type_class; //which type
+ gchar ** enum_strings; //for enum labels
+ struct _LttType ** element_type; //for array, sequence and struct
+ unsigned element_number; //the number of elements
+ //for enum, array, sequence and structure
+};
+
+struct _LttEventType{
+ gchar * name;
+ gchar * description;
+ int index; //id of the event type within the facility
+ LttFacility * facility; //the facility that contains the event type
+ LttField * root_field; //root field
+ //unsigned int latest_block; //the latest block using the event type
+ //unsigned int latest_event; //the latest event using the event type
+};
+
+struct _LttEvent{
+
+ /* Where is this event ? */
+ LttTracefile *tracefile;
+ unsigned int block;
+ void *offset;
+
+ union { /* choice by trace has_tsc */
+ guint32 timestamp; /* truncated timestamp */
+ guint32 delta;
+ } time;
+
+ unsigned char facility_id; /* facility ID are never reused. */
+ unsigned char event_id;
+
+ LttTime event_time;
+
+ void * data; //event data
+
+ int count; //the number of overflow of cycle count
+ gint64 overflow_nsec; //precalculated nsec for overflows
+ TimeHeartbeat * last_heartbeat; //last heartbeat
+};
+
+
+struct _LttField{
+ unsigned field_pos; //field position within its parent
+ LttType * field_type; //field type, if it is root field
+ //then it must be struct type
+
+ off_t offset_root; //offset from the root, -1:uninitialized
+ short fixed_root; //offset fixed according to the root
+ //-1:uninitialized, 0:unfixed, 1:fixed
+ off_t offset_parent; //offset from the parent,-1:uninitialized
+ short fixed_parent; //offset fixed according to its parent
+ //-1:uninitialized, 0:unfixed, 1:fixed
+ // void * base_address; //base address of the field ????
+
+ int field_size; //>0: size of the field,
+ //0 : uncertain
+ //-1: uninitialize
+ int sequ_number_size; //the size of unsigned used to save the
+ //number of elements in the sequence
+
+ int element_size; //the element size of the sequence
+ int field_fixed; //0: field has string or sequence
+ //1: field has no string or sequenc
+ //-1: uninitialize
+
+ struct _LttField * parent;
+ struct _LttField ** child; //for array, sequence and struct:
+ //list of fields, it may have only one
+ //field if the element is not a struct
+ unsigned current_element; //which element is currently processed
+};
+
+
+struct _LttFacility{
+ //gchar * name; //facility name
+ GQuark name;
+ unsigned int event_number; //number of events in the facility
+ guint32 checksum; //checksum of the facility
+ //guint32 base_id; //base id of the facility
+ LttEventType ** events; //array of event types
+ LttType ** named_types;
+ unsigned int named_types_number;
+};
+
+typedef struct _LttBuffer {
+ void * head;
+ unsigned int index;
+
+ struct {
+ struct timeval timestamp;
+ uint64_t cycle_count;
+ } begin;
+ struct {
+ struct timeval timestamp;
+ uint64_t cycle_count;
+ } end;
+ uint32_t lost_size; /* Size unused at the end of the buffer */
+
+ /* Timekeeping */
+ uint64_t tsc; /* Current timestamp counter */
+ double nsecs_per_cycle;
+} LttBuffer;
+
+struct _LttTracefile{
+ gboolean cpu_online; //is the cpu online ?
+ GQuark name; //tracefile name
+ LttTrace * trace; //trace containing the tracefile
+ int fd; //file descriptor
+ off_t file_size; //file size
+ unsigned block_size; //block_size
+ unsigned int num_blocks; //number of blocks in the file
+ gboolean reverse_bo; //must we reverse byte order ?
+
+ /* Current event */
+ LttEvent event; //Event currently accessible in the trace
+
+ /* Current block */
+ LttBuffer buffer; //current buffer
+ guint32 buf_size; /* The size of blocks */
+
+ /* Time flow */
+ //unsigned int count; //the number of overflow of cycle count
+ //double nsec_per_cycle; //Nsec per cycle
+ //TimeHeartbeat * last_heartbeat; //last heartbeat
+
+ //LttCycleCount cycles_per_nsec_reciprocal; // Optimisation for speed
+ //void * last_event_pos;
+
+ //LttTime prev_block_end_time; //the end time of previous block
+ //LttTime prev_event_time; //the time of the previous event
+ //LttCycleCount pre_cycle_count; //previous cycle count of the event
+};
+
+struct _LttTrace{
+ GQuark pathname; //the pathname of the trace
+ guint facility_number; //the number of facilities
+ //LttSystemDescription * system_description;//system description
+
+ //GPtrArray *control_tracefiles; //array of control tracefiles
+ //GPtrArray *per_cpu_tracefiles; //array of per cpu tracefiles
+ GPtrArray *facilities; //array of facilities
+ guint8 ltt_major_version;
+ guint8 ltt_minor_version;
+ guint8 flight_recorder;
+ guint8 has_heartbeat;
+ // guint8 alignment;
+ guint8 has_tsc;
+
+ GData *tracefiles; //tracefiles groups
+};
+
+struct _LttEventPosition{
+ LttTracefile *tracefile;
+ unsigned int block;
+ void *offset;
+
+ /* Timekeeping */
+ uint64_t tsc; /* Current timestamp counter */
+};
+
+/* The characteristics of the system on which the trace was obtained
+ is described in a LttSystemDescription structure. */
+
+struct _LttSystemDescription {
+ gchar *description;
+ gchar *node_name;
+ gchar *domain_name;
+ unsigned nb_cpu;
+ LttArchSize size;
+ LttArchEndian endian;
+ gchar *kernel_name;
+ gchar *kernel_release;
+ gchar *kernel_version;
+ gchar *machine;
+ gchar *processor;
+ gchar *hardware_platform;
+ gchar *operating_system;
+ //unsigned ltt_block_size;
+ LttTime trace_start;
+ LttTime trace_end;
+};
+
+/*****************************************************************************
+ macro for size of some data types
+ *****************************************************************************/
+// alignment -> dynamic!
+
+//#define TIMESTAMP_SIZE sizeof(guint32)
+//#define EVENT_ID_SIZE sizeof(guint16)
+//#define EVENT_HEADER_SIZE (TIMESTAMP_SIZE + EVENT_ID_SIZE)
+
+#define LTT_GET_BO(t) ((t)->reverse_bo)
+
+
+#endif /* LTT_PRIVATE_H */
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2004-2005 Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LTT_TYPES_H
+#define LTT_TYPES_H
+
+/* Set of functions to access the types portably, given the trace as parameter.
+ * */
+
+#include <ltt/ltt.h>
+//#include <ltt/ltt-private.h>
+#include <glib.h>
+#include <ltt/time.h>
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_get_int64 : get a 64 bits integer number
+ *Input params
+ * ptr : pointer to the integer
+ *Return value
+ * gint64 : a 64 bits integer
+ *
+ * Takes care of endianness
+ *
+ ****************************************************************************/
+
+static inline gint64 ltt_get_int64(gboolean reverse_byte_order, void *ptr)
+{
+ guint64 value = *(guint64*)ptr;
+ return (gint64) (reverse_byte_order ? GUINT64_SWAP_LE_BE(value): value);
+}
+
+
+static inline guint64 ltt_get_uint64(gboolean reverse_byte_order, void *ptr)
+{
+ guint64 value = *(guint64*)ptr;
+ return (guint64) (reverse_byte_order ? GUINT64_SWAP_LE_BE(value): value);
+}
+
+static inline gint32 ltt_get_int32(gboolean reverse_byte_order, void *ptr)
+{
+ guint32 value = *(guint32*)ptr;
+ return (gint32) (reverse_byte_order ? GUINT32_SWAP_LE_BE(value): value);
+}
+
+static inline guint32 ltt_get_uint32(gboolean reverse_byte_order, void *ptr)
+{
+ guint32 value = *(guint32*)ptr;
+ return (guint32) (reverse_byte_order ? GUINT32_SWAP_LE_BE(value): value);
+}
+
+static inline gint16 ltt_get_int16(gboolean reverse_byte_order, void *ptr)
+{
+ guint16 value = *(guint16*)ptr;
+ return (gint16) (reverse_byte_order ? GUINT16_SWAP_LE_BE(value): value);
+}
+
+static inline guint16 ltt_get_uint16(gboolean reverse_byte_order, void *ptr)
+{
+ guint16 value = *(guint16*)ptr;
+ return (guint16) (reverse_byte_order ? GUINT16_SWAP_LE_BE(value): value);
+}
+
+static inline LttTime ltt_get_time(gboolean reverse_byte_order, void *ptr)
+{
+ LttTime output;
+
+ output.tv_sec = ltt_get_uint32(reverse_byte_order, ptr);
+ ptr += sizeof(guint32);
+ output.tv_nsec = ltt_get_uint32(reverse_byte_order, ptr);
+
+ return output;
+}
+
+#endif // LTT_TYPES_H
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef LTT_H
+#define LTT_H
+
+#include <glib.h>
+#include <ltt/time.h>
+#include <ltt/compiler.h>
+
+/* A trace is associated with a tracing session run on a single, possibly
+ multi-cpu, system. It is defined as a pathname to a directory containing
+ all the relevant trace files. All the tracefiles for a trace were
+ generated in a single system for the same time period by the same
+ trace daemon. They simply contain different events. Typically control
+ tracefiles contain the important events (process creations and registering
+ tracing facilities) for all CPUs, and one file for each CPU contains all
+ the events for that CPU. All the tracefiles within the same trace directory
+ then use the exact same id numbers for event types.
+
+ A tracefile (LttTracefile) contains a list of events (LttEvent) sorted
+ by time for each CPU; events from different CPUs may be slightly out of
+ order, especially using the (possibly drifting) cycle counters as
+ time unit.
+
+ A facility is a list of event types (LttEventType), declared in a special
+ eventdefs file. A corresponding checksum differentiates different
+ facilities which would have the same name but a different content
+ (e.g., different versions). The files are stored within the trace
+ directory and are accessed automatically upon opening a trace.
+ The list of facilities (and associated checksum) used in a trace
+ must be known in order to properly decode the contained events. An event
+ is stored in the "facilities" control tracefile to denote each different
+ facility used.
+
+ Event types (LttEventType) refer to data types (LttType) describing
+ their content. The data types supported are integer and unsigned integer
+ (of various length), enumerations (a special form of unsigned integer),
+ floating point (of various length), fixed size arrays, sequence
+ (variable sized arrays), structures and null terminated strings.
+ The elements of arrays and sequences, and the data members for
+ structures, may be of any nested data type (LttType).
+
+ An LttField is a special object to denote a specific, possibly nested,
+ field within an event type. Suppose an event type socket_connect is a
+ structure containing two data members, source and destination, of type
+ socket_address. Type socket_address contains two unsigned integer
+ data members, ip and port. An LttField is different from a data type
+ structure member since it can denote a specific nested field, like the
+ source port, and store associated access information (byte offset within
+ the event data). The LttField objects are trace specific since the
+ contained information (byte offsets) may vary with the architecture
+ associated to the trace. */
+
+typedef struct _LttTrace LttTrace;
+
+typedef struct _LttTracefile LttTracefile;
+
+typedef struct _LttFacility LttFacility;
+
+typedef struct _LttEventType LttEventType;
+
+typedef struct _LttType LttType;
+
+typedef struct _LttField LttField;
+
+typedef struct _LttEvent LttEvent;
+
+typedef struct _LttSystemDescription LttSystemDescription;
+
+
+/* Checksums are used to differentiate facilities which have the same name
+ but differ. */
+
+//typedef guint32 LttChecksum;
+
+
+/* Events are usually stored with the easily obtained CPU clock cycle count,
+ ltt_cycle_count. This can be converted to the real time value, LttTime,
+ using linear interpolation between regularly sampled values (e.g. a few
+ times per second) of the real time clock with their corresponding
+ cycle count values. */
+
+
+typedef struct _TimeInterval{
+ LttTime start_time;
+ LttTime end_time;
+} TimeInterval;
+
+
+typedef guint64 LttCycleCount;
+
+
+/* Event positions are used to seek within a tracefile based on
+ the block number and event position within the block. */
+
+typedef struct _LttEventPosition LttEventPosition;
+
+
+/* Differences between architectures include word sizes, endianess,
+ alignment, floating point format and calling conventions. For a
+ packed binary trace, endianess and size matter, assuming that the
+ floating point format is standard (and is seldom used anyway). */
+
+typedef enum _LttArchSize
+{ LTT_LP32, LTT_ILP32, LTT_LP64, LTT_ILP64, LTT_UNKNOWN
+} LttArchSize;
+
+
+typedef enum _LttArchEndian
+{ LTT_LITTLE_ENDIAN, LTT_BIG_ENDIAN
+} LttArchEndian;
+
+typedef enum _LttTypeEnum
+{ LTT_INT, LTT_UINT, LTT_FLOAT, LTT_STRING, LTT_ENUM, LTT_ARRAY,
+ LTT_SEQUENCE, LTT_STRUCT, LTT_UNION
+} LttTypeEnum;
+
+
+#endif // LTT_H
--- /dev/null
+/*
+
+parser.c: Generate helper declarations and functions to trace events
+ from an event description file.
+
+Copyright (C) 2002, Xianxiu Yang
+Copyright (C) 2002, Michel Dagenais
+Copyright (C) 2005, Mathieu Desnoyers
+
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+the Free Software Foundation; version 2 of the License.
+
+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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* This program reads the ".xml" event definitions input files
+ and constructs structure for each event.
+
+ The program uses a very simple tokenizer, called from a hand written
+ recursive descent parser to fill a data structure describing the events.
+ The result is a sequence of events definitions which refer to type
+ definitions.
+
+ A table of named types is maintained to allow refering to types by name
+ when the same type is used at several places. Finally a sequence of
+ all types is maintained to facilitate the freeing of all type
+ information when the processing of an ".xml" file is finished. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <linux/errno.h>
+#include <glib.h>
+
+
+#include "parser.h"
+
+/*****************************************************************************
+ *Function name
+ * getSize : translate from string to integer
+ *Input params
+ * in : input file handle
+ *Return values
+ * size
+ *****************************************************************************/
+
+int getSize(parse_file *in)
+{
+ gchar *token;
+
+ token = getToken(in);
+ if(in->type == NUMBER) {
+ if(g_ascii_strcasecmp(token,"1") == 0) return 0;
+ else if(g_ascii_strcasecmp(token,"2") == 0) return 1;
+ else if(g_ascii_strcasecmp(token,"4") == 0) return 2;
+ else if(g_ascii_strcasecmp(token,"8") == 0) return 3;
+ }
+ else if(in->type == NAME) {
+ if(g_ascii_strcasecmp(token,"short") == 0) return 4;
+ else if(g_ascii_strcasecmp(token,"medium") == 0) return 5;
+ else if(g_ascii_strcasecmp(token,"long") == 0) return 6;
+ }
+ in->error(in,"incorrect size specification");
+ return -1;
+}
+
+/*****************************************************************************
+ *Function name
+ * error_callback : print out error info
+ *Input params
+ * in : input file handle
+ * msg : message to be printed
+ ****************************************************************************/
+
+void error_callback(parse_file *in, char *msg)
+{
+ if(in)
+ g_printf("Error in file %s, line %d: %s\n", in->name, in->lineno, msg);
+ else
+ printf("%s\n",msg);
+}
+
+/**************************************************************************
+ * Function :
+ * getNameAttribute,getFormatAttribute,getSizeAttribute,getValueAttribute
+ * getValueStrAttribute
+ * Description :
+ * Read the attribute from the input file.
+ *
+ * Parameters :
+ * in , input file handle.
+ *
+ * Return values :
+ * address of the attribute.
+ *
+ **************************************************************************/
+
+gchar * getNameAttribute(parse_file *in)
+{
+ gchar * token;
+ gunichar car;
+ GIOStatus status;
+
+ token = getName(in);
+ if(g_ascii_strcasecmp("name",token))in->error(in,"name was expected");
+ getEqual(in);
+
+ status = seekNextChar(in, &car);
+ if(status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
+ in->error(in,"name was expected");
+ else if(car == '\"') token = getQuotedString(in);
+ else token = getName(in);
+ return token;
+}
+
+char * getFormatAttribute(parse_file *in)
+{
+ char * token;
+
+ //format is an option
+ token = getToken(in);
+ if(g_ascii_strcasecmp("/",token) == 0 || g_ascii_strcasecmp(">",token) == 0){
+ ungetToken(in);
+ return NULL;
+ }
+
+ if(g_ascii_strcasecmp("format",token))in->error(in,"format was expected");
+ getEqual(in);
+ token = getQuotedString(in);
+ return token;
+}
+
+int getSizeAttribute(parse_file *in)
+{
+ /* skip name and equal */
+ getName(in);
+ getEqual(in);
+
+ return getSize(in);
+}
+
+int getValueAttribute(parse_file *in)
+{
+ /* skip name and equal */
+ getName(in);
+ getEqual(in);
+
+ return getNumber(in);
+}
+
+//for <label name=label_name value=n/>, value is an option
+char * getValueStrAttribute(parse_file *in)
+{
+ char * token;
+
+ token = getToken(in);
+ if(g_ascii_strcasecmp("/",token) == 0){
+ ungetToken(in);
+ return NULL;
+ }
+
+ if(g_ascii_strcasecmp("value",token))in->error(in,"value was expected");
+ getEqual(in);
+ token = getToken(in);
+ if(in->type != NUMBER) in->error(in,"number was expected");
+ return token;
+}
+
+char * getDescription(parse_file *in)
+{
+ gint64 pos;
+ gchar * token, *str;
+ gunichar car;
+ GError * error = NULL;
+
+ pos = in->pos;
+
+ getLAnglebracket(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("description",token)){
+ g_io_channel_seek_position(in->channel, pos-(in->pos), G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos = pos;
+
+ return NULL;
+ }
+
+ getRAnglebracket(in);
+
+ pos = 0;
+ while((g_io_channel_read_unichar(in->channel, &car, &error))
+ != G_IO_STATUS_EOF) {
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car == '<') break;
+ if(car == '\0') continue;
+ in->buffer[pos] = car;
+ pos++;
+ }
+ if(car == EOF)in->error(in,"not a valid description");
+ in->buffer[pos] = '\0';
+
+ str = g_strdup(in->buffer);
+
+ getForwardslash(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("description", token))in->error(in,"not a valid description");
+ getRAnglebracket(in);
+
+ return str;
+}
+
+/*****************************************************************************
+ *Function name
+ * parseFacility : generate event list
+ *Input params
+ * in : input file handle
+ * fac : empty facility
+ *Output params
+ * fac : facility filled with event list
+ ****************************************************************************/
+
+void parseFacility(parse_file *in, facility_t * fac)
+{
+ char * token;
+ event_t *ev;
+
+ fac->name = g_strdup(getNameAttribute(in));
+ getRAnglebracket(in);
+
+ fac->description = getDescription(in);
+
+ while(1){
+ getLAnglebracket(in);
+
+ token = getToken(in);
+ if(in->type == ENDFILE)
+ in->error(in,"the definition of the facility is not finished");
+
+ if(g_ascii_strcasecmp("event",token) == 0){
+ ev = (event_t*) g_new(event_t,1);
+ sequence_push(&(fac->events),ev);
+ parseEvent(in,ev, &(fac->unnamed_types), &(fac->named_types));
+ }else if(g_ascii_strcasecmp("type",token) == 0){
+ parseTypeDefinition(in, &(fac->unnamed_types), &(fac->named_types));
+ }else if(in->type == FORWARDSLASH){
+ break;
+ }else in->error(in,"event or type token expected\n");
+ }
+
+ token = getName(in);
+ if(g_ascii_strcasecmp("facility",token)) in->error(in,"not the end of the facility");
+ getRAnglebracket(in); //</facility>
+}
+
+/*****************************************************************************
+ *Function name
+ * parseEvent : generate event from event definition
+ *Input params
+ * in : input file handle
+ * ev : new event
+ * unnamed_types : array of unamed types
+ * named_types : array of named types
+ *Output params
+ * ev : new event (parameters are passed to it)
+ ****************************************************************************/
+
+void parseEvent(parse_file *in, event_t * ev, sequence * unnamed_types,
+ table * named_types)
+{
+ char *token;
+
+ //<event name=eventtype_name>
+ ev->name = g_strdup(getNameAttribute(in));
+ getRAnglebracket(in);
+
+ //<description>...</descriptio>
+ ev->description = getDescription(in);
+
+ //event can have STRUCT, TYPEREF or NOTHING
+ getLAnglebracket(in);
+
+ token = getToken(in);
+ if(in->type == FORWARDSLASH){ //</event> NOTHING
+ ev->type = NULL;
+ }else if(in->type == NAME){
+ if(g_ascii_strcasecmp("struct",token)==0 || g_ascii_strcasecmp("typeref",token)==0){
+ ungetToken(in);
+ ev->type = parseType(in,NULL, unnamed_types, named_types);
+ if(ev->type->type != STRUCT && ev->type->type != NONE)
+ in->error(in,"type must be a struct");
+ }else in->error(in, "not a valid type");
+
+ getLAnglebracket(in);
+ getForwardslash(in);
+ }else in->error(in,"not a struct type");
+
+ token = getName(in);
+ if(g_ascii_strcasecmp("event",token))in->error(in,"not an event definition");
+ getRAnglebracket(in); //</event>
+}
+
+/*****************************************************************************
+ *Function name
+ * parseField : get field infomation from buffer
+ *Input params
+ * in : input file handle
+ * t : type descriptor
+ * unnamed_types : array of unamed types
+ * named_types : array of named types
+ ****************************************************************************/
+
+void parseFields(parse_file *in, type_descriptor *t, sequence * unnamed_types,
+ table * named_types)
+{
+ char * token;
+ type_fields *f;
+
+ f = g_new(type_fields,1);
+ sequence_push(&(t->fields),f);
+
+ //<field name=field_name> <description> <type> </field>
+ f->name = g_strdup(getNameAttribute(in));
+ getRAnglebracket(in);
+
+ f->description = getDescription(in);
+
+ //<int size=...>
+ getLAnglebracket(in);
+ f->type = parseType(in,NULL, unnamed_types, named_types);
+
+ getLAnglebracket(in);
+ getForwardslash(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("field",token))in->error(in,"not a valid field definition");
+ getRAnglebracket(in); //</field>
+}
+
+
+/*****************************************************************************
+ *Function name
+ * parseType : get type information, type can be :
+ * Primitive:
+ * int(size,fmt); uint(size,fmt); float(size,fmt);
+ * string(fmt); enum(size,fmt,(label1,label2...))
+ * Compound:
+ * array(arraySize, type); sequence(lengthSize,type)
+ * struct(field(name,type,description)...)
+ * type name:
+ * type(name,type)
+ *Input params
+ * in : input file handle
+ * inType : a type descriptor
+ * unnamed_types : array of unamed types
+ * named_types : array of named types
+ *Return values
+ * type_descriptor* : a type descriptor
+ ****************************************************************************/
+
+type_descriptor *parseType(parse_file *in, type_descriptor *inType,
+ sequence * unnamed_types, table * named_types)
+{
+ char *token;
+ type_descriptor *t;
+
+ if(inType == NULL) {
+ t = g_new(type_descriptor,1);
+ t->type_name = NULL;
+ t->type = NONE;
+ t->fmt = NULL;
+ sequence_push(unnamed_types,t);
+ }
+ else t = inType;
+
+ token = getName(in);
+
+ if(g_ascii_strcasecmp(token,"struct") == 0) {
+ t->type = STRUCT;
+ getRAnglebracket(in); //<struct>
+ getLAnglebracket(in); //<field name=..>
+ token = getToken(in);
+ sequence_init(&(t->fields));
+ while(g_ascii_strcasecmp("field",token) == 0){
+ parseFields(in,t, unnamed_types, named_types);
+
+ //next field
+ getLAnglebracket(in);
+ token = getToken(in);
+ }
+ if(g_ascii_strcasecmp("/",token))in->error(in,"not a valid structure definition");
+ token = getName(in);
+ if(g_ascii_strcasecmp("struct",token)!=0)
+ in->error(in,"not a valid structure definition");
+ getRAnglebracket(in); //</struct>
+ }
+ else if(g_ascii_strcasecmp(token,"union") == 0) {
+ t->type = UNION;
+ t->size = getSizeAttribute(in);
+ getRAnglebracket(in); //<union typecodesize=isize>
+
+ getLAnglebracket(in); //<field name=..>
+ token = getToken(in);
+ sequence_init(&(t->fields));
+ while(g_ascii_strcasecmp("field",token) == 0){
+ parseFields(in,t, unnamed_types, named_types);
+
+ //next field
+ getLAnglebracket(in);
+ token = getToken(in);
+ }
+ if(g_ascii_strcasecmp("/",token))in->error(in,"not a valid union definition");
+ token = getName(in);
+ if(g_ascii_strcasecmp("union",token)!=0)
+ in->error(in,"not a valid union definition");
+ getRAnglebracket(in); //</union>
+ }
+ else if(g_ascii_strcasecmp(token,"array") == 0) {
+ t->type = ARRAY;
+ t->size = getValueAttribute(in);
+ getRAnglebracket(in); //<array size=n>
+
+ getLAnglebracket(in); //<type struct>
+ t->nested_type = parseType(in,NULL, unnamed_types, named_types);
+
+ getLAnglebracket(in); //</array>
+ getForwardslash(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("array",token))in->error(in,"not a valid array definition");
+ getRAnglebracket(in); //</array>
+ }
+ else if(g_ascii_strcasecmp(token,"sequence") == 0) {
+ t->type = SEQUENCE;
+ t->size = getSizeAttribute(in);
+ getRAnglebracket(in); //<array lengthsize=isize>
+
+ getLAnglebracket(in); //<type struct>
+ t->nested_type = parseType(in,NULL, unnamed_types, named_types);
+
+ getLAnglebracket(in); //</sequence>
+ getForwardslash(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("sequence",token))in->error(in,"not a valid sequence definition");
+ getRAnglebracket(in); //</sequence>
+ }
+ else if(g_ascii_strcasecmp(token,"enum") == 0) {
+ char * str, *str1;
+ t->type = ENUM;
+ sequence_init(&(t->labels));
+ t->size = getSizeAttribute(in);
+ t->fmt = g_strdup(getFormatAttribute(in));
+ getRAnglebracket(in);
+
+ //<label name=label1 value=n/>
+ getLAnglebracket(in);
+ token = getToken(in); //"label" or "/"
+ while(g_ascii_strcasecmp("label",token) == 0){
+ str1 = g_strdup(getNameAttribute(in));
+ token = getValueStrAttribute(in);
+ if(token){
+ str = g_strconcat(str1,"=",token,NULL);
+ g_free(str1);
+ sequence_push(&(t->labels),str);
+ }else
+ sequence_push(&(t->labels),str1);
+
+ getForwardslash(in);
+ getRAnglebracket(in);
+
+ //next label definition
+ getLAnglebracket(in);
+ token = getToken(in); //"label" or "/"
+ }
+ if(g_ascii_strcasecmp("/",token))in->error(in, "not a valid enum definition");
+ token = getName(in);
+ if(g_ascii_strcasecmp("enum",token))in->error(in, "not a valid enum definition");
+ getRAnglebracket(in); //</label>
+ }
+ else if(g_ascii_strcasecmp(token,"int") == 0) {
+ t->type = INT;
+ t->size = getSizeAttribute(in);
+ t->fmt = g_strdup(getFormatAttribute(in));
+ getForwardslash(in);
+ getRAnglebracket(in);
+ }
+ else if(g_ascii_strcasecmp(token,"uint") == 0) {
+ t->type = UINT;
+ t->size = getSizeAttribute(in);
+ t->fmt = g_strdup(getFormatAttribute(in));
+ getForwardslash(in);
+ getRAnglebracket(in);
+ }
+ else if(g_ascii_strcasecmp(token,"float") == 0) {
+ t->type = FLOAT;
+ t->size = getSizeAttribute(in);
+ t->fmt = g_strdup(getFormatAttribute(in));
+ getForwardslash(in);
+ getRAnglebracket(in);
+ }
+ else if(g_ascii_strcasecmp(token,"string") == 0) {
+ t->type = STRING;
+ t->fmt = g_strdup(getFormatAttribute(in));
+ getForwardslash(in);
+ getRAnglebracket(in);
+ }
+ else if(g_ascii_strcasecmp(token,"typeref") == 0){
+ // Must be a named type
+ if(inType != NULL)
+ in->error(in,"Named type cannot refer to a named type");
+ else {
+ g_free(t);
+ sequence_pop(unnamed_types);
+ token = getNameAttribute(in);
+ t = find_named_type(token, named_types);
+ getForwardslash(in); //<typeref name=type_name/>
+ getRAnglebracket(in);
+ return t;
+ }
+ }else in->error(in,"not a valid type");
+
+ return t;
+}
+
+/*****************************************************************************
+ *Function name
+ * find_named_type : find a named type from hash table
+ *Input params
+ * name : type name
+ * named_types : array of named types
+ *Return values
+ * type_descriptor * : a type descriptor
+ *****************************************************************************/
+
+type_descriptor * find_named_type(gchar *name, table * named_types)
+{
+ type_descriptor *t;
+
+ t = table_find(named_types,name);
+ if(t == NULL) {
+ t = g_new(type_descriptor,1);
+ t->type_name = g_strdup(name);
+ t->type = NONE;
+ t->fmt = NULL;
+ table_insert(named_types,t->type_name,t);
+ // table_insert(named_types,g_strdup(name),t);
+ }
+ return t;
+}
+
+/*****************************************************************************
+ *Function name
+ * parseTypeDefinition : get type information from type definition
+ *Input params
+ * in : input file handle
+ * unnamed_types : array of unamed types
+ * named_types : array of named types
+ *****************************************************************************/
+
+void parseTypeDefinition(parse_file * in, sequence * unnamed_types,
+ table * named_types)
+{
+ char *token;
+ type_descriptor *t;
+
+ token = getNameAttribute(in);
+ t = find_named_type(token, named_types);
+
+ if(t->type != NONE) in->error(in,"redefinition of named type");
+ getRAnglebracket(in); //<type name=type_name>
+ getLAnglebracket(in); //<struct>
+ token = getName(in);
+ if(g_ascii_strcasecmp("struct",token))in->error(in,"not a valid type definition");
+ ungetToken(in);
+ parseType(in,t, unnamed_types, named_types);
+
+ //</type>
+ getLAnglebracket(in);
+ getForwardslash(in);
+ token = getName(in);
+ if(g_ascii_strcasecmp("type",token))in->error(in,"not a valid type definition");
+ getRAnglebracket(in); //</type>
+}
+
+/**************************************************************************
+ * Function :
+ * getComa, getName, getNumber, getEqual
+ * Description :
+ * Read a token from the input file, check its type, return it scontent.
+ *
+ * Parameters :
+ * in , input file handle.
+ *
+ * Return values :
+ * address of token content.
+ *
+ **************************************************************************/
+
+char *getName(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != NAME) in->error(in,"Name token was expected");
+ return token;
+}
+
+int getNumber(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != NUMBER) in->error(in, "Number token was expected");
+ return atoi(token);
+}
+
+char *getForwardslash(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != FORWARDSLASH) in->error(in, "forward slash token was expected");
+ return token;
+}
+
+char *getLAnglebracket(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != LANGLEBRACKET) in->error(in, "Left angle bracket was expected");
+ return token;
+}
+
+char *getRAnglebracket(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != RANGLEBRACKET) in->error(in, "Right angle bracket was expected");
+ return token;
+}
+
+char *getQuotedString(parse_file * in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != QUOTEDSTRING) in->error(in, "quoted string was expected");
+ return token;
+}
+
+char * getEqual(parse_file *in)
+{
+ char *token;
+
+ token = getToken(in);
+ if(in->type != EQUAL) in->error(in, "equal was expected");
+ return token;
+}
+
+gunichar seekNextChar(parse_file *in, gunichar *car)
+{
+ GError * error = NULL;
+ GIOStatus status;
+
+ do {
+
+ status = g_io_channel_read_unichar(in->channel, car, &error);
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ break;
+ }
+ in->pos++;
+
+ if(!g_unichar_isspace(*car)) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+ in->pos--;
+ break;
+ }
+
+ } while(status != G_IO_STATUS_EOF && status != G_IO_STATUS_ERROR);
+
+ return status;
+}
+
+
+/******************************************************************
+ * Function :
+ * getToken, ungetToken
+ * Description :
+ * Read a token from the input file and return its type and content.
+ * Line numbers are accounted for and whitespace/comments are skipped.
+ *
+ * Parameters :
+ * in, input file handle.
+ *
+ * Return values :
+ * address of token content.
+ *
+ ******************************************************************/
+
+void ungetToken(parse_file * in)
+{
+ in->unget = 1;
+}
+
+gchar *getToken(parse_file * in)
+{
+ gunichar car, car1;
+ int pos = 0, escaped;
+ GError * error = NULL;
+
+ if(in->unget == 1) {
+ in->unget = 0;
+ return in->buffer;
+ }
+
+ /* skip whitespace and comments */
+
+ while((g_io_channel_read_unichar(in->channel, &car, &error))
+ != G_IO_STATUS_EOF) {
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car == '/') {
+ g_io_channel_read_unichar(in->channel, &car1, &error);
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car1 == '*') skipComment(in);
+ else if(car1 == '/') skipEOL(in);
+ else {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ break;
+ }
+ }
+ else if(car == '\n') in->lineno++;
+ else if(!g_unichar_isspace(car)) break;
+ }
+ switch(car) {
+ case EOF:
+ in->type = ENDFILE;
+ break;
+ case '/':
+ in->type = FORWARDSLASH;
+ in->buffer[pos] = car;
+ pos++;
+ break;
+ case '<':
+ in->type = LANGLEBRACKET;
+ in->buffer[pos] = car;
+ pos++;
+ break;
+ case '>':
+ in->type = RANGLEBRACKET;
+ in->buffer[pos] = car;
+ pos++;
+ break;
+ case '=':
+ in->type = EQUAL;
+ in->buffer[pos] = car;
+ pos++;
+ break;
+ case '"':
+ escaped = 0;
+ while(g_io_channel_read_unichar(in->channel, &car, &error)
+ != G_IO_STATUS_EOF && pos < BUFFER_SIZE) {
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car == '\\' && escaped == 0) {
+ in->buffer[pos] = car;
+ pos++;
+ escaped = 1;
+ continue;
+ }
+ if(car == '"' && escaped == 0) break;
+ if(car == '\n' && escaped == 0) {
+ in->error(in, "non escaped newline inside quoted string");
+ }
+ if(car == '\n') in->lineno++;
+ in->buffer[pos] = car;
+ pos++;
+ escaped = 0;
+ }
+ if(car == EOF) in->error(in,"no ending quotemark");
+ if(pos == BUFFER_SIZE) in->error(in, "quoted string token too large");
+ in->type = QUOTEDSTRING;
+ break;
+ default:
+ if(g_unichar_isdigit(car)) {
+ in->buffer[pos] = car;
+ pos++;
+ while(g_io_channel_read_unichar(in->channel, &car, &error)
+ != G_IO_STATUS_EOF && pos < BUFFER_SIZE) {
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(!isdigit(car)) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ break;
+ }
+ in->buffer[pos] = car;
+ pos++;
+ }
+ if(car == EOF) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ }
+ if(pos == BUFFER_SIZE) in->error(in, "number token too large");
+ in->type = NUMBER;
+ }
+ else if(g_unichar_isalpha(car)) {
+ in->buffer[0] = car;
+ pos = 1;
+ while(g_io_channel_read_unichar(in->channel, &car, &error)
+ != G_IO_STATUS_EOF && pos < BUFFER_SIZE) {
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(!(g_unichar_isalnum(car) || car == '_')) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ break;
+ }
+ in->buffer[pos] = car;
+ pos++;
+ }
+ if(car == EOF) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ }
+ if(pos == BUFFER_SIZE) in->error(in, "name token too large");
+ in->type = NAME;
+ }
+ else in->error(in, "invalid character, unrecognized token");
+ }
+ in->buffer[pos] = 0;
+ return in->buffer;
+}
+
+void skipComment(parse_file * in)
+{
+ gunichar car;
+ GError * error = NULL;
+
+ while(g_io_channel_read_unichar(in->channel, &car, &error)
+ != G_IO_STATUS_EOF) {
+
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car == '\n') in->lineno++;
+ else if(car == '*') {
+
+ g_io_channel_read_unichar(in->channel, &car, &error);
+ if(error != NULL) {
+ g_warning("Can not read file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos++;
+
+ if(car ==EOF) break;
+ if(car == '/') return;
+
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+
+ }
+ }
+ if(car == EOF) in->error(in,"comment begining with '/*' has no ending '*/'");
+}
+
+void skipEOL(parse_file * in)
+{
+ gunichar car;
+ GError * error = NULL;
+
+ while(g_io_channel_read_unichar(in->channel, &car, &error)
+ != G_IO_STATUS_EOF) {
+ if(car == '\n') {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ break;
+ }
+ }
+ if(car == EOF) {
+ g_io_channel_seek_position(in->channel, -1, G_SEEK_CUR, &error);
+ if(error != NULL) {
+ g_warning("Can not seek file: \n%s\n", error->message);
+ g_error_free(error);
+ } else in->pos--;
+ }
+}
+
+/*****************************************************************************
+ *Function name
+ * checkNamedTypesImplemented : check if all named types have definition
+ * returns -1 on error, 0 if ok
+ ****************************************************************************/
+
+int checkNamedTypesImplemented(table * named_types)
+{
+ type_descriptor *t;
+ int pos;
+ char str[256];
+
+ for(pos = 0 ; pos < named_types->values.position; pos++) {
+ t = (type_descriptor *) named_types->values.array[pos];
+ if(t->type == NONE){
+ sprintf(str,"named type '%s' has no definition",
+ (char*)named_types->keys.array[pos]);
+ error_callback(NULL,str);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * generateChecksum : generate checksum for the facility
+ *Input Params
+ * facName : name of facility
+ *Output Params
+ * checksum : checksum for the facility
+ ****************************************************************************/
+
+int generateChecksum(char* facName, guint32 * checksum, sequence * events)
+{
+ unsigned long crc ;
+ int pos;
+ event_t * ev;
+ char str[256];
+
+ crc = crc32(facName);
+ for(pos = 0; pos < events->position; pos++){
+ ev = (event_t *)(events->array[pos]);
+ crc = partial_crc32(ev->name,crc);
+ if(!ev->type) continue; //event without type
+ if(ev->type->type != STRUCT){
+ sprintf(str,"event '%s' has a type other than STRUCT",ev->name);
+ error_callback(NULL, str);
+ return -1;
+ }
+ crc = getTypeChecksum(crc, ev->type);
+ }
+ *checksum = crc;
+ return 0;
+}
+
+/*****************************************************************************
+ *Function name
+ * getTypeChecksum : generate checksum by type info
+ *Input Params
+ * crc : checksum generated so far
+ * type : type descriptor containing type info
+ *Return value
+ * unsigned long : checksum
+ *****************************************************************************/
+
+unsigned long getTypeChecksum(unsigned long aCrc, type_descriptor * type)
+{
+ unsigned long crc = aCrc;
+ char * str = NULL, buf[16];
+ int flag = 0, pos;
+ type_fields * fld;
+
+ switch(type->type){
+ case INT:
+ str = intOutputTypes[type->size];
+ break;
+ case UINT:
+ str = uintOutputTypes[type->size];
+ break;
+ case FLOAT:
+ str = floatOutputTypes[type->size];
+ break;
+ case STRING:
+ str = g_strdup("string");
+ flag = 1;
+ break;
+ case ENUM:
+ str = g_strconcat("enum ", uintOutputTypes[type->size], NULL);
+ flag = 1;
+ break;
+ case ARRAY:
+ sprintf(buf,"%d",type->size);
+ str = g_strconcat("array ",buf, NULL);
+ flag = 1;
+ break;
+ case SEQUENCE:
+ sprintf(buf,"%d",type->size);
+ str = g_strconcat("sequence ",buf, NULL);
+ flag = 1;
+ break;
+ case STRUCT:
+ str = g_strdup("struct");
+ flag = 1;
+ break;
+ case UNION:
+ str = g_strdup("union");
+ flag = 1;
+ break;
+ default:
+ error_callback(NULL, "named type has no definition");
+ break;
+ }
+
+ crc = partial_crc32(str,crc);
+ if(flag) g_free(str);
+
+ if(type->fmt) crc = partial_crc32(type->fmt,crc);
+
+ if(type->type == ARRAY || type->type == SEQUENCE){
+ crc = getTypeChecksum(crc,type->nested_type);
+ }else if(type->type == STRUCT || type->type == UNION){
+ for(pos =0; pos < type->fields.position; pos++){
+ fld = (type_fields *) type->fields.array[pos];
+ crc = partial_crc32(fld->name,crc);
+ crc = getTypeChecksum(crc, fld->type);
+ }
+ }else if(type->type == ENUM){
+ for(pos = 0; pos < type->labels.position; pos++)
+ crc = partial_crc32((char*)type->labels.array[pos],crc);
+ }
+
+ return crc;
+}
+
+
+/* Event type descriptors */
+void freeType(type_descriptor * tp)
+{
+ int pos2;
+ type_fields *f;
+
+ if(tp->fmt != NULL) g_free(tp->fmt);
+ if(tp->type == ENUM) {
+ for(pos2 = 0; pos2 < tp->labels.position; pos2++) {
+ g_free(tp->labels.array[pos2]);
+ }
+ sequence_dispose(&(tp->labels));
+ }
+ if(tp->type == STRUCT) {
+ for(pos2 = 0; pos2 < tp->fields.position; pos2++) {
+ f = (type_fields *) tp->fields.array[pos2];
+ g_free(f->name);
+ g_free(f->description);
+ g_free(f);
+ }
+ sequence_dispose(&(tp->fields));
+ }
+}
+
+void freeNamedType(table * t)
+{
+ int pos;
+ type_descriptor * td;
+
+ for(pos = 0 ; pos < t->keys.position; pos++) {
+ g_free((char *)t->keys.array[pos]);
+ td = (type_descriptor*)t->values.array[pos];
+ freeType(td);
+ g_free(td);
+ }
+}
+
+void freeTypes(sequence *t)
+{
+ int pos;
+ type_descriptor *tp;
+
+ for(pos = 0 ; pos < t->position; pos++) {
+ tp = (type_descriptor *)t->array[pos];
+ freeType(tp);
+ g_free(tp);
+ }
+}
+
+void freeEvents(sequence *t)
+{
+ int pos;
+ event_t *ev;
+
+ for(pos = 0 ; pos < t->position; pos++) {
+ ev = (event_t *) t->array[pos];
+ g_free(ev->name);
+ g_free(ev->description);
+ g_free(ev);
+ }
+
+}
+
+
+/* Extensible array */
+
+void sequence_init(sequence *t)
+{
+ t->size = 10;
+ t->position = 0;
+ t->array = g_new(void*, t->size);
+}
+
+void sequence_dispose(sequence *t)
+{
+ t->size = 0;
+ g_free(t->array);
+ t->array = NULL;
+}
+
+void sequence_push(sequence *t, void *elem)
+{
+ void **tmp;
+
+ if(t->position >= t->size) {
+ tmp = t->array;
+ t->array = g_new(void*, 2*t->size);
+ memcpy(t->array, tmp, t->size * sizeof(void *));
+ t->size = t->size * 2;
+ g_free(tmp);
+ }
+ t->array[t->position] = elem;
+ t->position++;
+}
+
+void *sequence_pop(sequence *t)
+{
+ return t->array[t->position--];
+}
+
+
+/* Hash table API, implementation is just linear search for now */
+
+void table_init(table *t)
+{
+ sequence_init(&(t->keys));
+ sequence_init(&(t->values));
+}
+
+void table_dispose(table *t)
+{
+ sequence_dispose(&(t->keys));
+ sequence_dispose(&(t->values));
+}
+
+void table_insert(table *t, char *key, void *value)
+{
+ sequence_push(&(t->keys),key);
+ sequence_push(&(t->values),value);
+}
+
+void *table_find(table *t, char *key)
+{
+ int pos;
+ for(pos = 0 ; pos < t->keys.position; pos++) {
+ if(g_ascii_strcasecmp((char *)key,(char *)t->keys.array[pos]) == 0)
+ return(t->values.array[pos]);
+ }
+ return NULL;
+}
+
+void table_insert_int(table *t, int *key, void *value)
+{
+ sequence_push(&(t->keys),key);
+ sequence_push(&(t->values),value);
+}
+
+void *table_find_int(table *t, int *key)
+{
+ int pos;
+ for(pos = 0 ; pos < t->keys.position; pos++) {
+ if(*key == *(int *)t->keys.array[pos])
+ return(t->values.array[pos]);
+ }
+ return NULL;
+}
+
+
--- /dev/null
+/*
+
+parser.c: Generate helper declarations and functions to trace events
+ from an event description file.
+
+Copyright (C) 2002, Xianxiu Yang
+Copyright (C) 2002, Michel Dagenais
+This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+the Free Software Foundation; version 2 of the License.
+
+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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <glib.h>
+
+/* Extensible array container */
+
+typedef struct _sequence {
+ int size;
+ int position;
+ void **array;
+} sequence;
+
+void sequence_init(sequence *t);
+void sequence_dispose(sequence *t);
+void sequence_push(sequence *t, void *elem);
+void *sequence_pop(sequence *t);
+
+
+/* Hash table */
+
+typedef struct _table {
+ sequence keys;
+ sequence values;
+} table;
+
+void table_init(table *t);
+void table_dispose(table *t);
+void table_insert(table *t, char *key, void *value);
+void *table_find(table *t, char *key);
+void table_insert_int(table *t, int *key, void *value);
+void *table_find_int(table *t, int *key);
+
+
+/* Token types */
+
+typedef enum _token_type {
+ ENDFILE,
+ FORWARDSLASH,
+ LANGLEBRACKET,
+ RANGLEBRACKET,
+ EQUAL,
+ QUOTEDSTRING,
+ NUMBER,
+ NAME
+} token_type;
+
+
+/* State associated with a file being parsed */
+typedef struct _parse_file {
+ gchar *name;
+ int fd;
+ guint64 pos;
+ GIOChannel *channel;
+ int lineno;
+ gchar *buffer;
+ token_type type;
+ int unget;
+ void (*error) (struct _parse_file *, char *);
+} parse_file;
+
+void ungetToken(parse_file * in);
+gchar *getToken(parse_file *in);
+gchar *getForwardslash(parse_file *in);
+gchar *getLAnglebracket(parse_file *in);
+gchar *getRAnglebracket(parse_file *in);
+gchar *getQuotedString(parse_file *in);
+gchar *getName(parse_file *in);
+int getNumber(parse_file *in);
+gchar *getEqual(parse_file *in);
+GIOStatus seekNextChar(parse_file *in, gunichar *car);
+
+void skipComment(parse_file * in);
+void skipEOL(parse_file * in);
+
+/* Some constants */
+
+#define BUFFER_SIZE 1024
+
+
+/* Events data types */
+
+typedef enum _data_type {
+ INT,
+ UINT,
+ FLOAT,
+ STRING,
+ ENUM,
+ ARRAY,
+ SEQUENCE,
+ STRUCT,
+ UNION,
+ NONE
+} data_type;
+
+
+/* Event type descriptors */
+
+typedef struct _type_descriptor {
+ char * type_name; //used for named type
+ data_type type;
+ char *fmt;
+ int size;
+ sequence labels; // for enumeration
+ sequence fields; // for structure
+ struct _type_descriptor *nested_type; // for array and sequence
+} type_descriptor;
+
+
+/* Fields within types */
+
+typedef struct _type_fields{
+ char *name;
+ char *description;
+ type_descriptor *type;
+} type_fields;
+
+
+/* Events definitions */
+
+typedef struct _event_t {
+ char *name;
+ char *description;
+ type_descriptor *type;
+} event_t;
+
+typedef struct _facility_t {
+ char * name;
+ char * description;
+ sequence events;
+ sequence unnamed_types;
+ table named_types;
+} facility_t;
+
+int getSize(parse_file *in);
+unsigned long getTypeChecksum(unsigned long aCrc, type_descriptor * type);
+
+void parseFacility(parse_file *in, facility_t * fac);
+void parseEvent(parse_file *in, event_t *ev, sequence * unnamed_types, table * named_types);
+void parseTypeDefinition(parse_file *in, sequence * unnamed_types, table * named_types);
+type_descriptor *parseType(parse_file *in, type_descriptor *t, sequence * unnamed_types, table * named_types);
+void parseFields(parse_file *in, type_descriptor *t, sequence * unnamed_types, table * named_types);
+int checkNamedTypesImplemented(table * namedTypes);
+type_descriptor * find_named_type(char *name, table * named_types);
+int generateChecksum(char * facName, guint32 * checksum, sequence * events);
+
+
+/* get attributes */
+char * getNameAttribute(parse_file *in);
+char * getFormatAttribute(parse_file *in);
+int getSizeAttribute(parse_file *in);
+int getValueAttribute(parse_file *in);
+char * getValueStrAttribute(parse_file *in);
+
+char * getDescription(parse_file *in);
+
+
+static char *intOutputTypes[] = {
+ "int8_t", "int16_t", "int32_t", "int64_t", "short int", "int", "long int" };
+
+static char *uintOutputTypes[] = {
+ "uint8_t", "uint16_t", "uint32_t", "uint64_t", "unsigned short int",
+ "unsigned int", "unsigned long int" };
+
+static char *floatOutputTypes[] = {
+ "undef", "undef", "float", "double", "undef", "float", "double" };
+
+
+/* Dynamic memory allocation and freeing */
+
+void freeTypes(sequence *t);
+void freeType(type_descriptor * td);
+void freeEvents(sequence *t);
+void freeNamedType(table * t);
+void error_callback(parse_file *in, char *msg);
+
+
+//checksum part
+static const unsigned int crctab32[] =
+{
+#include "crc32.tab"
+};
+
+static inline unsigned long
+partial_crc32_one(unsigned char c, unsigned long crc)
+{
+ return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
+}
+
+static inline unsigned long
+partial_crc32(const char *s, unsigned long crc)
+{
+ while (*s)
+ crc = partial_crc32_one(*s++, crc);
+ return crc;
+}
+
+static inline unsigned long
+crc32(const char *s)
+{
+ return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
+}
+
+
+#endif // PARSER_H
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef LTT_TIME_H
+#define LTT_TIME_H
+
+#include <glib.h>
+#include <ltt/compiler.h>
+#include <math.h>
+
+typedef struct _LttTime {
+ unsigned long tv_sec;
+ unsigned long tv_nsec;
+} LttTime;
+
+
+#define NANOSECONDS_PER_SECOND 1000000000
+
+/* We give the DIV and MUL constants so we can always multiply, for a
+ * division as well as a multiplication of NANOSECONDS_PER_SECOND */
+/* 2^30/1.07374182400631629848 = 1000000000.0 */
+#define DOUBLE_SHIFT_CONST_DIV 1.07374182400631629848
+#define DOUBLE_SHIFT 30
+
+/* 2^30*0.93132257461547851562 = 1000000000.0000000000 */
+#define DOUBLE_SHIFT_CONST_MUL 0.93132257461547851562
+
+
+/* 1953125 * 2^9 = NANOSECONDS_PER_SECOND */
+#define LTT_TIME_UINT_SHIFT_CONST 1953125
+#define LTT_TIME_UINT_SHIFT 9
+
+
+static const LttTime ltt_time_zero = { 0, 0 };
+
+static const LttTime ltt_time_one = { 0, 1 };
+
+static const LttTime ltt_time_infinite = { G_MAXUINT, NANOSECONDS_PER_SECOND };
+
+static inline LttTime ltt_time_sub(LttTime t1, LttTime t2)
+{
+ LttTime res;
+ res.tv_sec = t1.tv_sec - t2.tv_sec;
+ res.tv_nsec = t1.tv_nsec - t2.tv_nsec;
+ /* unlikely : given equal chance to be anywhere in t1.tv_nsec, and
+ * higher probability of low value for t2.tv_sec, we will habitually
+ * not wrap.
+ */
+ if(unlikely(t1.tv_nsec < t2.tv_nsec)) {
+ res.tv_sec--;
+ res.tv_nsec += NANOSECONDS_PER_SECOND;
+ }
+ return res;
+}
+
+
+static inline LttTime ltt_time_add(LttTime t1, LttTime t2)
+{
+ LttTime res;
+ res.tv_nsec = t1.tv_nsec + t2.tv_nsec;
+ res.tv_sec = t1.tv_sec + t2.tv_sec;
+ /* unlikely : given equal chance to be anywhere in t1.tv_nsec, and
+ * higher probability of low value for t2.tv_sec, we will habitually
+ * not wrap.
+ */
+ if(unlikely(res.tv_nsec >= NANOSECONDS_PER_SECOND)) {
+ res.tv_sec++;
+ res.tv_nsec -= NANOSECONDS_PER_SECOND;
+ }
+ return res;
+}
+
+/* Fastest comparison : t1 > t2 */
+static inline int ltt_time_compare(LttTime t1, LttTime t2)
+{
+ int ret=0;
+ if(likely(t1.tv_sec > t2.tv_sec)) ret = 1;
+ else if(unlikely(t1.tv_sec < t2.tv_sec)) ret = -1;
+ else if(likely(t1.tv_nsec > t2.tv_nsec)) ret = 1;
+ else if(unlikely(t1.tv_nsec < t2.tv_nsec)) ret = -1;
+
+ return ret;
+}
+
+#define LTT_TIME_MIN(a,b) ((ltt_time_compare((a),(b)) < 0) ? (a) : (b))
+#define LTT_TIME_MAX(a,b) ((ltt_time_compare((a),(b)) > 0) ? (a) : (b))
+
+#define MAX_TV_SEC_TO_DOUBLE 0x7FFFFF
+static inline double ltt_time_to_double(LttTime t1)
+{
+ /* We lose precision if tv_sec is > than (2^23)-1
+ *
+ * Max values that fits in a double (53 bits precision on normalised
+ * mantissa):
+ * tv_nsec : NANOSECONDS_PER_SECONDS : 2^30
+ *
+ * So we have 53-30 = 23 bits left for tv_sec.
+ * */
+#ifdef EXTRA_CHECK
+ g_assert(t1.tv_sec <= MAX_TV_SEC_TO_DOUBLE);
+ if(t1.tv_sec > MAX_TV_SEC_TO_DOUBLE)
+ g_warning("Precision loss in conversion LttTime to double");
+#endif //EXTRA_CHECK
+ return ((double)((guint64)t1.tv_sec<<DOUBLE_SHIFT)
+ * (double)DOUBLE_SHIFT_CONST_MUL)
+ + (double)t1.tv_nsec;
+}
+
+
+static inline LttTime ltt_time_from_double(double t1)
+{
+ /* We lose precision if tv_sec is > than (2^23)-1
+ *
+ * Max values that fits in a double (53 bits precision on normalised
+ * mantissa):
+ * tv_nsec : NANOSECONDS_PER_SECONDS : 2^30
+ *
+ * So we have 53-30 = 23 bits left for tv_sec.
+ * */
+#ifdef EXTRA_CHECK
+ g_assert(t1 <= MAX_TV_SEC_TO_DOUBLE);
+ if(t1 > MAX_TV_SEC_TO_DOUBLE)
+ g_warning("Conversion from non precise double to LttTime");
+#endif //EXTRA_CHECK
+ LttTime res;
+ //res.tv_sec = t1/(double)NANOSECONDS_PER_SECOND;
+ res.tv_sec = (guint64)(t1 * DOUBLE_SHIFT_CONST_DIV) >> DOUBLE_SHIFT;
+ res.tv_nsec = (t1 - (((guint64)res.tv_sec<<LTT_TIME_UINT_SHIFT))
+ * LTT_TIME_UINT_SHIFT_CONST);
+ return res;
+}
+
+/* Use ltt_time_to_double and ltt_time_from_double to check for lack
+ * of precision.
+ */
+static inline LttTime ltt_time_mul(LttTime t1, double d)
+{
+ LttTime res;
+
+ double time_double = ltt_time_to_double(t1);
+
+ time_double = time_double * d;
+
+ res = ltt_time_from_double(time_double);
+
+ return res;
+
+#if 0
+ /* What is that ? (Mathieu) */
+ if(f == 0.0){
+ res.tv_sec = 0;
+ res.tv_nsec = 0;
+ }else{
+ double d;
+ d = 1.0/f;
+ sec = t1.tv_sec / (double)d;
+ res.tv_sec = sec;
+ res.tv_nsec = t1.tv_nsec / (double)d + (sec - res.tv_sec) *
+ NANOSECONDS_PER_SECOND;
+ res.tv_sec += res.tv_nsec / NANOSECONDS_PER_SECOND;
+ res.tv_nsec %= NANOSECONDS_PER_SECOND;
+ }
+ return res;
+#endif //0
+}
+
+
+/* Use ltt_time_to_double and ltt_time_from_double to check for lack
+ * of precision.
+ */
+static inline LttTime ltt_time_div(LttTime t1, double d)
+{
+ LttTime res;
+
+ double time_double = ltt_time_to_double(t1);
+
+ time_double = time_double / d;
+
+ res = ltt_time_from_double(time_double);
+
+ return res;
+
+
+#if 0
+ double sec;
+ LttTime res;
+
+ sec = t1.tv_sec / (double)f;
+ res.tv_sec = sec;
+ res.tv_nsec = t1.tv_nsec / (double)f + (sec - res.tv_sec) *
+ NANOSECONDS_PER_SECOND;
+ res.tv_sec += res.tv_nsec / NANOSECONDS_PER_SECOND;
+ res.tv_nsec %= NANOSECONDS_PER_SECOND;
+ return res;
+#endif //0
+}
+
+
+static inline guint64 ltt_time_to_uint64(LttTime t1)
+{
+ return (((guint64)t1.tv_sec*LTT_TIME_UINT_SHIFT_CONST) << LTT_TIME_UINT_SHIFT)
+ + (guint64)t1.tv_nsec;
+}
+
+
+#define MAX_TV_SEC_TO_UINT64 0x3FFFFFFFFFFFFFFFULL
+
+/* The likely branch is with sec != 0, because most events in a bloc
+ * will be over 1s from the block start. (see tracefile.c)
+ */
+static inline LttTime ltt_time_from_uint64(guint64 t1)
+{
+ /* We lose precision if tv_sec is > than (2^62)-1
+ * */
+#ifdef EXTRA_CHECK
+ g_assert(t1 <= MAX_TV_SEC_TO_UINT64);
+ if(t1 > MAX_TV_SEC_TO_UINT64)
+ g_warning("Conversion from uint64 to non precise LttTime");
+#endif //EXTRA_CHECK
+ LttTime res;
+ //if(unlikely(t1 >= NANOSECONDS_PER_SECOND)) {
+ if(likely(t1>>LTT_TIME_UINT_SHIFT >= LTT_TIME_UINT_SHIFT_CONST)) {
+ //res.tv_sec = t1/NANOSECONDS_PER_SECOND;
+ res.tv_sec = (t1>>LTT_TIME_UINT_SHIFT)
+ /LTT_TIME_UINT_SHIFT_CONST; // acceleration
+ res.tv_nsec = (t1 - res.tv_sec*NANOSECONDS_PER_SECOND);
+ } else {
+ res.tv_sec = 0;
+ res.tv_nsec = (guint32)t1;
+ }
+ return res;
+}
+
+#endif // LTT_TIME_H
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#include <ltt/ltt.h>
+
+
+extern GQuark LTT_FACILITY_NAME_HEARTBEAT,
+ LTT_EVENT_NAME_HEARTBEAT;
+
+/* A trace is specified as a pathname to the directory containing all the
+ associated data (control tracefiles, per cpu tracefiles, event
+ descriptions...).
+
+ When a trace is closed, all the associated facilities, types and fields
+ are released as well.
+
+ return value is NULL if there is an error when opening the trace.
+
+ */
+
+LttTrace *ltt_trace_open(const gchar *pathname);
+
+/* copy reopens a trace
+ *
+ * return value NULL if error while opening the trace
+ */
+LttTrace *ltt_trace_copy(LttTrace *self);
+
+gchar * ltt_trace_name(LttTrace *t);
+
+void ltt_trace_close(LttTrace *t);
+
+
+LttSystemDescription *ltt_trace_system_description(LttTrace *t);
+
+
+/* Functions to discover the facilities in the trace. Once the number
+ of facilities is known, they may be accessed by position. Multiple
+ versions of a facility (same name, different checksum) have consecutive
+ positions. */
+
+unsigned ltt_trace_facility_number(LttTrace *t);
+
+LttFacility *ltt_trace_facility_get(LttTrace *t, unsigned i);
+
+LttFacility * ltt_trace_facility_by_id(LttTrace * trace, unsigned id);
+
+/* Look for a facility by name. It returns the number of facilities found
+ and sets the position argument to the first found. Returning 0, the named
+ facility is unknown, returning 1, the named facility is at the specified
+ position, returning n, the facilities are from position to
+ position + n - 1. */
+
+unsigned ltt_trace_facility_find(LttTrace *t, gchar *name, unsigned *position);
+
+
+/* Functions to discover all the event types in the trace */
+
+unsigned ltt_trace_eventtype_number(LttTrace *t);
+
+LttEventType *ltt_trace_eventtype_get(LttTrace *t, unsigned i);
+
+
+/* There is one "per cpu" tracefile for each CPU, numbered from 0 to
+ the maximum number of CPU in the system. When the number of CPU installed
+ is less than the maximum, some positions are unused. There are also a
+ number of "control" tracefiles (facilities, interrupts...). */
+
+unsigned ltt_trace_control_tracefile_number(LttTrace *t);
+
+unsigned ltt_trace_per_cpu_tracefile_number(LttTrace *t);
+
+
+/* It is possible to search for the tracefiles by name or by CPU tracefile
+ * name.
+ * The index within the tracefiles of the same type is returned if found
+ * and a negative value otherwise.
+ */
+
+int ltt_trace_control_tracefile_find(LttTrace *t, const gchar *name);
+
+int ltt_trace_per_cpu_tracefile_find(LttTrace *t, const gchar *name);
+
+
+/* Get a specific tracefile */
+
+LttTracefile *ltt_trace_control_tracefile_get(LttTrace *t, unsigned i);
+
+LttTracefile *ltt_trace_per_cpu_tracefile_get(LttTrace *t, unsigned i);
+
+
+/* Get the start time and end time of the trace */
+
+void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end);
+
+
+/* Get the name of a tracefile */
+
+char *ltt_tracefile_name(LttTracefile *tf);
+
+
+/* Get the number of blocks in the tracefile */
+
+unsigned ltt_tracefile_block_number(LttTracefile *tf);
+
+
+/* Seek to the first event of the trace with time larger or equal to time */
+
+void ltt_tracefile_seek_time(LttTracefile *t, LttTime time);
+
+/* Seek to the first event with position equal or larger to ep */
+
+void ltt_tracefile_seek_position(LttTracefile *t,
+ const LttEventPosition *ep);
+
+/* Read the next event */
+
+LttEvent *ltt_tracefile_read(LttTracefile *t, LttEvent *event);
+
+/* open tracefile */
+
+LttTracefile * ltt_tracefile_open(LttTrace *t, gchar * tracefile_name);
+
+void ltt_tracefile_open_cpu(LttTrace *t, gchar * tracefile_name);
+
+gint ltt_tracefile_open_control(LttTrace *t, gchar * control_name);
+
+
+/* get the data type size and endian type of the local machine */
+
+void getDataEndianType(LttArchSize * size, LttArchEndian * endian);
+
+/* get an integer number */
+
+gint64 getIntNumber(gboolean reverse_byte_order, int size1, void *evD);
+
+
+/* get the node name of the system */
+
+gchar * ltt_trace_system_description_node_name (LttSystemDescription * s);
+
+
+/* get the domain name of the system */
+
+gchar * ltt_trace_system_description_domain_name (LttSystemDescription * s);
+
+
+/* get the description of the system */
+
+gchar * ltt_trace_system_description_description (LttSystemDescription * s);
+
+
+/* get the start time of the trace */
+
+LttTime ltt_trace_system_description_trace_start_time(LttSystemDescription *s);
+
+/* copy tracefile info over another. Used for sync. */
+LttTracefile *ltt_tracefile_new();
+void ltt_tracefile_destroy(LttTracefile *tf);
+void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src);
+
+void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname);
+
+
+
+#endif // TRACE_H
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2005 Mathieu Desnoyers
+ *
+ * Complete rewrite from the original version made by XangXiu Yang.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <math.h>
+#include <glib.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+// For realpath
+#include <limits.h>
+#include <stdlib.h>
+
+
+#include "parser.h"
+#include <ltt/ltt.h>
+#include "ltt-private.h"
+#include <ltt/trace.h>
+#include <ltt/facility.h>
+#include <ltt/event.h>
+#include <ltt/type.h>
+#include <ltt/ltt-types.h>
+
+
+/* Facility names used in this file */
+
+GQuark LTT_FACILITY_NAME_HEARTBEAT,
+ LTT_EVENT_NAME_HEARTBEAT;
+
+#ifndef g_open
+#define g_open open
+#endif
+
+
+#define __UNUSED__ __attribute__((__unused__))
+
+#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
+#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
+
+#define g_close close
+
+/* obtain the time of an event */
+
+static inline LttTime getEventTime(LttTracefile * tf);
+
+
+/* set the offset of the fields belonging to the event,
+ need the information of the archecture */
+void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace *t);
+
+/* get the size of the field type according to the archtecture's
+ size and endian type(info of the archecture) */
+static inline gint getFieldtypeSize(LttTracefile * tf,
+ LttEventType * evT, gint offsetRoot,
+ gint offsetParent, LttField *fld, void *evD, LttTrace* t);
+
+/* read a fixed size or a block information from the file (fd) */
+int map_block(LttTracefile * tf, unsigned int block_num);
+
+/* calculate cycles per nsec for current block */
+void getCyclePerNsec(LttTracefile * t);
+
+/* reinitialize the info of the block which is already in the buffer */
+void updateTracefile(LttTracefile * tf);
+
+/* go to the next event */
+int skipEvent(LttTracefile * t);
+
+
+/* Functions to parse system.xml file (using glib xml parser) */
+static void parser_start_element (GMarkupParseContext __UNUSED__ *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ int i=0;
+ LttSystemDescription* des = (LttSystemDescription* )user_data;
+ if(strcmp("system", element_name)){
+ *error = g_error_new(G_MARKUP_ERROR,
+ G_LOG_LEVEL_WARNING,
+ "This is not system.xml file");
+ return;
+ }
+
+ while(attribute_names[i]){
+ if(strcmp("node_name", attribute_names[i])==0){
+ des->node_name = g_strdup(attribute_values[i]);
+ }else if(strcmp("domainname", attribute_names[i])==0){
+ des->domain_name = g_strdup(attribute_values[i]);
+ }else if(strcmp("cpu", attribute_names[i])==0){
+ des->nb_cpu = atoi(attribute_values[i]);
+ }else if(strcmp("arch_size", attribute_names[i])==0){
+ if(strcmp(attribute_values[i],"LP32") == 0) des->size = LTT_LP32;
+ else if(strcmp(attribute_values[i],"ILP32") == 0) des->size = LTT_ILP32;
+ else if(strcmp(attribute_values[i],"LP64") == 0) des->size = LTT_LP64;
+ else if(strcmp(attribute_values[i],"ILP64") == 0) des->size = LTT_ILP64;
+ else if(strcmp(attribute_values[i],"UNKNOWN") == 0) des->size = LTT_UNKNOWN;
+ }else if(strcmp("endian", attribute_names[i])==0){
+ if(strcmp(attribute_values[i],"LITTLE_ENDIAN") == 0)
+ des->endian = LTT_LITTLE_ENDIAN;
+ else if(strcmp(attribute_values[i],"BIG_ENDIAN") == 0)
+ des->endian = LTT_BIG_ENDIAN;
+ }else if(strcmp("kernel_name", attribute_names[i])==0){
+ des->kernel_name = g_strdup(attribute_values[i]);
+ }else if(strcmp("kernel_release", attribute_names[i])==0){
+ des->kernel_release = g_strdup(attribute_values[i]);
+ }else if(strcmp("kernel_version", attribute_names[i])==0){
+ des->kernel_version = g_strdup(attribute_values[i]);
+ }else if(strcmp("machine", attribute_names[i])==0){
+ des->machine = g_strdup(attribute_values[i]);
+ }else if(strcmp("processor", attribute_names[i])==0){
+ des->processor = g_strdup(attribute_values[i]);
+ }else if(strcmp("hardware_platform", attribute_names[i])==0){
+ des->hardware_platform = g_strdup(attribute_values[i]);
+ }else if(strcmp("operating_system", attribute_names[i])==0){
+ des->operating_system = g_strdup(attribute_values[i]);
+ }else if(strcmp("ltt_major_version", attribute_names[i])==0){
+ des->ltt_major_version = atoi(attribute_values[i]);
+ }else if(strcmp("ltt_minor_version", attribute_names[i])==0){
+ des->ltt_minor_version = atoi(attribute_values[i]);
+ }else if(strcmp("ltt_block_size", attribute_names[i])==0){
+ des->ltt_block_size = atoi(attribute_values[i]);
+ }else{
+ *error = g_error_new(G_MARKUP_ERROR,
+ G_LOG_LEVEL_WARNING,
+ "Not a valid attribute");
+ return;
+ }
+ i++;
+ }
+}
+
+static void parser_characters (GMarkupParseContext __UNUSED__ *context,
+ const gchar *text,
+ gsize __UNUSED__ text_len,
+ gpointer user_data,
+ GError __UNUSED__ **error)
+{
+ LttSystemDescription* des = (LttSystemDescription* )user_data;
+ des->description = g_strdup(text);
+}
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_tracefile_open : open a trace file, construct a LttTracefile
+ *Input params
+ * t : the trace containing the tracefile
+ * fileName : path name of the trace file
+ * tf : the tracefile structure
+ *Return value
+ * : 0 for success, -1 otherwise.
+ ****************************************************************************/
+
+int ltt_tracefile_open(LttTrace *t, gchar * fileName, LttTracefile *tf)
+{
+ struct stat lTDFStat; /* Trace data file status */
+ struct ltt_block_start_header *header;
+
+ //open the file
+ tf->name = g_quark_from_string(fileName);
+ tf->trace = t;
+ tf->fd = g_open(fileName, O_RDONLY, 0);
+ if(tf->fd < 0){
+ g_warning("Unable to open input data file %s\n", fileName);
+ goto end;
+ }
+
+ // Get the file's status
+ if(fstat(tf->fd, &lTDFStat) < 0){
+ g_warning("Unable to get the status of the input data file %s\n", fileName);
+ goto close_file;
+ }
+
+ // Is the file large enough to contain a trace
+ if(lTDFStat.st_size < (off_t)(sizeof(BlockStart))){
+ g_print("The input data file %s does not contain a trace\n", fileName);
+ goto close_file;
+ }
+
+ /* Temporarily map the buffer start header to get trace information */
+ /* Multiple of pages aligned head */
+ tf->buffer.head = mmap(0, sizeof(struct ltt_block_start_header), PROT_READ,
+ tf->fd, 0);
+ if(tf->buffer == NULL) {
+ perror("Error in allocating memory for buffer of tracefile %s\n", fileName);
+ goto close_file;
+ }
+ g_assert(tf->buffer.head & (8-1) == 0); // make sure it's aligned.
+
+ header = (struct ltt_block_start_header*)tf->buffer.head;
+
+ if(header->traceset.magic_number == LTT_MAGIC_NUMBER)
+ tf->reverse_bo = 0;
+ else if(header->traceset.magic_number == LTT_REV_MAGIC_NUMBER)
+ tf->reverse_bo = 1;
+ else /* invalid magic number, bad tracefile ! */
+ goto unmap_file;
+
+ //store the size of the file
+ tf->file_size = lTDFStat.st_size;
+ tf->block_size = header->buf_size;
+ tf->block_number = tf->file_size / tf->block_size;
+
+ vfree(tf->buffer.head);
+ tf->buffer.head = NULL;
+
+ //read the first block
+ if(map_block(tf,0)) {
+ perror("Cannot map block %u for tracefile %s\n", 0, fileName);
+ goto close_file;
+ }
+
+ return 0;
+
+ /* Error */
+unmap_file:
+ munmap(tf->buffer.head, sizeof(struct ltt_block_start_header));
+close_file:
+ g_close(tf->fd);
+end:
+ return -1;
+}
+
+
+/*****************************************************************************
+ *Open control and per cpu tracefiles
+ ****************************************************************************/
+
+void ltt_tracefile_open_cpu(LttTrace *t, gchar * tracefile_name)
+{
+ LttTracefile * tf;
+ tf = ltt_tracefile_open(t,tracefile_name);
+ if(!tf) return;
+ t->per_cpu_tracefile_number++;
+ g_ptr_array_add(t->per_cpu_tracefiles, tf);
+}
+
+gint ltt_tracefile_open_control(LttTrace *t, gchar * control_name)
+{
+ LttTracefile * tf;
+ LttEvent ev;
+ LttFacility * f;
+ void * pos;
+ FacilityLoad fLoad;
+ unsigned int i;
+
+ tf = ltt_tracefile_open(t,control_name);
+ if(!tf) {
+ g_warning("ltt_tracefile_open_control : bad file descriptor");
+ return -1;
+ }
+ t->control_tracefile_number++;
+ g_ptr_array_add(t->control_tracefiles,tf);
+
+ //parse facilities tracefile to get base_id
+ if(strcmp(&control_name[strlen(control_name)-10],"facilities") ==0){
+ while(1){
+ if(!ltt_tracefile_read(tf,&ev)) return 0; // end of file
+
+ if(ev.event_id == TRACE_FACILITY_LOAD){
+ pos = ev.data;
+ fLoad.name = (gchar*)pos;
+ fLoad.checksum = *(LttChecksum*)(pos + strlen(fLoad.name));
+ fLoad.base_code = *(guint32 *)(pos + strlen(fLoad.name) + sizeof(LttChecksum));
+
+ for(i=0;i<t->facility_number;i++){
+ f = (LttFacility*)g_ptr_array_index(t->facilities,i);
+ if(strcmp(f->name,fLoad.name)==0 && fLoad.checksum==f->checksum){
+ f->base_id = fLoad.base_code;
+ break;
+ }
+ }
+ if(i==t->facility_number) {
+ g_warning("Facility: %s, checksum: %u is not found",
+ fLoad.name,(unsigned int)fLoad.checksum);
+ return -1;
+ }
+ }else if(ev.event_id == TRACE_BLOCK_START){
+ continue;
+ }else if(ev.event_id == TRACE_BLOCK_END){
+ break;
+ }else {
+ g_warning("Not valid facilities trace file");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_tracefile_close: close a trace file,
+ *Input params
+ * t : tracefile which will be closed
+ ****************************************************************************/
+
+void ltt_tracefile_close(LttTracefile *t)
+{
+ if(t->buffer.head != NULL)
+ munmap(t->buffer.head, t->buf_size);
+ g_close(t->fd);
+}
+
+
+/*****************************************************************************
+ *Get system information
+ ****************************************************************************/
+gint getSystemInfo(LttSystemDescription* des, gchar * pathname)
+{
+ int fd;
+ GIOChannel *iochan;
+ gchar *buf = NULL;
+ gsize length;
+
+ GMarkupParseContext * context;
+ GError * error = NULL;
+ GMarkupParser markup_parser =
+ {
+ parser_start_element,
+ NULL,
+ parser_characters,
+ NULL, /* passthrough */
+ NULL /* error */
+ };
+
+ fd = g_open(pathname, O_RDONLY, 0);
+ if(fd == -1){
+ g_warning("Can not open file : %s\n", pathname);
+ return -1;
+ }
+
+ iochan = g_io_channel_unix_new(fd);
+
+ context = g_markup_parse_context_new(&markup_parser, 0, des,NULL);
+
+ //while(fgets(buf,DIR_NAME_SIZE, fp) != NULL){
+ while(g_io_channel_read_line(iochan, &buf, &length, NULL, &error)
+ != G_IO_STATUS_EOF) {
+
+ if(error != NULL) {
+ g_warning("Can not read xml file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+ if(!g_markup_parse_context_parse(context, buf, length, &error)){
+ if(error != NULL) {
+ g_warning("Can not parse xml file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+ g_markup_parse_context_free(context);
+
+ g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
+ if(error != NULL) {
+ g_warning("Can not close file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+
+ close(fd);
+ return -1;
+ }
+ }
+ g_markup_parse_context_free(context);
+
+ g_io_channel_shutdown(iochan, FALSE, &error); /* No flush */
+ if(error != NULL) {
+ g_warning("Can not close file: \n%s\n", error->message);
+ g_error_free(error);
+ }
+
+ g_close(fd);
+
+ g_free(buf);
+ return 0;
+}
+
+/*****************************************************************************
+ *The following functions get facility/tracefile information
+ ****************************************************************************/
+
+gint getFacilityInfo(LttTrace *t, gchar* eventdefs)
+{
+ GDir * dir;
+ const gchar * name;
+ unsigned int i,j;
+ LttFacility * f;
+ LttEventType * et;
+ gchar fullname[DIR_NAME_SIZE];
+ GError * error = NULL;
+
+ dir = g_dir_open(eventdefs, 0, &error);
+
+ if(error != NULL) {
+ g_warning("Can not open directory: %s, %s\n", eventdefs, error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ while((name = g_dir_read_name(dir)) != NULL){
+ if(!g_pattern_match_simple("*.xml", name)) continue;
+ strcpy(fullname,eventdefs);
+ strcat(fullname,name);
+ ltt_facility_open(t,fullname);
+ }
+ g_dir_close(dir);
+
+ for(j=0;j<t->facility_number;j++){
+ f = (LttFacility*)g_ptr_array_index(t->facilities, j);
+ for(i=0; i<f->event_number; i++){
+ et = f->events[i];
+ setFieldsOffset(NULL, et, NULL, t);
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************
+ *A trace is specified as a pathname to the directory containing all the
+ *associated data (control tracefiles, per cpu tracefiles, event
+ *descriptions...).
+ *
+ *When a trace is closed, all the associated facilities, types and fields
+ *are released as well.
+ */
+
+
+/****************************************************************************
+ * get_absolute_pathname
+ *
+ * return the unique pathname in the system
+ *
+ * MD : Fixed this function so it uses realpath, dealing well with
+ * forgotten cases (.. were not used correctly before).
+ *
+ ****************************************************************************/
+void get_absolute_pathname(const gchar *pathname, gchar * abs_pathname)
+{
+ abs_pathname[0] = '\0';
+
+ if ( realpath (pathname, abs_pathname) != NULL)
+ return;
+ else
+ {
+ /* error, return the original path unmodified */
+ strcpy(abs_pathname, pathname);
+ return;
+ }
+ return;
+}
+
+/* Search for something like : .*_.*
+ *
+ * The left side is the name, the right side is the number.
+ */
+
+int get_tracefile_name_number(const gchar *raw_name,
+ GQuark *name,
+ guint *num)
+{
+ guint raw_name_len = strlen(raw_name);
+ gchar char_name[PATH_MAX]
+ gchar *digit_begin;
+ int i;
+ int underscore_pos;
+ long int cpu_num;
+ gchar *endptr;
+
+ for(i=raw_name_len-1;i>=0;i--) {
+ if(raw_name[i] == '_') break;
+ }
+ if(i==0) /* Either not found or name length is 0 */
+ return -1;
+ underscore_pos = i;
+
+ cpu_num = strtol(raw_name+underscore_pos+1, &endptr, 10);
+
+ if(endptr == raw_name+underscore_pos+1)
+ return -1; /* No digit */
+ if(cpu_num == LONG_MIN || cpu_num == LONG_MAX)
+ return -1; /* underflow / overflow */
+
+ char_name = strncpy(char_name, raw_name, underscore_pos);
+
+ *name = g_quark_from_string(char_name);
+ *num = cpu_num;
+
+ return 0;
+}
+
+
+void ltt_tracefile_group_destroy(gpointer data)
+{
+ GArray *group = (GArray *)data;
+ int i;
+ LttTracefile *tf;
+
+ for(i=0; i<group->len; i++) {
+ tf = &g_array_index (group, LttTracefile, i);
+ if(tf->cpu_online)
+ ltt_tracefile_close(tf);
+ }
+}
+
+gboolean ltt_tracefile_group_has_cpu_online(gpointer data)
+{
+ GArray *group = (GArray *)data;
+ int i;
+ LttTracefile *tf;
+
+ for(i=0; i<group->len; i++) {
+ tf = &g_array_index (group, LttTracefile, i);
+ if(tf->cpu_online) return 1;
+ }
+ return 0;
+}
+
+
+/* Open each tracefile under a specific directory. Put them in a
+ * GData : permits to access them using their tracefile group pathname.
+ * i.e. access control/modules tracefile group by index :
+ * "control/module".
+ *
+ * A tracefile group is simply an array where all the per cpu tracefiles sits.
+ */
+
+static int open_tracefiles(LttTrace *trace, char *root_path, GData *tracefiles)
+{
+ DIR *dir = opendir(root_path);
+ struct dirent *entry;
+ struct stat stat_buf;
+ int ret;
+ char path[PATH_MAX];
+ int path_len;
+ char *path_ptr;
+
+ if(channel_dir == NULL) {
+ perror(subchannel_name);
+ return ENOENT;
+ }
+
+ strncpy(path, root_path, PATH_MAX-1);
+ path_len = strlen(path);
+ path[path_len] = '/';
+ path_len++;
+ path_ptr = path + path_len;
+
+ while((entry = readdir(channel_dir)) != NULL) {
+
+ if(entry->d_name[0] == '.') continue;
+
+ strncpy(path_ptr, entry->d_name, PATH_MAX - path_len);
+
+ ret = stat(path, &stat_buf);
+ if(ret == -1) {
+ perror(path);
+ continue;
+ }
+
+ g_debug("Tracefile file or directory : %s\n", path);
+
+ if(S_ISDIR(stat_buf.st_mode)) {
+
+ g_debug("Entering subdirectory...\n");
+ ret = open_tracefiles(path, tracefiles);
+ if(ret < 0) continue;
+ } else if(S_ISREG(stat_buf.st_mode)) {
+ g_debug("Opening file.\n");
+
+ GQuark name;
+ guint num;
+ GArray *group;
+ LttTracefile *tf;
+ guint len;
+
+ if(get_tracefile_name_number(path, &name, &num))
+ continue; /* invalid name */
+
+ group = g_datalist_get_data(tracefiles, name);
+ if(group == NULL) {
+ /* Elements are automatically cleared when the array is allocated.
+ * It makes the cpu_online variable set to 0 : cpu offline, by default.
+ */
+ group = g_array_sized_new (FALSE, TRUE, sizeof(LttTracefile), 10);
+ g_datalist_set_data_full(tracefiles, name,
+ group, ltt_tracefile_group_destroy);
+ }
+ /* Add the per cpu tracefile to the named group */
+ unsigned int old_len = group->len;
+ if(num+1 > old_len)
+ g_array_set_size(group, num+1);
+ tf = &g_array_index (group, LttTracefile, num);
+
+ if(ltt_tracefile_open(trace, path, tf)) {
+ g_info("Error opening tracefile %s", path);
+ g_array_set_size(group, old_len);
+
+ if(!ltt_tracefile_group_has_cpu_online(group))
+ g_datalist_remove_data(tracefiles, name);
+
+ continue; /* error opening the tracefile : bad magic number ? */
+ }
+ tf->cpu_online = 1;
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+LttTrace *ltt_trace_open(const gchar *pathname)
+{
+ gchar abs_path[PATH_MAX];
+ LttTrace * t;
+ LttTracefile tf;
+ GArray *group;
+ int i;
+
+ LttTrace * t = g_new(LttTrace, 1);
+ if(!t) goto alloc_error;
+
+ get_absolute_pathname(pathname, abs_path);
+ t->pathname = g_quark_from_string(abs_path);
+
+ /* Open all the tracefiles */
+ g_datalist_init(t->tracefiles);
+ if(open_tracefiles(t, abs_path, t->tracefiles))
+ goto open_error;
+
+ /* Load trace XML event descriptions */
+ //TODO
+
+ /* Parse each trace control/facilitiesN files : get runtime fac. info */
+ group = g_datalist_get_data(t->tracefiles, LTT_TRACEFILE_NAME_FACILITIES);
+ if(group == NULL) {
+ g_error("Trace %s has no facility tracefile", abs_path);
+ goto facilities_error;
+ }
+
+ for(i=0; i<group->len; i++) {
+ tf = &g_array_index (group, LttTracefile, i);
+ //TODO
+ process_facility_tracefile(tf);
+ }
+
+
+
+ return t;
+
+ /* Error handling */
+facilities_error:
+open_error:
+ g_datalist_clear(t->tracefiles);
+ g_free(t);
+alloc_error:
+ return NULL;
+
+
+
+ LttSystemDescription * sys_description;
+ gchar eventdefs[DIR_NAME_SIZE];
+ gchar info[DIR_NAME_SIZE];
+ gchar cpu[DIR_NAME_SIZE];
+ gchar tmp[DIR_NAME_SIZE];
+ gboolean has_slash = FALSE;
+
+ //establish the pathname to different directories
+ if(abs_path[strlen(abs_path)-1] == '/')has_slash = TRUE;
+ strcpy(eventdefs,abs_path);
+ if(!has_slash)strcat(eventdefs,"/");
+ strcat(eventdefs,"eventdefs/");
+
+ strcpy(info,abs_path);
+ if(!has_slash)strcat(info,"/");
+ strcat(info,"info/");
+
+ strcpy(control,abs_path);
+ if(!has_slash)strcat(control,"/");
+ strcat(control,"control/");
+
+ strcpy(cpu,abs_path);
+ if(!has_slash)strcat(cpu,"/");
+ strcat(cpu,"cpu/");
+
+ //new trace
+ sys_description = g_new(LttSystemDescription, 1);
+ t = g_new(LttTrace, 1);
+ t->pathname = g_strdup(abs_path);
+ t->facility_number = 0;
+ t->control_tracefile_number = 0;
+ t->per_cpu_tracefile_number = 0;
+ t->system_description = sys_description;
+ t->control_tracefiles = g_ptr_array_new();
+ t->per_cpu_tracefiles = g_ptr_array_new();
+ t->facilities = g_ptr_array_new();
+ //getDataEndianType(&(t->my_arch_size), &(t->my_arch_endian));
+
+ //get system description
+ strcpy(tmp,info);
+ strcat(tmp,"system.xml");
+ if(getSystemInfo(sys_description, tmp)) {
+ g_ptr_array_free(t->facilities, TRUE);
+ g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
+ g_ptr_array_free(t->control_tracefiles, TRUE);
+ g_free(sys_description);
+ g_free(t->pathname);
+ g_free(t);
+ return NULL;
+ }
+
+ /* Set the reverse byte order between trace and reader */
+ if(sys_description->endian == LTT_LITTLE_ENDIAN
+ && G_BYTE_ORDER != G_LITTLE_ENDIAN) {
+ t->reverse_byte_order = 1;
+ } else if(sys_description->endian == LTT_BIG_ENDIAN
+ && G_BYTE_ORDER != G_BIG_ENDIAN) {
+ t->reverse_byte_order = 1;
+ } else t->reverse_byte_order = 0;
+
+ //get facilities info
+ if(getFacilityInfo(t,eventdefs)) {
+ g_ptr_array_free(t->facilities, TRUE);
+ g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
+ g_ptr_array_free(t->control_tracefiles, TRUE);
+ g_free(sys_description);
+ g_free(t->pathname);
+ g_free(t);
+ return NULL;
+ }
+
+ //get control tracefile info
+ getControlFileInfo(t,control);
+ /*
+ if(getControlFileInfo(t,control)) {
+ g_ptr_array_free(t->facilities, TRUE);
+ g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
+ g_ptr_array_free(t->control_tracefiles, TRUE);
+ g_free(sys_description);
+ g_free(t->pathname);
+ g_free(t);
+ return NULL;
+ }*/ // With fatal error
+
+ //get cpu tracefile info
+ if(getCpuFileInfo(t,cpu)) {
+ g_ptr_array_free(t->facilities, TRUE);
+ g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
+ g_ptr_array_free(t->control_tracefiles, TRUE);
+ g_free(sys_description);
+ g_free(t->pathname);
+ g_free(t);
+ return NULL;
+ }
+
+ return t;
+}
+
+char * ltt_trace_name(LttTrace *t)
+{
+ return t->pathname;
+}
+
+
+/******************************************************************************
+ * When we copy a trace, we want all the opening actions to happen again :
+ * the trace will be reopened and totally independant from the original.
+ * That's why we call ltt_trace_open.
+ *****************************************************************************/
+LttTrace *ltt_trace_copy(LttTrace *self)
+{
+ return ltt_trace_open(self->pathname);
+}
+
+void ltt_trace_close(LttTrace *t)
+{
+ unsigned int i;
+ LttTracefile * tf;
+ LttFacility * f;
+
+ g_free(t->pathname);
+
+ //free system_description
+ g_free(t->system_description->description);
+ g_free(t->system_description->node_name);
+ g_free(t->system_description->domain_name);
+ g_free(t->system_description->kernel_name);
+ g_free(t->system_description->kernel_release);
+ g_free(t->system_description->kernel_version);
+ g_free(t->system_description->machine);
+ g_free(t->system_description->processor);
+ g_free(t->system_description->hardware_platform);
+ g_free(t->system_description->operating_system);
+ g_free(t->system_description);
+
+ //free control_tracefiles
+ for(i=0;i<t->control_tracefile_number;i++){
+ tf = (LttTracefile*)g_ptr_array_index(t->control_tracefiles,i);
+ ltt_tracefile_close(tf);
+ }
+ g_ptr_array_free(t->control_tracefiles, TRUE);
+
+ //free per_cpu_tracefiles
+ for(i=0;i<t->per_cpu_tracefile_number;i++){
+ tf = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles,i);
+ ltt_tracefile_close(tf);
+ }
+ g_ptr_array_free(t->per_cpu_tracefiles, TRUE);
+
+ //free facilities
+ for(i=0;i<t->facility_number;i++){
+ f = (LttFacility*)g_ptr_array_index(t->facilities,i);
+ ltt_facility_close(f);
+ }
+ g_ptr_array_free(t->facilities, TRUE);
+
+ g_free(t);
+
+ g_blow_chunks();
+}
+
+
+/*****************************************************************************
+ *Get the system description of the trace
+ ****************************************************************************/
+
+LttSystemDescription *ltt_trace_system_description(LttTrace *t)
+{
+ return t->system_description;
+}
+
+/*****************************************************************************
+ * The following functions discover the facilities of the trace
+ ****************************************************************************/
+
+unsigned ltt_trace_facility_number(LttTrace *t)
+{
+ return (unsigned)(t->facility_number);
+}
+
+LttFacility *ltt_trace_facility_get(LttTrace *t, unsigned i)
+{
+ return (LttFacility*)g_ptr_array_index(t->facilities, i);
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_trace_facility_find : find facilities in the trace
+ *Input params
+ * t : the trace
+ * name : facility name
+ *Output params
+ * position : position of the facility in the trace
+ *Return value
+ * : the number of facilities
+ ****************************************************************************/
+
+unsigned ltt_trace_facility_find(LttTrace *t, char *name, unsigned *position)
+{
+ unsigned int i, count=0;
+ LttFacility * f;
+ for(i=0;i<t->facility_number;i++){
+ f = (LttFacility*)g_ptr_array_index(t->facilities, i);
+ if(strcmp(f->name,name)==0){
+ count++;
+ if(count==1) *position = i;
+ }else{
+ if(count) break;
+ }
+ }
+ return count;
+}
+
+/*****************************************************************************
+ * Functions to discover all the event types in the trace
+ ****************************************************************************/
+
+unsigned ltt_trace_eventtype_number(LttTrace *t)
+{
+ unsigned int i;
+ unsigned count = 0;
+ unsigned int num = t->facility_number;
+ LttFacility * f;
+
+ for(i=0;i<num;i++){
+ f = (LttFacility*)g_ptr_array_index(t->facilities, i);
+ count += f->event_number;
+ }
+ return count;
+}
+
+/* FIXME : performances could be improved with a better design for this
+ * function : sequential search through a container has never been the
+ * best on the critical path. */
+LttFacility * ltt_trace_facility_by_id(LttTrace * trace, unsigned id)
+{
+ LttFacility * facility = NULL;
+ unsigned int i;
+ unsigned int num = trace->facility_number;
+ GPtrArray *facilities = trace->facilities;
+
+ for(i=0;unlikely(i<num);){
+ LttFacility *iter_facility =
+ (LttFacility*) g_ptr_array_index(facilities,i);
+ unsigned base_id = iter_facility->base_id;
+
+ if(likely(id >= base_id &&
+ id < base_id + iter_facility->event_number)) {
+ facility = iter_facility;
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ return facility;
+}
+
+LttEventType *ltt_trace_eventtype_get(LttTrace *t, unsigned evId)
+{
+ LttEventType *event_type;
+
+ LttFacility * f;
+ f = ltt_trace_facility_by_id(t,evId);
+
+ if(unlikely(!f)) event_type = NULL;
+ else event_type = f->events[evId - f->base_id];
+
+ return event_type;
+}
+
+/*****************************************************************************
+ *There is one "per cpu" tracefile for each CPU, numbered from 0 to
+ *the maximum number of CPU in the system. When the number of CPU installed
+ *is less than the maximum, some positions are unused. There are also a
+ *number of "control" tracefiles (facilities, interrupts...).
+ ****************************************************************************/
+unsigned ltt_trace_control_tracefile_number(LttTrace *t)
+{
+ return t->control_tracefile_number;
+}
+
+unsigned ltt_trace_per_cpu_tracefile_number(LttTrace *t)
+{
+ return t->per_cpu_tracefile_number;
+}
+
+/*****************************************************************************
+ *It is possible to search for the tracefiles by name or by CPU position.
+ *The index within the tracefiles of the same type is returned if found
+ *and a negative value otherwise.
+ ****************************************************************************/
+
+int ltt_trace_control_tracefile_find(LttTrace *t, const gchar *name)
+{
+ LttTracefile * tracefile;
+ unsigned int i;
+ for(i=0;i<t->control_tracefile_number;i++){
+ tracefile = (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i);
+ if(strcmp(tracefile->name, name)==0)break;
+ }
+ if(i == t->control_tracefile_number) return -1;
+ return i;
+}
+
+/* not really useful. We just have to know that cpu tracefiles
+ * comes before control tracefiles.
+ */
+int ltt_trace_per_cpu_tracefile_find(LttTrace *t, const gchar *name)
+{
+ LttTracefile * tracefile;
+ unsigned int i;
+ for(i=0;i<t->per_cpu_tracefile_number;i++){
+ tracefile = (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i);
+ if(strcmp(tracefile->name, name)==0)break;
+ }
+ if(i == t->per_cpu_tracefile_number) return -1;
+ return i;
+}
+
+/*****************************************************************************
+ *Get a specific tracefile
+ ****************************************************************************/
+
+LttTracefile *ltt_trace_control_tracefile_get(LttTrace *t, unsigned i)
+{
+ return (LttTracefile*)g_ptr_array_index(t->control_tracefiles, i);
+}
+
+LttTracefile *ltt_trace_per_cpu_tracefile_get(LttTrace *t, unsigned i)
+{
+ return (LttTracefile*)g_ptr_array_index(t->per_cpu_tracefiles, i);
+}
+
+/*****************************************************************************
+ * Get the start time and end time of the trace
+ ****************************************************************************/
+
+static void ltt_tracefile_time_span_get(LttTracefile *tf,
+ LttTime *start, LttTime *end)
+{
+ struct ltt_block_start_header * header;
+ int err;
+
+ err = map_block(tf, 0);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ *start = { 0xFFFFFFFF, 0xFFFFFFFF };
+ } else
+ *start = tf->buffer.begin.timestamp;
+
+ err = map_block(tf, tf->num_blocks - 1); /* Last block */
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ *end = { 0, 0 };
+ } else
+ *end = tf->buffer.end.timestamp;
+}
+
+struct tracefile_time_span_get_args {
+ LttTrace *t;
+ LttTime *start;
+ LttTime *end;
+};
+
+static void group_time_span_get(GQuark name, gpointer data, gpointer user_data)
+{
+ struct tracefile_time_span_get_args *args =
+ (struct tracefile_time_span_get_args*)user_data;
+
+ GArray *group = (GArray *)data;
+ int i;
+ LttTracefile *tf;
+ LttTime tmp_start;
+ LttTime tmp_end;
+
+ for(i=0; i<group->len; i++) {
+ tf = &g_array_index (group, LttTracefile, i);
+ if(tf->cpu_online) {
+ ltt_tracefile_time_span_get(tf, &tmp_start, &tmp_end);
+ if(ltt_time_compare(*args->start, tmp_start)>0) *args->start = tmp_start;
+ if(ltt_time_compare(*args->end, tmp_end)<0) *args->end = tmp_end;
+ }
+ }
+}
+
+void ltt_trace_time_span_get(LttTrace *t, LttTime *start, LttTime *end)
+{
+ LttTime min_start = { 0xFFFFFFFF, 0xFFFFFFFF };
+ LttTime max_end = { 0, 0 };
+ struct tracefile_time_span_get_args args = { t, &min_start, &max_end };
+
+ g_datalist_foreach(t->tracefiles, &group_time_span_get, &args);
+
+ if(start != NULL) *start = min_start;
+ if(end != NULL) *end = max_end;
+
+}
+
+
+/*****************************************************************************
+ *Get the name of a tracefile
+ ****************************************************************************/
+
+char *ltt_tracefile_name(LttTracefile *tf)
+{
+ return tf->name;
+}
+
+/*****************************************************************************
+ * Get the number of blocks in the tracefile
+ ****************************************************************************/
+
+unsigned ltt_tracefile_block_number(LttTracefile *tf)
+{
+ return tf->block_number;
+}
+
+
+/* Seek to the first event in a tracefile that has a time equal or greater than
+ * the time passed in parameter.
+ *
+ * If the time parameter is outside the tracefile time span, seek to the first
+ * or the last event of the tracefile.
+ *
+ * If the time parameter is before the first event, we have to seek specially to
+ * there.
+ *
+ * If the time is after the end of the trace, get the last event.
+ *
+ * Do a binary search to find the right block, then a sequential search in the
+ * block to find the event.
+ *
+ * In the special case where the time requested fits inside a block that has no
+ * event corresponding to the requested time, the first event of the next block
+ * will be seeked.
+ *
+ * IMPORTANT NOTE : // FIXME everywhere...
+ *
+ * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time :
+ * you will jump over an event if you do.
+ *
+ * */
+
+void ltt_tracefile_seek_time(LttTracefile *tf, LttTime time)
+{
+ int err;
+ unsigned int block_num, high, low;
+
+ /* seek at the beginning of trace */
+ err = map_block(tf, 0); /* First block */
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ /* If the time is lower or equal the beginning of the trace,
+ * go to the first event. */
+ if(ltt_time_compare(time, tf->buffer.start.timestamp) <= 0) {
+ ltt_tracefile_read(tf)
+ goto found; /* There is either no event in the trace or the event points
+ to the first event in the trace */
+ }
+
+ err = map_block(tf, tf->num_blocks - 1); /* Last block */
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ /* If the time is after the end of the trace, get the last event. */
+ if(ltt_time_compare(time, tf->buffer.end.timestamp) >= 0) {
+ /* While the ltt_tracefile_read_event doesn't return NULL, continue reading
+ */
+ while(ltt_tracefile_read(tf));
+ goto found;
+ }
+
+ /* Binary search the block */
+ high = tf->num_blocks - 1;
+ low = 0;
+
+ while(1) {
+ block_num = ((high-low) / 2) + low;
+
+ err = map_block(tf, block_num);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+ if(ltt_time_compare(time, tf->buffer.start.timestamp) < 0) {
+ /* go to lower part */
+ high = block_num;
+ } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
+ /* go to higher part */
+ low = block_num;
+ } else {/* The event is right in the buffer!
+ (or in the next buffer first event) */
+ while(1) {
+ ltt_tracefile_read(tf);
+ if(ltt_time_compare(time, tf->event.event_time) >= 0)
+ break;
+ }
+ goto found;
+ }
+ }
+
+found:
+
+ return;
+
+ /* Error handling */
+fail:
+ g_error("ltt_tracefile_seek_time failed on tracefile %s",
+ g_quark_to_string(tf->name));
+}
+
+
+int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) {
+
+ int err;
+
+ if(ep->tracefile != tf) {
+ goto fail;
+ }
+
+ err = map_block(tf, ep->block);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ tf->event.offset = ep->offset;
+
+ if(!ltt_tracefile_read(tf)) goto fail;
+
+ return;
+
+fail:
+ g_error("ltt_tracefile_seek_time failed on tracefile %s",
+ g_quark_to_string(tf->name));
+}
+
+
+
+/*****************************************************************************
+ * Seek to the first event with position equal or larger to ep
+ *
+ * Modified by Mathieu Desnoyers to used faster offset position instead of
+ * re-reading the whole buffer.
+ ****************************************************************************/
+
+void ltt_tracefile_seek_position(LttTracefile *t, const LttEventPosition *ep)
+{
+ //if we are at the right place, just return
+ if(likely(t->which_block == ep->block_num && t->which_event == ep->event_num))
+ return;
+
+ if(likely(t->which_block == ep->block_num)) updateTracefile(t);
+ else readBlock(t,ep->block_num);
+ //event offset is available
+ if(likely(ep->old_position)){
+ int err;
+
+ t->which_event = ep->event_num;
+ t->cur_event_pos = t->buffer + ep->event_offset;
+ t->prev_event_time = ep->event_time;
+ t->current_event_time = ep->event_time;
+ t->cur_heart_beat_number = ep->heart_beat_number;
+ t->cur_cycle_count = ep->event_cycle_count;
+
+ /* This is a workaround for fast position seek */
+ t->last_event_pos = ep->last_event_pos;
+ t->prev_block_end_time = ep->prev_block_end_time;
+ t->prev_event_time = ep->prev_event_time;
+ t->pre_cycle_count = ep->pre_cycle_count;
+ t->count = ep->count;
+ t->overflow_nsec = ep->overflow_nsec;
+ t->last_heartbeat = ep->last_heartbeat;
+ /* end of workaround */
+
+ //update the fields of the current event and go to the next event
+ err = skipEvent(t);
+ if(unlikely(err == ERANGE)) g_error("event id is out of range\n");
+
+ return;
+ }
+
+ //only block number and event index are available
+ //MD: warning : this is slow!
+ g_warning("using slow O(n) tracefile seek position");
+
+ LttEvent event;
+ while(likely(t->which_event < ep->event_num)) ltt_tracefile_read(t, &event);
+
+ return;
+}
+
+/* Calculate the real event time based on the buffer boundaries */
+LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event)
+{
+ LttTime time;
+
+ g_assert(t->trace->has_tsc);
+
+ time = ltt_time_from_uint64(
+ (guint64)tf->buffer.tsc*tf->buffer.nsecs_per_cycle);
+ time = ltt_time_add(tf->buffer.begin.timestamp, time);
+
+ return time;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_tracefile_read : Read the next event in the tracefile
+ *Input params
+ * t : tracefile
+ *Return value
+ * LttEvent * : an event to be processed
+ * Note : it points to the current tf->event. It will be overwritten
+ * by the next call to ltt_tracefile_read or any map_block.
+ *
+ * Returns NULL on end of trace (or error).
+ *
+ *
+ * This function does make the tracefile event structure point to the event
+ * currently pointed to by the
+ ****************************************************************************/
+
+LttEvent *ltt_tracefile_read(LttTracefile *tf)
+{
+ int err;
+ LttFacility *f;
+ void * pos;
+
+ /* Skip the current event to go to the next, or point to the
+ * t->buffer.head + t->buffer.lost_size if we were on the last
+ * event of a buffer.
+ */
+ err = ltt_seek_next_event(tf);
+ if(unlikely(err == ERANGE)) {
+ g_error("event id is out of range\n");
+ return NULL;
+ }
+
+ pos = tf->event.offset;
+
+ /* Are we at the end of the buffer ? */
+ if(unlikely(pos == tf->buffer.head + tf->buffer.lost_size)) {
+ if(unlikely(tf->buffer.index == tf->num_blocks-1)){ /* end of trace ? */
+ return NULL;
+ } else {
+ /* get next block */
+ err = map_block(tf, tf->buffer.index + 1);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ return NULL;
+ }
+ pos = tf->event.offset;
+ }
+ }
+
+ /* Read event header */
+
+ //TODO align
+
+ if(tf->trace->has_tsc) {
+ event->time.timestamp = ltt_get_uint32(LTT_GET_BO(t),
+ tf->cur_event_pos);
+ /* 32 bits -> 64 bits tsc */
+ if(event->time.timestamp < (0xFFFFFFFFULL&tf->buffer.tsc)) {
+ tf->buffer.tsc = ((tf->buffer.tsc&0xFFFFFFFF00000000ULL)
+ + 0x100000000ULL)
+ | (guint64)event->time.timestamp;
+
+ event->event_time = ltt_interpolate_time(tf, event);
+ } else {
+ /* no overflow */
+ tf->buffer.tsc = (tf->buffer.tsc&0xFFFFFFFF00000000ULL)
+ | (guint64)event->time.timestamp;
+ }
+ pos += sizeof(uint32);
+ } else {
+ event->time.delta = ltt_get_uint32(LTT_GET_BO(tf),
+ tf->cur_event_pos);
+ tf->buffer.tsc = 0;
+
+ event->event_time = ltt_time_add(tf->buffer.begin.timestamp,
+ event->time_delta);
+ pos += sizeof(uint32);
+ }
+
+ event->facility_id = ltt_get_uint8(LTT_GET_BO(tf),
+ tf->cur_event_pos);
+ pos += sizeof(uint8);
+
+ event->event_id = ltt_get_uint8(LTT_GET_BO(tf),
+ tf->cur_event_pos);
+ pos += sizeof(uint8);
+
+ event->data = tf->cur_event_pos + EVENT_HEADER_SIZE;
+
+ event->data = pos;
+
+ /* do event specific operation */
+
+ /* do something if its an heartbeat event : increment the heartbeat count */
+ if(event->facility_id != 0) { /* except core */
+ f = (LttFacility*)g_ptr_array_index(tf->trace->facilities,
+ event->facility_id);
+ g_assert(f != NULL);
+
+ if(unlikely(ltt_facility_name(f)
+ != LTT_FACILITY_NAME_HEARTBEAT)) {
+ LttEventType *et = ltt_facility_eventtype_get_by_name(f,
+ LTT_EVENT_NAME_HEARTBEAT);
+ if(et->id == event->event_id)
+ t->cur_heart_beat_number++;
+
+ }
+ }
+
+ return event;
+}
+
+/****************************************************************************
+ *Function name
+ * readFile : wrap function to read from a file
+ *Input Params
+ * fd : file descriptor
+ * buf : buf to contain the content
+ * size : number of bytes to be read
+ * mesg : message to be printed if some thing goes wrong
+ *return value
+ * 0 : success
+ * EIO : can not read from the file
+ ****************************************************************************/
+#if 0
+int readFile(int fd, void * buf, size_t size, char * mesg)
+{
+ ssize_t nbBytes = read(fd, buf, size);
+
+ if((size_t)nbBytes != size) {
+ if(nbBytes < 0) {
+ perror("Error in readFile : ");
+ } else {
+ g_warning("%s",mesg);
+ }
+ return EIO;
+ }
+ return 0;
+}
+#endif //0
+
+/****************************************************************************
+ *Function name
+ * map_block : map a block from the file
+ *Input Params
+ * lttdes : ltt trace file
+ * whichBlock : the block which will be read
+ *return value
+ * 0 : success
+ * EINVAL : lseek fail
+ * EIO : can not read from the file
+ ****************************************************************************/
+
+static int map_block(LttTracefile * tf, int block_num)
+{
+ struct ltt_block_start_header *header;
+
+ g_assert(block_num < tf->num_blocks);
+
+ if(tf->buffer.head != NULL)
+ munmap(tf->buffer.head, tf->buf_size);
+
+ /* Multiple of pages aligned head */
+ tf->buffer.head = mmap(0, tf->block_size, PROT_READ, tf->fd,
+ (off_t)tf->block_size * (off_t)block_num);
+
+ if(tf->buffer.head == NULL) {
+ perror("Error in allocating memory for buffer of tracefile %s\n", fileName);
+ goto map_error;
+ }
+ g_assert(tf->buffer.head & (8-1) == 0); // make sure it's aligned.
+
+
+ tf->buffer.index = block_num;
+
+ header = (struct ltt_block_start_header*)tf->buffer.head;
+
+ tf->buffer.begin.timestamp = ltt_get_uint64(LTT_GET_BO(tf),
+ header->begin.timestamp)
+ * NSEC_PER_USEC;
+ tf->buffer.begin.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
+ header->begin.cycle_count);
+ tf->buffer.end.timestamp = ltt_get_uint64(LTT_GET_BO(tf),
+ header->end.timestamp)
+ * NSEC_PER_USEC;
+ tf->buffer.end.cycle_count = ltt_get_uint64(LTT_GET_BO(tf),
+ header->end.cycle_count);
+ tf->buffer.lost_size = ltt_get_uint32(LTT_GET_BO(tf),
+ header->lost_size);
+
+ tf->buffer.tsc = tf->buffer.begin.cycle_count;
+
+ /* FIXME
+ * eventually support variable buffer size : will need a partial pre-read of
+ * the headers to create an index when we open the trace... eventually. */
+ g_assert(tf->block_size == ltt_get_uint32(header->buf_size));
+
+ /* Now that the buffer is mapped, calculate the time interpolation for the
+ * block. */
+
+ tf->buffer.nsecs_per_cycle = calc_nsecs_per_cycle(&tf->buffer);
+
+ /* Make the current event point to the beginning of the buffer :
+ * it means that the event read must get the first event. */
+ tf->event.tracefile = tf;
+ tf->event.block = block_num;
+ tf->event.offset = tf->buffer.head;
+
+ return 0;
+
+map_error:
+ return -errno;
+
+}
+
+/*****************************************************************************
+ *Function name
+ * updateTracefile : reinitialize the info of the block which is already
+ * in the buffer
+ *Input params
+ * tf : tracefile
+ ****************************************************************************/
+
+void updateTracefile(LttTracefile * tf)
+{
+ tf->which_event = 1;
+ tf->cur_event_pos = tf->buffer;
+ tf->current_event_time = getEventTime(tf);
+ tf->cur_heart_beat_number = 0;
+
+ tf->prev_event_time.tv_sec = 0;
+ tf->prev_event_time.tv_nsec = 0;
+ tf->count = 0;
+
+ tf->overflow_nsec =
+ (-((double)ltt_get_uint64(tf->trace->reverse_byte_order,
+ &tf->a_block_start->cycle_count))
+ * tf->nsec_per_cycle);
+
+}
+
+/* Take the tf current event offset and use the event facility id and event id
+ * to figure out where is the next event offset.
+ *
+ * This is an internal function not aiming at being used elsewhere : it will
+ * not jump over the current block limits. Please consider using
+ * ltt_tracefile_read to do this.
+ *
+ * Returns 0 on success
+ * ERANGE if we are at the end of the buffer.
+ */
+static int ltt_seek_next_event(LttTracefile *tf)
+{
+ void *pos;
+
+ /* seek over the buffer header if we are at the buffer start */
+ if(tf->event.offset == tf->buffer.head) {
+ tf->event.offset += sizeof(struct ltt_block_start_header);
+ goto found;
+ }
+
+ /* if we are at the end of a buffer, generate an error, not supposed to
+ * happen. */
+ if(tf->event.offset == tf->buffer.head + tf->buffer.lost_size)
+ goto error;
+
+ pos = tf->event.data;
+
+ pos += ltt_facility_get_event_size(tf->event.facility_id, tf->event.event_id);
+
+ tf->event.offset = pos;
+
+found:
+ return 0;
+
+error:
+ g_error("Error in ltt_seek_next_event for tracefile %s",
+ g_quark_to_string(tf->name));
+ return ERANGE;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * calc_nsecs_per_cycle : calculate nsecs per cycle for current block
+ *Input Params
+ * t : tracefile
+ ****************************************************************************/
+
+static double calc_nsecs_per_cycle(LttTracefile * t)
+{
+ LttTime lBufTotalTime; /* Total time for this buffer */
+ double lBufTotalNSec; /* Total time for this buffer in nsecs */
+ LttCycleCount lBufTotalCycle;/* Total cycles for this buffer */
+
+ /* Calculate the total time for this buffer */
+ lBufTotalTime = ltt_time_sub(
+ ltt_get_time(t->buffer.end.timestamp),
+ ltt_get_time(t->buffer.begin.timestamp));
+
+ /* Calculate the total cycles for this bufffer */
+ lBufTotalCycle = t->buffer.end.cycle_count;
+ lBufTotalCycle -= t->buffer.start.cycle_count;
+
+ /* Convert the total time to double */
+ lBufTotalNSec = ltt_time_to_double(lBufTotalTime);
+
+ return lBufTotalNSec / (double)lBufTotalCycle;
+
+}
+
+/*****************************************************************************
+ *Function name
+ * setFieldsOffset : set offset of the fields
+ *Input params
+ * tracefile : opened trace file
+ * evT : the event type
+ * evD : event data, it may be NULL
+ ****************************************************************************/
+
+void setFieldsOffset(LttTracefile *tf,LttEventType *evT,void *evD,LttTrace* t)
+{
+ LttField * rootFld = evT->root_field;
+ // rootFld->base_address = evD;
+
+ if(likely(rootFld))
+ rootFld->field_size = getFieldtypeSize(tf, evT, 0,0,rootFld, evD,t);
+}
+
+/*****************************************************************************
+ *Function name
+ * getFieldtypeSize: get the size of the field type (primitive type)
+ *Input params
+ * tracefile : opened trace file
+ * evT : event type
+ * offsetRoot : offset from the root
+ * offsetParent : offset from the parrent
+ * fld : field
+ * evD : event data, it may be NULL
+ *Return value
+ * int : size of the field
+ ****************************************************************************/
+
+static inline gint getFieldtypeSize(LttTracefile * t,
+ LttEventType * evT, gint offsetRoot,
+ gint offsetParent, LttField * fld, void *evD, LttTrace *trace)
+{
+ gint size, size1, element_number, i, offset1, offset2;
+ LttType * type = fld->field_type;
+
+ if(unlikely(t && evT->latest_block==t->which_block &&
+ evT->latest_event==t->which_event)){
+ size = fld->field_size;
+ goto end_getFieldtypeSize;
+ } else {
+ /* This likely has been tested with gcov : half of them.. */
+ if(unlikely(fld->field_fixed == 1)){
+ /* tested : none */
+ if(unlikely(fld == evT->root_field)) {
+ size = fld->field_size;
+ goto end_getFieldtypeSize;
+ }
+ }
+
+ /* From gcov profiling : half string, half struct, can we gain something
+ * from that ? (Mathieu) */
+ switch(type->type_class) {
+ case LTT_ARRAY:
+ element_number = (int) type->element_number;
+ if(fld->field_fixed == -1){
+ size = getFieldtypeSize(t, evT, offsetRoot,
+ 0,fld->child[0], NULL, trace);
+ if(size == 0){ //has string or sequence
+ fld->field_fixed = 0;
+ }else{
+ fld->field_fixed = 1;
+ size *= element_number;
+ }
+ }else if(fld->field_fixed == 0){// has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += getFieldtypeSize(t, evT, offsetRoot+size,size,
+ fld->child[0], evD+size, trace);
+ }
+ }else size = fld->field_size;
+ if(unlikely(!evD)){
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+ }
+
+ break;
+
+ case LTT_SEQUENCE:
+ size1 = (int) ltt_type_size(trace, type);
+ if(fld->field_fixed == -1){
+ fld->sequ_number_size = size1;
+ fld->field_fixed = 0;
+ size = getFieldtypeSize(t, evT, offsetRoot,
+ 0,fld->child[0], NULL, trace);
+ fld->element_size = size;
+ }else{//0: sequence
+ element_number = getIntNumber(t->trace->reverse_byte_order,size1,evD);
+ type->element_number = element_number;
+ if(fld->element_size > 0){
+ size = element_number * fld->element_size;
+ }else{//sequence has string or sequence
+ size = 0;
+ for(i=0;i<element_number;i++){
+ size += getFieldtypeSize(t, evT, offsetRoot+size+size1,size+size1,
+ fld->child[0], evD+size+size1, trace);
+ }
+ }
+ size += size1;
+ }
+ if(unlikely(!evD)){
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+ }
+
+ break;
+
+ case LTT_STRING:
+ size = 0;
+ if(fld->field_fixed == -1){
+ fld->field_fixed = 0;
+ }else{//0: string
+ /* Hope my implementation is faster than strlen (Mathieu) */
+ char *ptr=(char*)evD;
+ size = 1;
+ /* from gcov : many many strings are empty, make it the common case.*/
+ while(unlikely(*ptr != '\0')) { size++; ptr++; }
+ //size = ptr - (char*)evD + 1; //include end : '\0'
+ }
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+
+ break;
+
+ case LTT_STRUCT:
+ element_number = (int) type->element_number;
+ size = 0;
+ /* tested with gcov */
+ if(unlikely(fld->field_fixed == -1)){
+ offset1 = offsetRoot;
+ offset2 = 0;
+ for(i=0;i<element_number;i++){
+ size1=getFieldtypeSize(t, evT,offset1,offset2,
+ fld->child[i], NULL, trace);
+ if(likely(size1 > 0 && size >= 0)){
+ size += size1;
+ if(likely(offset1 >= 0)) offset1 += size1;
+ offset2 += size1;
+ }else{
+ size = -1;
+ offset1 = -1;
+ offset2 = -1;
+ }
+ }
+ if(unlikely(size == -1)){
+ fld->field_fixed = 0;
+ size = 0;
+ }else fld->field_fixed = 1;
+ }else if(likely(fld->field_fixed == 0)){
+ offset1 = offsetRoot;
+ offset2 = 0;
+ for(i=0;unlikely(i<element_number);i++){
+ size=getFieldtypeSize(t,evT,offset1,offset2,
+ fld->child[i],evD+offset2, trace);
+ offset1 += size;
+ offset2 += size;
+ }
+ size = offset2;
+ }else size = fld->field_size;
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+ break;
+
+ default:
+ if(unlikely(fld->field_fixed == -1)){
+ size = (int) ltt_type_size(trace, type);
+ fld->field_fixed = 1;
+ }else size = fld->field_size;
+ if(unlikely(!evD)){
+ fld->fixed_root = (offsetRoot==-1) ? 0 : 1;
+ fld->fixed_parent = (offsetParent==-1) ? 0 : 1;
+ }
+ break;
+ }
+ }
+
+ fld->offset_root = offsetRoot;
+ fld->offset_parent = offsetParent;
+ fld->field_size = size;
+
+end_getFieldtypeSize:
+
+ return size;
+}
+
+
+/*****************************************************************************
+ *Function name
+ * getIntNumber : get an integer number
+ *Input params
+ * size : the size of the integer
+ * evD : the event data
+ *Return value
+ * gint64 : a 64 bits integer
+ ****************************************************************************/
+
+gint64 getIntNumber(gboolean reverse_byte_order, int size, void *evD)
+{
+ gint64 i;
+
+ switch(size) {
+ case 1: i = *((gint8*)evD); break;
+ case 2: i = ltt_get_int16(reverse_byte_order, evD); break;
+ case 4: i = ltt_get_int32(reverse_byte_order, evD); break;
+ case 8: i = ltt_get_int64(reverse_byte_order, evD); break;
+ default: i = ltt_get_int64(reverse_byte_order, evD);
+ g_critical("getIntNumber : integer size %d unknown", size);
+ break;
+ }
+
+ return i;
+}
+#if 0
+/*****************************************************************************
+ *Function name
+ * getDataEndianType : get the data type size and endian type of the local
+ * machine
+ *Input params
+ * size : size of data type
+ * endian : endian type, little or big
+ ****************************************************************************/
+
+void getDataEndianType(LttArchSize * size, LttArchEndian * endian)
+{
+ int i = 1;
+ char c = (char) i;
+ int sizeInt=sizeof(int), sizeLong=sizeof(long), sizePointer=sizeof(void *);
+
+ if(c == 1) *endian = LTT_LITTLE_ENDIAN;
+ else *endian = LTT_BIG_ENDIAN;
+
+ if(sizeInt == 2 && sizeLong == 4 && sizePointer == 4)
+ *size = LTT_LP32;
+ else if(sizeInt == 4 && sizeLong == 4 && sizePointer == 4)
+ *size = LTT_ILP32;
+ else if(sizeInt == 4 && sizeLong == 8 && sizePointer == 8)
+ *size = LTT_LP64;
+ else if(sizeInt == 8 && sizeLong == 8 && sizePointer == 8)
+ *size = LTT_ILP64;
+ else *size = LTT_UNKNOWN;
+}
+#endif //0
+/* get the node name of the system */
+
+char * ltt_trace_system_description_node_name (LttSystemDescription * s)
+{
+ return s->node_name;
+}
+
+
+/* get the domain name of the system */
+
+char * ltt_trace_system_description_domain_name (LttSystemDescription * s)
+{
+ return s->domain_name;
+}
+
+
+/* get the description of the system */
+
+char * ltt_trace_system_description_description (LttSystemDescription * s)
+{
+ return s->description;
+}
+
+
+/* get the start time of the trace */
+
+LttTime ltt_trace_system_description_trace_start_time(LttSystemDescription *s)
+{
+ return s->trace_start;
+}
+
+
+LttTracefile *ltt_tracefile_new()
+{
+ return g_new(LttTracefile, 1);
+}
+
+void ltt_tracefile_destroy(LttTracefile *tf)
+{
+ g_free(tf);
+}
+
+void ltt_tracefile_copy(LttTracefile *dest, const LttTracefile *src)
+{
+ *dest = *src;
+}
+
+/* Before library loading... */
+
+static void __attribute__((constructor)) init(void)
+{
+ LTT_FACILITY_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
+ LTT_EVENT_NAME_HEARTBEAT = g_quark_from_string("heartbeat");
+
+ LTT_TRACEFILE_NAME_FACILITIES = g_quark_from_string("control/facilities");
+}
+
--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2003-2004 Xiangxiu Yang, Mathieu Desnoyers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "parser.h"
+#include <ltt/ltt.h>
+#include "ltt-private.h"
+#include <ltt/type.h>
+
+static unsigned intSizes[] = {
+ sizeof(int8_t), sizeof(int16_t), sizeof(int32_t), sizeof(int64_t),
+ sizeof(short) };
+
+typedef enum _intSizesNames { SIZE_INT8, SIZE_INT16, SIZE_INT32,
+ SIZE_INT64, SIZE_SHORT, INT_SIZES_NUMBER }
+ intSizesNames;
+
+
+static unsigned floatSizes[] = {
+ 0, 0, sizeof(float), sizeof(double), 0, sizeof(float), sizeof(double) };
+
+#define FLOAT_SIZES_NUMBER 7
+
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_name : get the name of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * char * : the name of the event type
+ ****************************************************************************/
+
+gchar *ltt_eventtype_name(LttEventType *et)
+{
+ return et->name;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_description : get the description of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * char * : the description of the event type
+ ****************************************************************************/
+
+gchar *ltt_eventtype_description(LttEventType *et)
+{
+ return et->description;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_facility : get the facility which contains the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * LttFacility * : the facility
+ ****************************************************************************/
+
+LttFacility *ltt_eventtype_facility(LttEventType *et)
+{
+ return et->facility;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_relative_id : get the relative id of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * unsigned : the relative id
+ ****************************************************************************/
+
+unsigned ltt_eventtype_relative_id(LttEventType *et)
+{
+ return et->index;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_id : get the id of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * unsigned : the id
+ ****************************************************************************/
+
+unsigned ltt_eventtype_id(LttEventType *et)
+{
+ return et->facility->base_id + et->index;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_type : get the type of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * LttType * : the type of the event type
+ ****************************************************************************/
+
+LttType *ltt_eventtype_type(LttEventType *et)
+{
+ if(unlikely(!et->root_field)) return NULL;
+ else return et->root_field->field_type;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_eventtype_field : get the root filed of the event type
+ *Input params
+ * et : an event type
+ *Return value
+ * LttField * : the root filed of the event type
+ ****************************************************************************/
+
+LttField *ltt_eventtype_field(LttEventType *et)
+{
+ return et->root_field;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_name : get the name of the type
+ *Input params
+ * t : a type
+ *Return value
+ * char * : the name of the type
+ ****************************************************************************/
+
+gchar *ltt_type_name(LttType *t)
+{
+ return t->element_name;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_class : get the type class of the type
+ *Input params
+ * t : a type
+ *Return value
+ * LttTypeEnum : the type class of the type
+ ****************************************************************************/
+
+LttTypeEnum ltt_type_class(LttType *t)
+{
+ return t->type_class;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_size : obtain the type size. The size is the number of bytes
+ * for primitive types (INT, UINT, FLOAT, ENUM), or the
+ * size for the unsigned integer length count for sequences
+ *Input params
+ * tf : trace file
+ * t : a type
+ *Return value
+ * unsigned : the type size
+ * returns 0 if erroneous, and show a critical warning message.
+ ****************************************************************************/
+
+unsigned ltt_type_size(LttTrace * trace, LttType *t)
+{
+ unsigned size;
+ if(unlikely(t->type_class==LTT_STRUCT || t->type_class==LTT_ARRAY ||
+ t->type_class==LTT_STRING || t->type_class==LTT_UNION)) {
+ size = 0;
+ } else {
+ if(t->type_class == LTT_FLOAT){
+ size = floatSizes[t->size];
+ }else{
+ if(likely(t->size < INT_SIZES_NUMBER))
+ size = intSizes[t->size];
+ else{
+ LttArchSize archsize = trace->system_description->size;
+ if(archsize == LTT_LP32){
+ if(t->size == 5) size = intSizes[SIZE_INT16];
+ else size = intSizes[SIZE_INT32];
+ }
+ else if(archsize == LTT_ILP32 || archsize == LTT_LP64){
+ if(t->size == 5) size = intSizes[SIZE_INT32];
+ else{
+ if(archsize == LTT_ILP32) size = intSizes[SIZE_INT32];
+ else size = intSizes[SIZE_INT64];
+ }
+ }
+ else if(archsize == LTT_ILP64) size = intSizes[SIZE_INT64];
+ }
+ }
+ }
+
+ return size;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_element_type : obtain the type of nested elements for arrays
+ * and sequences
+ *Input params
+ * t : a type
+ *Return value
+ * LttType : the type of nested element of array or sequence
+ ****************************************************************************/
+
+LttType *ltt_type_element_type(LttType *t)
+{
+ LttType *element_type;
+
+ if(unlikely(t->type_class != LTT_ARRAY && t->type_class != LTT_SEQUENCE))
+ element_type = NULL;
+ else
+ element_type = t->element_type[0];
+
+ return element_type;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_element_number : obtain the number of elements for arrays
+ *Input params
+ * t : a type
+ *Return value
+ * unsigned : the number of elements for arrays
+ ****************************************************************************/
+
+unsigned ltt_type_element_number(LttType *t)
+{
+ unsigned ret = 0;
+
+ if(likely(t->type_class == LTT_ARRAY))
+ ret = t->element_number;
+
+ return ret;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_member_number : obtain the number of data members for structure
+ *Input params
+ * t : a type
+ *Return value
+ * unsigned : the number of members for structure
+ ****************************************************************************/
+
+unsigned ltt_type_member_number(LttType *t)
+{
+ unsigned ret = 0;
+
+ if(likely(t->type_class == LTT_STRUCT || t->type_class == LTT_UNION))
+ ret =t->element_number;
+
+ return ret;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_type_member_type : obtain the type of a data member in a structure
+ * or union.
+ *Input params
+ * t : a type
+ * i : index of the member
+ *Return value
+ * LttType * : the type of structure member
+ ****************************************************************************/
+
+LttType *ltt_type_member_type(LttType *t, unsigned i, gchar ** name)
+{
+ LttType *member_type = NULL;
+
+ if(unlikely( (t->type_class != LTT_STRUCT
+ && t->type_class != LTT_UNION)
+ ||
+ (i >= t->element_number)
+ )) {
+ *name = NULL;
+ } else {
+ *name = t->element_type[i]->element_name;
+ member_type = t->element_type[i];
+ }
+
+ return member_type;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_enum_string_get : for enumerations, obtain the symbolic string
+ * associated with a value (0 to n - 1 for an
+ * enumeration of n elements)
+ *Input params
+ * t : a type
+ * i : index of the member
+ *Return value
+ * char * : symbolic string associated with a value
+ ****************************************************************************/
+
+char *ltt_enum_string_get(LttType *t, unsigned i)
+{
+ gchar *string = NULL;
+
+ if(likely(t->type_class == LTT_ENUM && i < t->element_number))
+ string = t->enum_strings[i];
+
+ return string;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_field_element : obtain the field of nested elements for arrays and
+ * sequence
+ *Input params
+ * f : a field
+ *Return value
+ * LttField * : the field of the nested element
+ ****************************************************************************/
+
+LttField *ltt_field_element(LttField *f)
+{
+ LttField *nest = NULL;
+
+ if(likely(f->field_type->type_class == LTT_ARRAY ||
+ f->field_type->type_class == LTT_SEQUENCE))
+ nest = f->child[0];
+
+ return nest;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_field_member : obtain the field of data members for structure
+ *Input params
+ * f : a field
+ * i : index of member field
+ *Return value
+ * LttField * : the field of the nested element
+ ****************************************************************************/
+
+LttField *ltt_field_member(LttField *f, unsigned i)
+{
+ LttField *field_member;
+
+ if(unlikely( f->field_type->type_class != LTT_STRUCT
+ && f->field_type->type_class != LTT_UNION)
+ || i >= f->field_type->element_number )
+ field_member = NULL;
+ else
+ field_member = f->child[i];
+
+ return field_member;
+}
+
+/*****************************************************************************
+ *Function name
+ * ltt_field_type : obtain the type of the field
+ *Input params
+ * f : a field
+ *Return value
+ * ltt_tyoe * : the type of field
+ ****************************************************************************/
+
+LttType *ltt_field_type(LttField *f)
+{
+ if(unlikely(!f))return NULL;
+ return f->field_type;
+}
+
+int ltt_field_size(LttField * f)
+{
+ if(unlikely(!f))return 0;
+ return f->field_size;
+}
--- /dev/null
+/* This file is part of the Linux Trace Toolkit trace reading library
+ * Copyright (C) 2003-2004 Michel Dagenais
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License Version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TYPE_H
+#define TYPE_H
+
+
+/* Different types allowed */
+
+#include <ltt/ltt.h>
+
+
+/* All event types, data types and fields belong to their trace and
+ are released at the same time. */
+
+/* Obtain the name, description, facility, facility relative id, global id,
+ type and root field for an eventtype */
+
+gchar *ltt_eventtype_name(LttEventType *et);
+
+gchar *ltt_eventtype_description(LttEventType *et);
+
+LttFacility *ltt_eventtype_facility(LttEventType *et);
+
+unsigned ltt_eventtype_relative_id(LttEventType *et);
+
+unsigned ltt_eventtype_id(LttEventType *et);
+
+LttType *ltt_eventtype_type(LttEventType *et);
+
+LttField *ltt_eventtype_field(LttEventType *et);
+
+
+/* obtain the type name and size. The size is the number of bytes for
+ primitive types (INT, UINT, FLOAT, ENUM), or the size for the unsigned
+ integer length count for sequences. */
+
+gchar *ltt_type_name(LttType *t);
+
+LttTypeEnum ltt_type_class(LttType *t);
+
+unsigned ltt_type_size(LttTrace *trace, LttType *t);
+
+
+/* The type of nested elements for arrays and sequences. */
+
+LttType *ltt_type_element_type(LttType *t);
+
+
+/* The number of elements for arrays. */
+
+unsigned ltt_type_element_number(LttType *t);
+
+
+/* The number of data members for structures and unions. */
+
+unsigned ltt_type_member_number(LttType *t);
+
+
+/* The type of a data member in a structure. */
+
+LttType *ltt_type_member_type(LttType *t, unsigned i, char ** name);
+
+
+/* For enumerations, obtain the symbolic string associated with a value
+ (0 to n - 1 for an enumeration of n elements). */
+
+gchar *ltt_enum_string_get(LttType *t, unsigned i);
+
+
+/* The fields form a tree representing a depth first search of the
+ corresponding event type directed acyclic graph. Fields for arrays and
+ sequences simply point to one nested field representing the currently
+ selected element among all the (identically typed) elements. For structures,
+ a nested field exists for each data member. Each field stores the
+ platform/trace specific offset values (for efficient access) and
+ points back to the corresponding LttType for the rest. */
+
+LttField *ltt_field_element(LttField *f);
+
+LttField *ltt_field_member(LttField *f, unsigned i);
+
+LttType *ltt_field_type(LttField *f);
+
+int ltt_field_size(LttField * f);
+
+#endif // TYPE_H