/*
* backtrace.c
* Function backtracing code (original code by Balloon)
* ---------------------------------------------------------------------------
*/
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdarg.h>
#include "include/config.h"
#include "include/player.h"
#include "include/proto.h"
#define MAX_DEBUG_LEN 50
#define MAX_DEPTH 250
#define MAX_MARK_LEN 250
struct FunctionTrack
{
char File[MAX_DEBUG_LEN];
int Line;
char Function[MAX_DEBUG_LEN];
char MarkMessage[MAX_MARK_LEN];
int MarkLine;
};
static int TrackingDepth = -1;
static int ActualDepth = -1;
static struct FunctionTrack Tracks[MAX_DEPTH];
void EnterFunction(int Line, char *File, char *Function)
{
if (sys_flags & DONT_TRACE)
return;
sys_flags |= DONT_TRACE;
if (TrackingDepth == -1)
memset(Tracks, 0, MAX_DEPTH * sizeof(struct FunctionTrack));
if (TrackingDepth == MAX_DEPTH)
{
if (TrackingDepth == ActualDepth++)
LOGF("error", "Gone deeper than tracking allows!");
sys_flags &= ~DONT_TRACE;
return;
}
TrackingDepth++;
ActualDepth++;
strncpy(Tracks[TrackingDepth].File, File, MAX_DEBUG_LEN);
strncpy(Tracks[TrackingDepth].Function, Function, MAX_DEBUG_LEN);
Tracks[TrackingDepth].Line = Line;
Tracks[TrackingDepth].MarkMessage[0] = 0;
sys_flags &= ~DONT_TRACE;
}
void ExitFunction(int Line, char *File, char *Function)
{
int temp;
if (sys_flags & DONT_TRACE)
return;
sys_flags |= DONT_TRACE;
if (ActualDepth > TrackingDepth)
{
if ((ActualDepth - 1) == TrackingDepth)
LOGF("error", "Leaving function (too deep)");
ActualDepth--;
sys_flags &= ~DONT_TRACE;
return;
}
if (TrackingDepth < 0)
{
LOGF("error", "Leaving : %s : %s : Line %d", File, Function, Line);
LOGF("error", "Tracking claims not to be in any function!");
sys_flags &= ~DONT_TRACE;
return;
}
if ((strncmp(File, Tracks[TrackingDepth].File, MAX_DEBUG_LEN)) ||
(strncmp(Function, Tracks[TrackingDepth].Function, MAX_DEBUG_LEN)))
{
LOGF("error", "Leaving : %s : %s : Line %d", File, Function, Line);
LOGF("error", "Not left : %s : %s : Line %d", Tracks[TrackingDepth].Function, Tracks[TrackingDepth].File, Tracks[TrackingDepth].Line);
temp = TrackingDepth;
while ((temp > -1) &&
((strncmp(File, Tracks[temp].File, MAX_DEBUG_LEN)) ||
(strncmp(Function, Tracks[temp].Function, MAX_DEBUG_LEN))))
temp--;
if (temp > -1)
{
LOGF("error","Hopefully recovered tracking.");
TrackingDepth = temp - 1;
ActualDepth = TrackingDepth;
}
else
LOGF("error","Not recovered as yet.");
}
Tracks[TrackingDepth].File[0] = 0;
Tracks[TrackingDepth].Function[0] = 0;
Tracks[TrackingDepth].Line = 0;
Tracks[TrackingDepth].MarkMessage[0] = 0;
TrackingDepth--;
ActualDepth--;
sys_flags &= ~DONT_TRACE;
}
void MarkFunction(int Line, char *File, char *Function, char *Format, ...)
{
int temp;
va_list ap;
if (sys_flags & DONT_TRACE)
return;
sys_flags |= DONT_TRACE;
if (ActualDepth > TrackingDepth)
{
LOGF("error", "Marking : %s : %s : Line %d", File, Function, Line);
LOGF("error", "Too deep to Mark function.");
sys_flags &= ~DONT_TRACE;
return;
}
if (TrackingDepth < 0)
{
LOGF("error", "Marking : %s : %s : Line %d", File, Function, Line);
LOGF("error", "Tracking claims not to be in any function!");
sys_flags &= ~DONT_TRACE;
return;
}
temp = TrackingDepth;
if ((strncmp(File, Tracks[TrackingDepth].File, MAX_DEBUG_LEN)) ||
(strncmp(Function, Tracks[TrackingDepth].Function, MAX_DEBUG_LEN)))
{
LOGF("error", "Marking : %s : %s : Line %d", File, Function, Line);
LOGF("error", "Actually in : %s : %s : Line %d", Tracks[TrackingDepth].Function, Tracks[TrackingDepth].File, Tracks[TrackingDepth].Line);
while ((temp > -1) &&
((strncmp(File, Tracks[temp].File, MAX_DEBUG_LEN)) ||
(strncmp(Function, Tracks[temp].Function, MAX_DEBUG_LEN))))
temp--;
if (temp > -1)
LOGF("error","Hopefully found correct function to mark.");
else
LOGF("error","Cant find correct function to mark.");
}
if (temp > -1)
{
/* It's safe to do the mark. */
va_start(ap, Format);
vsnprintf(Tracks[temp].MarkMessage, MAX_MARK_LEN, Format, ap);
va_end(ap);
Tracks[temp].MarkMessage[MAX_MARK_LEN - 1] = 0;
Tracks[temp].MarkLine = Line;
}
sys_flags &= ~DONT_TRACE;
}
void DumpTraceInfo(char *logfile)
{
int temp;
if (sys_flags & DONT_TRACE)
return;
sys_flags |= DONT_TRACE;
LOGF(logfile, "==== Showing last function calls");
for (temp = 0; temp <= TrackingDepth; temp++)
{
LOGF(logfile, " %s : %s : Line %d", Tracks[temp].Function, Tracks[temp].File, Tracks[temp].Line);
if (Tracks[temp].MarkMessage[0])
LOGF(logfile, " -- %s : Line %d", Tracks[temp].MarkMessage, Tracks[temp].MarkLine);
}
LOGF(logfile, "==== End of function calls");
sys_flags &= ~DONT_TRACE;
}