mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			332 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
# Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
 | 
						|
#
 | 
						|
# Redistribution and use in source and binary forms, with or without
 | 
						|
# modification, are permitted provided that the following conditions are met:
 | 
						|
# 
 | 
						|
#    * Redistributions of source code must retain the above copyright
 | 
						|
#      notice, this list of conditions and the following disclaimer. 
 | 
						|
#    * Redistributions in binary form must reproduce the above copyright
 | 
						|
#      notice, this list of conditions and the following disclaimer in  
 | 
						|
#      the documentation and/or other materials provided with the       
 | 
						|
#      distribution.
 | 
						|
#    * Neither the name of the above-listed copyright holders nor the names
 | 
						|
#      of its contributors may be used to endorse or promote products derived
 | 
						|
#      from this software without specific prior written permission.  
 | 
						|
#       
 | 
						|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 | 
						|
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  
 | 
						|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 | 
						|
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 | 
						|
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     
 | 
						|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      
 | 
						|
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  
 | 
						|
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    
 | 
						|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS      
 | 
						|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
#
 | 
						|
# ident	"@(#)dheadgen.pl	1.4	07/06/24 SMI"
 | 
						|
 | 
						|
#
 | 
						|
# DTrace Header Generator
 | 
						|
# -----------------------
 | 
						|
#
 | 
						|
# This script is meant to mimic the output of dtrace(1M) with the -h
 | 
						|
# (headergen) flag on system that lack native support for DTrace. This script
 | 
						|
# is intended to be integrated into projects that use DTrace's static tracing
 | 
						|
# facilities (USDT), and invoked as part of the build process to have a
 | 
						|
# common build process on all target systems. To facilitate this, this script
 | 
						|
# is licensed under a BSD license. On system with native DTrace support, the
 | 
						|
# dtrace(1M) command will be invoked to create the full header file; on other
 | 
						|
# systems, this script will generated a stub header file.
 | 
						|
#
 | 
						|
# Normally, generated macros take the form PROVIDER_PROBENAME().  It may be
 | 
						|
# desirable to customize the output of this script and of dtrace(1M) to
 | 
						|
# tailor the precise macro name. To do this, edit the emit_dtrace() subroutine
 | 
						|
# to pattern match for the lines you want to customize.
 | 
						|
#
 | 
						|
 | 
						|
use strict;
 | 
						|
 | 
						|
my @lines;
 | 
						|
my @tokens = ();
 | 
						|
my $lineno = 0;
 | 
						|
my $newline = 1;
 | 
						|
my $eof = 0;
 | 
						|
my $infile;
 | 
						|
my $outfile;
 | 
						|
my $force = 0;
 | 
						|
 | 
						|
sub emit_dtrace {
 | 
						|
	my ($line) = @_;
 | 
						|
 | 
						|
	#
 | 
						|
	# Insert customization here. For example, if you want to change the
 | 
						|
	# name of the macros you may do something like this:
 | 
						|
	#
 | 
						|
	# $line =~ s/(\s)[A-Z]+_/\1TRACE_MOZILLA_/;
 | 
						|
	#
 | 
						|
 | 
						|
	print $line;
 | 
						|
}
 | 
						|
 | 
						|
#
 | 
						|
# The remaining code deals with parsing D provider definitions and emitting
 | 
						|
# the stub header file. There should be no need to edit this absent a bug.
 | 
						|
#
 | 
						|
 | 
						|
#
 | 
						|
# Emit the two relevant macros for each probe in the given provider:
 | 
						|
#    PROVIDER_PROBENAME(<args>)
 | 
						|
#    PROVIDER_PROBENAME_ENABLED() (0)
 | 
						|
#
 | 
						|
sub emit_provider {
 | 
						|
	my ($provname, @probes) = @_;
 | 
						|
 | 
						|
	$provname = uc($provname);
 | 
						|
 | 
						|
	foreach my $probe (@probes) {
 | 
						|
		my $probename = uc($$probe{'name'});
 | 
						|
		my $argc = $$probe{'argc'};
 | 
						|
		my $line;
 | 
						|
 | 
						|
		$probename =~ s/__/_/g;
 | 
						|
 | 
						|
		$line = "#define\t${provname}_${probename}(";
 | 
						|
		for (my $i = 0; $i < $argc; $i++) {
 | 
						|
			$line .= ($i == 0 ? '' : ', ');
 | 
						|
			$line .= "arg$i";
 | 
						|
		}
 | 
						|
		$line .= ")\n";
 | 
						|
		emit_dtrace($line);
 | 
						|
		
 | 
						|
		$line = "#define\t${provname}_${probename}_ENABLED() (0)\n";
 | 
						|
		emit_dtrace($line);
 | 
						|
	}
 | 
						|
 | 
						|
	emit_dtrace("\n");
 | 
						|
}
 | 
						|
 | 
						|
sub emit_prologue {
 | 
						|
	my ($filename) = @_;
 | 
						|
 | 
						|
	$filename =~ s/.*\///g;
 | 
						|
	$filename = uc($filename);
 | 
						|
	$filename =~ s/\./_/g;
 | 
						|
 | 
						|
	emit_dtrace <<"EOF";
 | 
						|
/*
 | 
						|
 * Generated by dheadgen(1).
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef\t_${filename}
 | 
						|
#define\t_${filename}
 | 
						|
 | 
						|
#ifdef\t__cplusplus
 | 
						|
extern "C" {
 | 
						|
#endif
 | 
						|
 | 
						|
EOF
 | 
						|
}
 | 
						|
 | 
						|
sub emit_epilogue {
 | 
						|
	my ($filename) = @_;
 | 
						|
 | 
						|
	$filename =~ s/.*\///g;
 | 
						|
	$filename = uc($filename);
 | 
						|
	$filename =~ s/\./_/g;
 | 
						|
 | 
						|
	emit_dtrace <<"EOF";
 | 
						|
#ifdef  __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#endif  /* _$filename */
 | 
						|
EOF
 | 
						|
}
 | 
						|
 | 
						|
#
 | 
						|
# Get the next token from the file keeping track of the line number.
 | 
						|
#
 | 
						|
sub get_token {
 | 
						|
	my ($eof_ok) = @_;
 | 
						|
	my $tok;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		while (scalar(@tokens) == 0) {
 | 
						|
			if (scalar(@lines) == 0) {
 | 
						|
				$eof = 1;
 | 
						|
				return if ($eof_ok);
 | 
						|
				die "expected more data at line $lineno";
 | 
						|
			}
 | 
						|
 | 
						|
			$lineno++;
 | 
						|
			push(@tokens, split(/(\s+|\n|[(){},#;]|\/\*|\*\/)/,
 | 
						|
			    shift(@lines)));
 | 
						|
		}
 | 
						|
 | 
						|
		$tok = shift(@tokens);
 | 
						|
		next if ($tok eq '');
 | 
						|
		next if ($tok =~ /^[ \t]+$/);
 | 
						|
 | 
						|
		return ($tok);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#
 | 
						|
# Ignore newlines, comments and typedefs
 | 
						|
#
 | 
						|
sub next_token {
 | 
						|
	my ($eof_ok) = @_;
 | 
						|
	my $tok;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		$tok = get_token($eof_ok);
 | 
						|
		return if ($eof_ok && $eof);
 | 
						|
		if ($tok eq "typedef" or $tok =~ /^#/) {
 | 
						|
		  while (1) {
 | 
						|
		    $tok = get_token(0);
 | 
						|
		    last if ($tok eq "\n");
 | 
						|
		  }
 | 
						|
		  next;
 | 
						|
		} elsif ($tok eq '/*') {
 | 
						|
			while (get_token(0) ne '*/') {
 | 
						|
				next;
 | 
						|
			}
 | 
						|
			next;
 | 
						|
		} elsif ($tok eq "\n") {
 | 
						|
			next;
 | 
						|
		}
 | 
						|
 | 
						|
		last;
 | 
						|
	}
 | 
						|
 | 
						|
	return ($tok);
 | 
						|
}
 | 
						|
 | 
						|
sub expect_token {
 | 
						|
	my ($t) = @_;
 | 
						|
	my $tok;
 | 
						|
 | 
						|
	while (($tok = next_token(0)) eq "\n") {
 | 
						|
		next;
 | 
						|
	}
 | 
						|
 | 
						|
	die "expected '$t' at line $lineno rather than '$tok'" if ($t ne $tok);
 | 
						|
}
 | 
						|
 | 
						|
sub get_args {
 | 
						|
	expect_token('(');
 | 
						|
 | 
						|
	my $tok = next_token(0);
 | 
						|
	my @args = ();
 | 
						|
 | 
						|
	return (@args) if ($tok eq ')');
 | 
						|
 | 
						|
	if ($tok eq 'void') {
 | 
						|
		expect_token(')');
 | 
						|
		return (@args);
 | 
						|
	}
 | 
						|
 | 
						|
	my $arg = $tok;
 | 
						|
 | 
						|
	while (1) {
 | 
						|
		$tok = next_token(0);
 | 
						|
		if ($tok eq ',' || $tok eq ')') {
 | 
						|
			push(@args, $arg);
 | 
						|
			$arg = '';
 | 
						|
			last if ($tok eq ')');
 | 
						|
		} else {
 | 
						|
			$arg = "$arg $tok";
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return (@args);
 | 
						|
}
 | 
						|
 | 
						|
sub usage {
 | 
						|
	die "usage: $0 [-f] <filename.d>\n";
 | 
						|
}
 | 
						|
 | 
						|
usage() if (scalar(@ARGV) < 1);
 | 
						|
if ($ARGV[0] eq '-f') {
 | 
						|
	usage() if (scalar(@ARGV < 2));
 | 
						|
	$force = 1;
 | 
						|
	shift;
 | 
						|
}
 | 
						|
$infile = $ARGV[0];
 | 
						|
usage() if ($infile !~ /(.+)\.d$/);
 | 
						|
 | 
						|
#
 | 
						|
# If the system has native support for DTrace, we'll use that binary instead.
 | 
						|
#
 | 
						|
if (-x '/usr/sbin/dtrace' && !$force) {
 | 
						|
	open(DTRACE, "-| /usr/sbin/dtrace -C -h -s $infile -o /dev/stdout")
 | 
						|
	    or die "can't invoke dtrace(1M)";
 | 
						|
 | 
						|
	while (<DTRACE>) {
 | 
						|
		emit_dtrace($_);
 | 
						|
	}
 | 
						|
 | 
						|
	close(DTRACE);
 | 
						|
 | 
						|
	exit(0);
 | 
						|
}
 | 
						|
 | 
						|
emit_prologue($infile);
 | 
						|
 | 
						|
open(D, "< $infile") or die "couldn't open $infile";
 | 
						|
@lines = <D>;
 | 
						|
close(D);
 | 
						|
 | 
						|
while (1) {
 | 
						|
	my $nl = 0;
 | 
						|
	my $tok = next_token(1);
 | 
						|
	last if $eof;
 | 
						|
 | 
						|
	if ($newline && $tok eq '#') {
 | 
						|
		while (1) {
 | 
						|
			$tok = get_token(0);
 | 
						|
 | 
						|
			last if ($tok eq "\n");
 | 
						|
		}
 | 
						|
		$nl = 1;
 | 
						|
	} elsif ($tok eq "\n") {
 | 
						|
		$nl = 1;
 | 
						|
	} elsif ($tok eq 'provider') {
 | 
						|
		my $provname = next_token(0);
 | 
						|
		my @probes = ();
 | 
						|
		expect_token('{');
 | 
						|
 | 
						|
		while (1) {
 | 
						|
			$tok = next_token(0);
 | 
						|
			if ($tok eq 'probe') {
 | 
						|
				my $probename = next_token(0);
 | 
						|
				my @args = get_args();
 | 
						|
 | 
						|
				next while (next_token(0) ne ';');
 | 
						|
 | 
						|
				push(@probes, {
 | 
						|
				    'name' => $probename,
 | 
						|
				    'argc' => scalar(@args)
 | 
						|
				});
 | 
						|
 | 
						|
			} elsif ($tok eq '}') {
 | 
						|
				expect_token(';');
 | 
						|
 | 
						|
				emit_provider($provname, @probes);
 | 
						|
 | 
						|
				last;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	} else {
 | 
						|
		die "syntax error at line $lineno near '$tok'\n";
 | 
						|
	}
 | 
						|
 | 
						|
	$newline = $nl;
 | 
						|
}
 | 
						|
 | 
						|
emit_epilogue($infile);
 | 
						|
 | 
						|
exit(0);
 |