// Copyright (C) 2005, 2006 IBM Corp. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. %{ #if defined(ASCII_TRACE) #ifndef _FMT_ #define _FMT_ unsigned int #endif #else #ifndef _FMT_ #define _FMT_ int64_t #endif #endif %} function lket_trace_header_init() %{ /* header info for binary format*/ #if !defined(ASCII_TRACE) #define MAGIC_NUMBER 0xAEFCDB6B #define LKET_TRACE_VER_MAJOR 0x01 #define LKET_TRACE_VER_MINOR 0x01 /* used for user customization */ #define LITTLE_ENDIAN 0x01 #define BIG_ENDIAN 0x02 #define BITS_WIDTH 64 /* 32-bit or 64-bit environment*/ _stp_printf("%4b%2n%1b%1b%1b%1b", (_FMT_)MAGIC_NUMBER, (_FMT_)LKET_TRACE_VER_MAJOR, (_FMT_)LKET_TRACE_VER_MINOR, (_FMT_)BIG_ENDIAN, (_FMT_)BITS_WIDTH); _stp_print_flush(); #endif %} function lket_trace_init() { lket_trace_header_init() } %{ #ifndef __LKET_TRACE__ #define __LKET_TRACE__ #define LKET_PKT_BT 2 #define MAX_FMT_LEN 128 char new_sysfmt[MAX_FMT_LEN] = "\n%d|%d|%d|%d|%d|%d|%d|%d"; #define NEW_SYSFMT_START 24 void fmt_change(char *oldfmt, char *newfmt, int newfmt_start) { char *old_ptr, *new_ptr; old_ptr = oldfmt; new_ptr = newfmt + newfmt_start; while(*old_ptr != 0 && (new_ptr - newfmt) < MAX_FMT_LEN) { if(*old_ptr != '%') { *new_ptr++ = *old_ptr++; continue; } else { *new_ptr++ = '|'; /* delimier to make it readable */ *new_ptr++ = *old_ptr++; while( *old_ptr == 'L' || *old_ptr == 'l' || isdigit(*old_ptr) ) { *new_ptr++ = *old_ptr++; } if( *old_ptr == 'b') { if(isdigit(*(old_ptr-1))) { if(*(old_ptr-1) == '1' || *(old_ptr-1) == '2' || *(old_ptr-1) == '3' || *(old_ptr-1) == '4') { new_ptr--; } else if(*(old_ptr-1) == '8') { *--new_ptr='l'; *++new_ptr='l'; new_ptr++; } } *new_ptr++ = 'd'; old_ptr++; } else if ( *old_ptr == 's') { if(isdigit(*(old_ptr-1)) && *(old_ptr-1)=='0') new_ptr--; *new_ptr++ = 's'; old_ptr++; } else *new_ptr++ = *old_ptr++; } } *new_ptr=0; } /* trace data in ASCII format Format of the common prefix of the trace data: groupid|subhookid|sec|usec|tgid|ppid|pid|cpuid| */ #if defined(ASCII_TRACE) #define _lket_trace(GroupID, hookID, fmt, args...) do { \ struct timeval tv; \ do_gettimeofday (&tv); \ fmt_change(fmt, new_sysfmt, NEW_SYSFMT_START); \ _stp_printf(new_sysfmt, \ (_FMT_)GroupID, (_FMT_)hookID, (_FMT_)tv.tv_sec, (_FMT_)tv.tv_usec,\ (_FMT_)current->tgid, (_FMT_)current->parent->pid,\ (_FMT_)current->pid, (_FMT_)current->thread_info->cpu, args);\ } while(0) #else //binary trace static inline int this_event_len(void) { return 0; } /* we use 2 bytes to store the length. */ #define _lket_trace(GroupID, hookID, fmt, args...) do { \ struct timeval tv; \ do_gettimeofday (&tv); \ _stp_printf("%2b%2n%8b%8b"fmt, (_FMT_)0, \ (_FMT_)(tv.tv_sec*1000000LL + tv.tv_usec),\ (_FMT_)((int64_t)current->pid << 32 | (int32_t)GroupID << 24 |\ (int32_t)hookID << 16 | (int16_t)current->thread_info->cpu << 8), args);\ } while(0) #endif #endif %} function update_record() %{ #if !defined(ASCII_TRACE) int cpu = smp_processor_id(); char *total_length = &_stp_pbuf[cpu][STP_PRINT_BUF_START]; *(int16_t *)total_length = _stp_pbuf_len[cpu] - 4; #endif %}