blob: 6b52297d7515545626b2393af47d08fe6ec08064 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* pg_ltrace.c
* Poor linux's tracing facility.
*
*/
#include <pg_config.h>
#ifdef ENABLE_LTRACE
#include <sys/types.h>
#include <unistd.h>
#include <pg_trace.h>
#include <stdio.h>
extern int gp_ltrace_flag;
struct pg_trace_data_t
{
long val[9];
};
/*
* Poor linux tracing facility.
*
* Unlike dtrace, linux tracing (SystemTap) at this moment
* does not support user space tracing. We use the following
* HACK to get some tracing.
*
* The write is strange. Postgres will redirect fd 0 (stdin) to
* read from /dev/null. We are writing to stdin, a string of 0 bytes.
* it will fail, as stdin is readonly, but, it is still a system call.
* In system tap, we can catch at syscall.write and test $fd == 0 and
* $count == 0. The constructed buffer can be accessed by $buf.
*
* Note that the $fd = 0 and $count = 0 hack is kind of "Needed".
* If the fd is not valid, then actually the systemtap syscalls tapset
* will not catch it. Count set to 0 is safe.
*
* NOTE: At this moment, SystemTap cannot even display user stack.
* if we really want the stack, we can construct the stack using backtrace()
* and put the string as the str arg.
*
* filename and funcname can be used a quick dirty depth 1 stack.
*
* The stp script need to match the t.val layout. Right now,
* 0 family
* 1 filename
* 2 funcname
* 3 line number
* 4-9 5 args
*/
#if 0
--------------------- BEGIN EXAMPLE STP ---------------------------------
#! /usr/bin/env stap
/*
* Example stap. The stp must be run as root because it uses embeded C.
*
* sudo stap -g my.stp
*/
function pgtrace_decode_val:long(pgtrace_data:long, fieldnum:long)
%{
struct pg_trace_data_t {
long iv[9];
};
struct pg_trace_data_t *p = (struct pg_trace_data_t *) (long) THIS->pgtrace_data;
if(p && THIS->fieldnum >= 0 && THIS->fieldnum < 9)
THIS->__retvalue = kread(&(p->iv[THIS->fieldnum]));
else
THIS->__retvalue = 0;
CATCH_DEREF_FAULT();
%}
probe syscall.write {
/* We have $fd, $count, and $buf. Need to access $buf with user_string($buf) */
if($fd == 0 && $count == 0)
{
printf("PGTrace family %d, file %s, func %s line %d: args: %d, %d, %d, %d, %d\n",
pgtrace_decode_val($buf, 0),
user_string(pgtrace_decode_val($buf, 1)),
user_string(pgtrace_decode_val($buf, 2)),
pgtrace_decode_val($buf, 3),
pgtrace_decode_val($buf, 4),
pgtrace_decode_val($buf, 5),
pgtrace_decode_val($buf, 6),
pgtrace_decode_val($buf, 7),
pgtrace_decode_val($buf, 8)
)
}
}
--------------------- END EXAMPLE STP -----------------------------------------
#endif
void LTRACE_PROBE_FIRE(long family,
const char *filename, const char *funcname, long line,
long i1, long i2, long i3, long i4, long i5
)
{
if(gp_ltrace_flag)
{
struct pg_trace_data_t t;
t.val[0] = family;
t.val[1] = (long) filename;
t.val[2] = (long) funcname;
t.val[3] = line;
t.val[4] = i1;
t.val[5] = i2;
t.val[6] = i3;
t.val[7] = i4;
t.val[8] = i5;
write(0, (char *) &t, 0);
}
}
#endif