diff gsm-fw/g23m-gsm/dl/dl_trace.c @ 673:2f7df7a314f8

gsm-fw/g23m-gsm subtree: initial import from LoCosto source
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 28 Sep 2014 23:20:04 +0000
parents
children 576c006d4b90
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gsm-fw/g23m-gsm/dl/dl_trace.c	Sun Sep 28 23:20:04 2014 +0000
@@ -0,0 +1,650 @@
+/*
++-----------------------------------------------------------------------------
+|  Project :
+|  Modul   :
++-----------------------------------------------------------------------------
+|  Copyright 2002 Texas Instruments Berlin, AG
+|                 All rights reserved.
+|
+|                 This file is confidential and a trade secret of Texas
+|                 Instruments Berlin, AG
+|                 The receipt of or possession of this file does not convey
+|                 any rights to reproduce or disclose its contents or to
+|                 manufacture, use, or sell anything it may describe, in
+|                 whole, or in part, without the specific written consent of
+|                 Texas Instruments Berlin, AG.
++-----------------------------------------------------------------------------
+|  Purpose :  This Modul defines the offline trace functions
+|             for the component DL of the mobile station.
++-----------------------------------------------------------------------------
+*/
+
+#ifndef DL_TRACE_C
+#define DL_TRACE_C
+
+#define ENTITY_DL
+
+/*==== INCLUDES ===================================================*/
+#include "typedefs.h"
+#include <string.h>
+#include "vsi.h"
+#include "pconst.cdg"
+#include "custom.h"
+#include "gsm.h"
+#include "mon_dl.h"
+#include "prim.h"
+#include "pei.h"
+#include "tok.h"
+#include "ccdapi.h"
+#include "dl.h"
+
+/*==== EXPORT =====================================================*/
+/*==== PRIVAT =====================================================*/
+#if defined(DL_TRACE_ENABLED)
+#ifdef OPTION_MULTITHREAD
+  #define TRACE_TYPE    _ENTITY_PREFIXED(TRACE_TYPE)
+  #define CHANNEL       _ENTITY_PREFIXED(CHANNEL)
+  #define STATES        _ENTITY_PREFIXED(STATES)
+#endif  /* OPTION_MULTITHREAD */
+LOCAL const char* const STATES[] =      {
+                                "INVALID",
+                                "DISABLED",
+                                "IDLE_DL",
+                                "SUSPENDED",
+                                "AWAITING_ESTABLISHMENT",
+                                "MULTI_FRAME_ESTABLISHED",
+                                "TIMER_RECOVERY",
+                                "AWAITING_RELEASE"
+                             };
+LOCAL const char* const TRACE_TYPE[] =  { "UL", "DL", "Ev", "St", "PL", "RR" };
+LOCAL const char* const CH_TYPE[] =     { "  ", "SA", "SD", "FH", "FF", "CC", "BC", "PC", "PE", "CB", "BE" };
+LOCAL const char  SAPI_TYPE[] =         { '0', '1', '2', '3', ' '};
+
+LOCAL void  array2hex (UBYTE *inarray, char *outarray, int size);
+
+#if !defined(DL_IMMEDIATE_TRACE)
+
+/*==== TEST TRACE ===================================================*/
+#define TEST_ENTITY_DL
+
+/*==== VARIABLES ==================================================*/
+/*==== FUNCTIONS ==================================================*/
+/*
+ * The Data Link Layer Trace is a cyclic buffer for
+ * debugging layer 2 problems.
+ *
+ * The buffer will be initialized at startup and will
+ * be filled by the function dl_trace() until it is full.
+ * The size of the buffer is IDLE_TRACE_SIZE.
+ *
+ * The content is
+ *
+ * trace_type (uplink, downlink, event state, alr_event, rr_event)
+ * Channel Type (SACCH, SDDCH, FACCH)
+ * real system clock
+ * State (DL states)
+ * pending disc request
+ * data (layer frame, eevnt strings, state)
+ *
+ * During IDLE mode (triggered by RX_PERIODIC_IND in ALR/TIL_main.c)
+ * an output is written to as SYST trace.
+ * (IDLE_TRACE_MAX_READED traces each trigger)
+ */
+
+#define IDLE_TRACE_SIZE       512
+#define IDLE_TRACE_MAX_READED  16
+
+#if (((IDLE_TRACE_SIZE-1) & (~IDLE_TRACE_SIZE)) == (IDLE_TRACE_SIZE-1))
+#define POWER_OF_2
+#pragma message("IDLE_TRACE_SIZE is power of 2")
+#else
+#pragma message("IDLE_TRACE_SIZE is NOT power of 2")
+#endif
+
+typedef struct
+{
+  UBYTE         trace_type;
+  UBYTE         ch_type;
+  UBYTE         sapi;
+  T_TIME        sysClock;
+  UBYTE         disc_request;
+  UBYTE         state;
+  UBYTE         data [MAX_L2_FRAME_SIZE];
+} T_IDLE_TRACE_DATA;
+
+#ifdef OPTION_MULTITHREAD
+  #define IDLE_Trace_buffer       _ENTITY_PREFIXED(IDLE_Trace_buffer)
+  #define IDLE_Trace_write_index  _ENTITY_PREFIXED(IDLE_Trace_write_index)
+  #define IDLE_Trace_read_index   _ENTITY_PREFIXED(IDLE_Trace_read_index)
+#endif  /* OPTION_MULTITHREAD */
+
+GLOBAL T_IDLE_TRACE_DATA   IDLE_Trace_buffer [IDLE_TRACE_SIZE];
+GLOBAL USHORT              IDLE_Trace_write_index  = 0;
+GLOBAL USHORT              IDLE_Trace_read_index   = 0;
+
+LOCAL  T_HANDLE            sem_DL_TRC;
+
+GLOBAL void dl_trace_init (void)
+{
+  sem_DL_TRC  = vsi_s_open (VSI_CALLER "DL_IDLE_TRACE",1);
+  if (sem_DL_TRC NEQ VSI_ERROR)
+    dl_trace_clear (0);
+  else
+    SYST_TRACE ("DL:canīt open semaphore \"DL_IDLE_TRACE\"");
+}
+
+GLOBAL void dl_trace_exit (void)
+{
+  if (sem_DL_TRC NEQ VSI_ERROR)
+    vsi_s_close (VSI_CALLER sem_DL_TRC);
+}
+
+GLOBAL void dl_trace_clear ()
+{
+  dl_trace_read_all (0); /* first, get all remaining traces (if exists) */
+
+  ENTER_CRITICAL_SECTION (sem_DL_TRC);
+  IDLE_Trace_write_index = IDLE_Trace_read_index = 0;
+  LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+
+  TRACE_EVENT ("offline trace reset");
+  DL_OFFLINE_TRACE (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, 0, "offline trace reset");
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
+| STATE   : code                     ROUTINE : dl_trace              |
++--------------------------------------------------------------------+
+
+  PURPOSE : Fill in a trace.
+
+*/
+GLOBAL void dl_trace (UCHAR trace_type, UCHAR channel, UCHAR ch_type, UCHAR* data)
+{
+  T_IDLE_TRACE_DATA*  trace_data;
+  USHORT              write_index1, write_index2;/* trace_size must not be greater than 2 */
+  UBYTE               trace_size;
+
+  if (data)
+  {
+#if defined (DISABLE_MEASREPORT_TRACE)
+    if ((ch_type EQ L2_CHANNEL_SACCH) AND
+        (data[2] EQ 0x01) AND
+        (data[3] EQ 0x03) AND
+        (data[4] EQ 0x49))
+      return;
+#endif  /* DISABLE_MEASREPORT_TRACE */
+
+#if defined (DISABLE_EMPTY_UI)
+    if ((trace_type EQ TRACE_DOWNLINK) OR (trace_type EQ TRACE_UPLINK))
+    {
+      if ((ch_type EQ L2_CHANNEL_SACCH) AND
+        (data[3] EQ 0x03) AND
+        (data[4] EQ 0x01))
+        return;
+      else if (
+        (data[1] EQ 0x03) AND
+        (data[2] EQ 0x01))
+        return;
+    }
+#endif  /* DISABLE_EMPTY_UI */
+  }
+
+  TEST_SEMAPHORE (sem_DL_TRC);
+  ENTER_CRITICAL_SECTION(sem_DL_TRC);
+
+  trace_size = 1;
+  if ((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT))
+  {
+    if (data AND strlen ((char *)data) >= 23)
+      trace_size = 2;
+  }
+
+#if defined(POWER_OF_2)
+  write_index1 = (IDLE_Trace_write_index + 1) & (IDLE_TRACE_SIZE - 1);  /* if IDLE_TRACE_SIZE power of 2 */
+  write_index2 = (IDLE_Trace_write_index + trace_size) & (IDLE_TRACE_SIZE - 1);  /* if IDLE_TRACE_SIZE power of 2 */
+#else
+  write_index1 = (IDLE_Trace_write_index + 1) % IDLE_TRACE_SIZE;      /* if IDLE_TRACE_SIZE not power of 2 */
+  write_index2 = (IDLE_Trace_write_index + trace_size) % IDLE_TRACE_SIZE;      /* if IDLE_TRACE_SIZE not power of 2 */
+#endif  /* POWER_OF_2 */
+  if ((write_index1 NEQ IDLE_Trace_read_index) AND (write_index2 NEQ IDLE_Trace_read_index))
+  { /* buffer is not full */
+    trace_data = &IDLE_Trace_buffer[IDLE_Trace_write_index];
+
+    trace_data->trace_type = trace_type;
+    if ((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT))
+    {
+      trace_data->state = trace_size;
+    }
+    else
+    {
+  GET_INSTANCE_DATA; 
+      trace_data->ch_type = ch_type;
+      switch (channel)
+      {
+      case C_SACCH0:
+      case C_DCCH0:
+        trace_data->disc_request = dl_data->dcch0_disc_request;
+        trace_data->state = dl_data->state [C_DCCH0];
+        trace_data->sapi = PS_SAPI_0;
+        break;
+      case C_DCCH3:
+        trace_data->disc_request = dl_data->dcch3_disc_request;
+        trace_data->state = dl_data->state [C_DCCH3];
+        trace_data->sapi = PS_SAPI_3;
+        break;
+      default:
+        trace_data->disc_request = 0;
+        trace_data->state = 0;
+        trace_data->sapi = NOT_PRESENT_8BIT;
+        break;
+      }
+    }
+
+    vsi_t_time (VSI_CALLER &trace_data->sysClock);
+
+    if (data)
+    {
+      memcpy (trace_data->data, data, MAX_L2_FRAME_SIZE);
+      if ((trace_type NEQ TRACE_UPLINK) AND (trace_type NEQ TRACE_DOWNLINK))
+      {
+        trace_data->data[MAX_L2_FRAME_SIZE-1] = 0;
+      }
+
+      if (trace_size EQ 2)
+      {
+        if (IDLE_Trace_write_index EQ (IDLE_TRACE_SIZE - 1))/* the last buffer index ? */
+          trace_data = &IDLE_Trace_buffer[0];/* -> overflow to the first buffer index */
+        else
+          trace_data++;
+        memcpy (trace_data->data, data+MAX_L2_FRAME_SIZE-1, MAX_L2_FRAME_SIZE-1);
+        trace_data->data[MAX_L2_FRAME_SIZE-1] = 0;
+      }
+    }
+
+    IDLE_Trace_write_index = write_index2;
+  }/* endif buffer is not full */
+
+  LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+
+#if defined(_SIMULATION_)
+  dl_trace_read (0);
+#endif  /* _SIMULATION_ */
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
+| STATE   : code                     ROUTINE : dl_trace_read         |
++--------------------------------------------------------------------+
+
+  PURPOSE : Fill in a trace.
+
+*/
+GLOBAL void dl_trace_read_all ()
+{
+  USHORT  write_index, read_index;
+
+  do
+  {
+    dl_trace_read ();
+
+    ENTER_CRITICAL_SECTION (sem_DL_TRC);
+    write_index = IDLE_Trace_write_index;
+    read_index = IDLE_Trace_read_index;
+    LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+  } while (read_index NEQ write_index);
+}
+
+GLOBAL void dl_trace_read ()
+{
+  T_IDLE_TRACE_DATA*  trace_data;
+  USHORT              write_index, read_index, left;
+  UBYTE               trace_size;
+  static char         buffer[80];
+  UBYTE               j, o, readed = 0;
+
+  TEST_SEMAPHORE (sem_DL_TRC);
+
+  ENTER_CRITICAL_SECTION (sem_DL_TRC);
+  write_index = IDLE_Trace_write_index;
+  read_index = IDLE_Trace_read_index;
+  LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+
+  if (read_index EQ write_index)
+  {
+    #if defined (_TARGET_) AND !defined( GPRS ) AND defined(FF_GTI)
+      sleep_mode ();
+    #endif  /* _TARGET_ AND !GPRS AND !FF_GTI */
+    return;
+  }
+
+  while (read_index NEQ write_index)
+  {
+    ENTER_CRITICAL_SECTION (sem_DL_TRC);
+    trace_data = &IDLE_Trace_buffer[read_index];
+    LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+
+#if defined(POWER_OF_2)
+    left = (write_index - read_index - 1) & (IDLE_TRACE_SIZE-1);
+#else
+    left = (IDLE_TRACE_SIZE + write_index - read_index - 1) % IDLE_TRACE_SIZE;
+#endif  /* POWER_OF_2 */
+
+    if (trace_data->ch_type > ELEMENTS(CH_TYPE))
+      trace_data->ch_type = 0;
+
+    if (trace_data->sapi >= ELEMENTS (SAPI_TYPE))
+      trace_data->sapi = ELEMENTS (SAPI_TYPE) - 1;
+
+    trace_size = 1;/* default */
+    switch (trace_data->trace_type)
+    {
+    case TRACE_UPLINK:
+    case TRACE_DOWNLINK:
+      sprintf (buffer, "[%03d]:%07lu %c%d %s %s ",
+        left,
+        trace_data->sysClock,
+        trace_data->disc_request?'D':' ',
+        trace_data->state,
+        TRACE_TYPE[trace_data->trace_type],
+        CH_TYPE[trace_data->ch_type]);
+      o = strlen (buffer);
+      array2hex (trace_data->data, buffer+o, 23);
+      break;
+
+    case TRACE_DL_EVENT:
+      sprintf (buffer, "[%03d]:%07lu %c%d Ev %s%c %s",
+        left,
+        trace_data->sysClock,
+        trace_data->disc_request?'D':' ',
+        trace_data->state,
+        CH_TYPE[trace_data->ch_type],
+        SAPI_TYPE[trace_data->sapi],
+        trace_data->data);
+      break;
+
+    case TRACE_PL_EVENT:
+    case TRACE_RR_EVENT:
+      trace_size = trace_data->state;
+      if (trace_size EQ 2)
+      {
+        T_IDLE_TRACE_DATA *trace_data2;
+        if (read_index EQ (IDLE_TRACE_SIZE - 1))/* the last buffer index ? */
+          trace_data2 = &IDLE_Trace_buffer[0];/* -> overflow to the first buffer index */
+        else
+          trace_data2 = trace_data+1;
+
+        sprintf (buffer, "[%03d]:%07lu %d  Ev %s %s%s",
+          left,
+          trace_data->sysClock,
+          trace_data->state,
+          TRACE_TYPE[trace_data->trace_type],
+          trace_data->data,
+          trace_data2->data);
+      }
+      else
+      {
+        sprintf (buffer, "[%03d]:%07lu %d  Ev %s %s",
+          left,
+          trace_data->sysClock,
+          trace_data->state,
+          TRACE_TYPE[trace_data->trace_type],
+          trace_data->data);
+      }
+      break;
+
+    case TRACE_CHSTATE:
+      sprintf (buffer, "[%03d]:%07lu %c%d ST %s%c state=%s",
+        left,
+        trace_data->sysClock,
+        trace_data->disc_request?'D':' ',
+        trace_data->state,
+        CH_TYPE[trace_data->ch_type],
+        SAPI_TYPE[trace_data->sapi],
+        STATES[trace_data->state]);
+      break;
+
+    default:
+      buffer[0] = 0;
+      break;
+    }
+
+    if (buffer[0])
+    {
+      SYST_TRACE (buffer);
+    }
+    else
+    {
+      SYST_TRACE ("dl_trace_read() failed");
+    }
+
+    ENTER_CRITICAL_SECTION (sem_DL_TRC);
+    trace_data->sysClock = 0; /* readed */
+    IDLE_Trace_read_index += trace_size;
+#if defined(POWER_OF_2)
+    IDLE_Trace_read_index &= (IDLE_TRACE_SIZE-1);/* if power of 2 */
+#else
+    IDLE_Trace_read_index %= IDLE_TRACE_SIZE; /* if not power of 2 */
+#endif  /* POWER_OF_2 */
+    read_index = IDLE_Trace_read_index;
+    write_index = IDLE_Trace_write_index;
+    LEAVE_CRITICAL_SECTION (sem_DL_TRC);
+
+    if (readed++ >= IDLE_TRACE_MAX_READED)
+      break;
+  }/* endwhile */
+}
+
+#else  /* DL_IMMEDIATE_TRACE */
+
+#define IMM_TRACE_SIZE       2
+typedef struct
+{
+  UBYTE         sapi;
+  T_TIME        sysClock;
+  UBYTE         disc_request;
+  UBYTE         state;
+  UBYTE         data [IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE];
+} T_TRACE_DATA;
+
+#ifdef OPTION_MULTITHREAD
+  #define print_buffer  _ENTITY_PREFIXED(print_buffer)
+  #define trace_buffer  _ENTITY_PREFIXED(trace_buffer)
+#endif  /* OPTION_MULTITHREAD */
+LOCAL char          print_buffer[25+IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE];
+LOCAL T_TRACE_DATA  trace_buffer;
+
+/*
++--------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)            MODULE  : DL_COM                |
+| STATE   : code                     ROUTINE : dl_trace              |
++--------------------------------------------------------------------+
+
+  PURPOSE : Fill in a trace.
+
+*/
+
+GLOBAL void dl_fast_trace (UBYTE trace_type, UBYTE channel, UBYTE ch_type,
+                    T_TIME trace_time, ULONG trace_mask, UBYTE* data)
+{
+  T_TRACE_DATA*  trace_data;
+  UBYTE          o;
+
+  /* While TC_USER2 is set, measurements and empty frames will be traced always */
+  if (data AND ((trace_mask & TC_USER2) EQ 0))
+  {
+    if ((ch_type EQ L2_CHANNEL_SACCH) AND
+        (data[2] EQ 0x01) AND
+        (data[3] EQ 0x03) AND
+        (data[4] EQ 0x49))
+      return;
+
+    if ((trace_type EQ TRACE_DOWNLINK) OR (trace_type EQ TRACE_UPLINK))
+    {
+      if ((ch_type EQ L2_CHANNEL_SACCH) AND
+        (data[3] EQ 0x03) AND
+        (data[4] EQ 0x01))
+        return;
+      else if (
+        (data[1] EQ 0x03) AND
+        (data[2] EQ 0x01))
+        return;
+    }
+  }
+
+  trace_data = &trace_buffer;
+  trace_data->sysClock = trace_time;
+  if (!((trace_type EQ TRACE_PL_EVENT) OR (trace_type EQ TRACE_RR_EVENT)))
+  {
+  GET_INSTANCE_DATA; 
+    switch (channel)
+    {
+    case C_SACCH0:
+    case C_DCCH0:
+      trace_data->disc_request = dl_data->dcch0_disc_request;
+      trace_data->state = dl_data->state [C_DCCH0];
+      trace_data->sapi = PS_SAPI_0;
+      break;
+    case C_DCCH3:
+      trace_data->disc_request = dl_data->dcch3_disc_request;
+      trace_data->state = dl_data->state [C_DCCH3];
+      trace_data->sapi = PS_SAPI_3;
+      break;
+    default:
+      trace_data->disc_request = 0;
+      trace_data->state = 0;
+      trace_data->sapi = NOT_PRESENT_8BIT;
+      break;
+    }
+  }
+
+  if (data)
+  {
+    if ((trace_type EQ TRACE_UPLINK) OR (trace_type EQ TRACE_DOWNLINK))
+    {
+      memcpy (trace_data->data, data, MAX_L2_FRAME_SIZE);
+    }
+    else
+    {
+      strncpy ((char *)trace_data->data, (char *)data, IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE-1);
+      trace_data->data[IMM_TRACE_SIZE*MAX_L2_FRAME_SIZE-1] = 0;
+    }
+  }
+  else
+  {
+    trace_data->data[0] = 0;
+  }
+
+
+  if (ch_type > ELEMENTS(CH_TYPE))
+    ch_type = 0;
+
+  if (trace_data->sapi >= ELEMENTS (SAPI_TYPE))
+    trace_data->sapi = ELEMENTS (SAPI_TYPE) - 1;
+
+  switch (trace_type)
+  {
+  case TRACE_UPLINK:
+  case TRACE_DOWNLINK:
+    sprintf (print_buffer, "DLTRC:%07lu %c%d %s %s%c ",
+      trace_data->sysClock,
+      trace_data->disc_request?'D':' ',
+      trace_data->state,
+      TRACE_TYPE[trace_type],
+      CH_TYPE[ch_type],
+      SAPI_TYPE[trace_data->sapi]);
+    o = strlen (print_buffer);
+    array2hex (trace_data->data, print_buffer+o, 23);
+    break;
+
+  case TRACE_DL_EVENT:
+    sprintf (print_buffer, "DLTRC:%07lu %c%d Ev %s%c %s",
+      trace_data->sysClock,
+      trace_data->disc_request?'D':' ',
+      trace_data->state,
+      CH_TYPE[ch_type],
+      SAPI_TYPE[trace_data->sapi],
+      trace_data->data);
+    break;
+
+  case TRACE_PL_EVENT:
+  case TRACE_RR_EVENT:
+    sprintf (print_buffer, "DLTRC:%07lu %d  Ev %s %s",
+      trace_data->sysClock,
+      trace_data->state,
+      TRACE_TYPE[trace_type],
+      trace_data->data);
+    break;
+
+  case TRACE_CHSTATE:
+    sprintf (print_buffer, "DLTRC:%07lu %c%d ST %s%c state=%s",
+      trace_data->sysClock,
+      trace_data->disc_request?'D':' ',
+      trace_data->state,
+      CH_TYPE[ch_type],
+      SAPI_TYPE[trace_data->sapi],
+      STATES[trace_data->state]);
+    break;
+
+  default:
+    print_buffer[0] = 0;
+    break;
+  }
+
+  TRACE_USER_CLASS (TC_USER1, print_buffer);
+
+#if 0
+  if (print_buffer[0])
+  {
+    #if defined(_SIMULATION_)
+      TRACE_EVENT_WIN (print_buffer);
+    #else  /* _SIMULATION_ */
+      SYST_TRACE_P ((DLTRC,print_buffer));
+    #endif  /* _SIMULATION_ */
+  }
+#endif /* 0 */
+}
+#endif  /* DL_IMMEDIATE_TRACE */
+
+LOCAL void  array2hex (UBYTE *inarray, char *outarray, int size)
+{
+  int col=0, n=0;
+  UBYTE b, nh, nl;
+
+  while (n < size)
+  {
+    b = inarray[n++];
+    nh = b>>4;
+    nl = b&0x0f;
+    outarray[col++] = nh > 9 ? nh + 'A' - 10 : nh + '0';
+    outarray[col++] = nl > 9 ? nl + 'A' - 10 : nl + '0';
+  }
+  outarray[col] = 0;
+}
+#endif  /* DL_TRACE_ENABLED */
+
+#if defined (DL_TRACE_PFREE)
+GLOBAL void* my_pfree(void *pointer, int line, char *file)
+{
+
+  char buffer[23];
+  sprintf (buffer, "%s#%u:%p", file+2, line, pointer);
+  dl_trace (TRACE_DL_EVENT, TRACE_CH_UNKNOWN, buffer);
+
+  if (pointer)
+  {
+    PFREE (pointer);
+  }
+  else
+  {
+    SYST_TRACE_P((SYST, "%s#%u: PFREE(NULL)", file, line));
+  }
+
+  return NULL;
+}
+#endif /* DL_TRACE_PFREE */
+
+#endif  /* DL_TRACE_C */
+