XRootD
XrdOucBackTrace Class Reference

#include <XrdOucBackTrace.hh>

+ Collaboration diagram for XrdOucBackTrace:

Public Types

enum  Action {
  addIt =0 ,
  clrIt ,
  delIt ,
  repIt
}
 
enum  PtrType {
  isThis ,
  isObject
}
 Define filter types and actions. More...
 

Static Public Member Functions

static void DoBT (const char *head=0, void *thisP=0, void *objP=0, const char *tail=0, bool force=false)
 
static void Filter (void *ptr, PtrType pType, Action how=addIt)
 
static bool Init (const char *reqs=0, const char *rsps=0)
 
static void XrdBT (const char *head=0, void *thisP=0, void *objP=0, int rspN=0, int reqN=0, const char *tail=0, bool force=false)
 

Detailed Description

XrdOucBackTrace provides a way to perform a back trace to assist in debugging esoteric problems. It is controlled by various envars or options can be set by methods in this class. It is fully MT_safe. However, a full back trace is only available for programs compiled using a GNU compiler.

Back tracing can be selectively controlled by filters. As filters interact, one must understand how they are applied. There are four filters: 1) this pointer matching 2) object pointer matching 3) request code matching (XrdBT only) 4) response code matching (XrdBT only, also known as the status code)

Both DoBT() and XrdBT() apply this and pointer filters while XrdBT() also applies request and response filters while DoBT() does not apply them. When DoBT() or XrdBT() is called, the following sequence occurs: 1) If the this filter is set and the this pointer matches a BT occurs. 2) if the object filter is set and the object pointer matches a BT occurs. 3) If both pointer filters are set then no BT occurs, period. 4) If only one of the pointer filters is set then DoBT() does not do a BT. 5) XrdBT() also does not do a BT if the neither code matching filters are set. If one of the code filters is set then a BT occurs if both filters succeed (note that an unset code filter always succeeds).

Two handy commands in gdb to convert a back trace to source file line: info line *addr list *addr The addr is the address that appears in the back trace in brackets. The 'info line' gives you a close approximation while list provides more context with a suggested line (optimization makes this obtuse). For example, given [0x7ffff695db36] say 'info line *0x7ffff695db36'.

Definition at line 65 of file XrdOucBackTrace.hh.

Member Enumeration Documentation

◆ Action

Enumerator
addIt 

Add item to the list of PtrTypes being filtered.

clrIt 

Delete all PtrType filtered items (1st arg ignored).

delIt 

Delete this item from the list of PtrTypes filtered.

repIt 

Replace all PtrTypes items filtered with this item.

Definition at line 132 of file XrdOucBackTrace.hh.

132  {addIt=0,
133  clrIt,
134  delIt,
135  repIt
136  };
@ repIt
Replace all PtrTypes items filtered with this item.
@ delIt
Delete this item from the list of PtrTypes filtered.
@ addIt
Add item to the list of PtrTypes being filtered.
@ clrIt
Delete all PtrType filtered items (1st arg ignored).

◆ PtrType

Define filter types and actions.

Enumerator
isThis 

Pointer is a this pointer.

isObject 

Pointer is an object pointer.

Definition at line 128 of file XrdOucBackTrace.hh.

128  {isThis,
129  isObject
130  };
@ isObject
Pointer is an object pointer.
@ isThis
Pointer is a this pointer.

Member Function Documentation

◆ DoBT()

void XrdOucBackTrace::DoBT ( const char *  head = 0,
void *  thisP = 0,
void *  objP = 0,
const char *  tail = 0,
bool  force = false 
)
static

Produce a back trace. The message header and corresponding back trace have the format below. The traceback lines may differ if an error occurs. The maximum levels displayed is controlled by the XRDBT_DEPTH envar. If not set, or is invalid, Only the last 15 levels are displayed (maximum depth is 30). This version is geared for general applications (see XrdBT() alternative).

TBT <thread_id> <thisP> [<head>] obj <objP> [<tail>] TBT <thread_id> [<addr_of_ret>] <func>(<args>)+offs

Parameters
headPoints to text to be included in back trace header. A nil pointer indicates there is no information.
thisPIs the this pointer of the caller. If there is no this pointer, pass nil. The address is included in the header. Use Filter() to filter the address.
objPPointer to an object of interest. It's address is included in the header. Use Filter() to filter the address.
tailPointer to text to be included at the end of the header. A nil pointer indicates there is none.
forceWhen true, all filters are ignored.

Definition at line 313 of file XrdOucBackTrace.cc.

315 {
316  TidType tid;
317  int k;
318  char btBuff[4096];
319 
320 // Apply any necessary filters
321 //
322  if (!force)
323  {if (AtomicGet(xeqPtrFilter) && !Screen(thisP, objP, false)) return;}
324 
325 // Prepare for formatting
326 //
327  if (!head) head = "";
328  if (!tail) tail = "";
329 #if defined(__linux__) || defined(__APPLE__)
330  tid = syscall(SYS_gettid);
331 #else
332  tid = XrdSysThread::ID();
333 #endif
334 
335 // Format the header
336 //
337  k = snprintf(btBuff,sizeof(btBuff),"\nTBT " TidFmt " %p %s obj %p %s\n",
338  tid, thisP, head, objP, tail);
339 
340 // Now dump the stack
341 //
342  DumpStack(btBuff+k, sizeof(btBuff)-k-8, tid);
343 
344 // Output the information
345 //
346  std::cerr <<btBuff <<std::flush;
347 }
#define TidType
#define TidFmt
#define AtomicGet(x)
static pthread_t ID(void)

References AtomicGet, XrdSysThread::ID(), TidFmt, and TidType.

+ Here is the call graph for this function:

◆ Filter()

void XrdOucBackTrace::Filter ( void *  ptr,
XrdOucBackTrace::PtrType  pType,
XrdOucBackTrace::Action  how = addIt 
)
static

Set a pointer filter. Back traces only occur when the corresponding pointer is passed to DoBT() or XrdBT(). See filtering explanation above.

Parameters
ptrThe pointer.
pTypeThe pointer's logical type (see PtrType defined above).
howOne of the action enums in Action (defined above).

Definition at line 397 of file XrdOucBackTrace.cc.

399 {
400  XrdSysMutexHelper btHelp(btMutex);
401  std::vector<void *>::iterator it;
402  std::vector<void *> *filtP;
403 
404 // Get the filter, we have the mutex so no need to atomically fetch it
405 //
406  filtP = ptrFilter[pType];
407 
408 // Perfome action when we don't already have a filter
409 //
410  if (!filtP)
411  {if (how != XrdOucBackTrace::clrIt && how != XrdOucBackTrace::delIt)
412  {filtP = new std::vector<void *>();
413  filtP->push_back(ptr);
414  ptrFilter[pType] = filtP;
415  AtomicInc(xeqPtrFilter); // This forces the above to complete
416  }
417  return;
418  }
419 
420 // We have a filter, see it we need to clear it
421 //
422  if (how == XrdOucBackTrace::clrIt)
423  {int i = pType ^ ptrXORFilter;
424  filtP->clear();
425  if (!ptrFilter[i] || ptrFilter[i]->size() == 0) AtomicZAP(xeqPtrFilter);
426  return;
427  }
428 
429 // We have a filter, see it we need to replace it
430 //
431  if (how == XrdOucBackTrace::repIt)
432  {filtP->clear();
433  filtP->push_back(ptr);
434  AtomicInc(xeqPtrFilter);
435  return;
436  }
437 
438 // We only have add and delete left and these require us to find the pointer
439 //
440  for (it = filtP->begin(); it!= filtP->end(); ++it) if (ptr == *it) break;
441 
442 // Handle the case where we found the element
443 //
444  if (it != filtP->end())
445  {if (how == XrdOucBackTrace::delIt)
446  {int i = pType ^ ptrXORFilter;
447  filtP->erase(it);
448  if (filtP->size() == 0 && (!ptrFilter[i] || !(ptrFilter[i]->size())))
449  AtomicZAP(xeqPtrFilter);
450 std::cerr <<"delIt: " <<xeqPtrFilter <<std::endl;
451  }
452  return;
453  }
454 
455 // We did not find the element, add it if we must
456 //
457  if (how == XrdOucBackTrace::addIt)
458  {filtP->push_back(ptr);
459  AtomicInc(xeqPtrFilter);
460  }
461 }
#define AtomicInc(x)
#define AtomicZAP(x)

References addIt, AtomicInc, AtomicZAP, clrIt, delIt, and repIt.

◆ Init()

bool XrdOucBackTrace::Init ( const char *  reqs = 0,
const char *  rsps = 0 
)
static

Do optional one time static intialization. Invoke this method at file level (e.g. bool aOK = XrdOucBackTrace::Init()) if you wish to set xrootd specific filters when calling XrdBT(). Otherwise, don't use this method.

Parameters
reqsThe kXR_ request code name(s). If the pointer is nil, the back trace filter is set using envar XRDBT_REQFILTER as the argument. If both are nil, no filter is established. Specify, one or more names, each separated by a space. Invalid names are ignored. Choose from this list:

admin auth bind chmod close dirlist endsess getfile locate login mkdir mv open ping prepare protocol putfile query read readv rm rmdir set stat statx sync truncate verifyw write

Parameters
rspsThe kXR_ response code name(s). If the pointer is nil, the back trace filter is set using envar XRDBT_RSPFILTER as the argument. If both are nil, no filter is established. Specify, one or more names, each separated by a space. Invalid names are ignored. Choose from this list:

attn authmore error ok oksofar redirect wait waitresp

Returns
true Initialization succeeded.
false Initialization completed but one or more reqs or rsps were ignored because they were invalid.

Definition at line 353 of file XrdOucBackTrace.cc.

354 {
355  XrdOucTokenizer tokLine(0);
356  XrdInfo *infoP;
357  char *line, *token;
358  bool aOK = true;
359 
360 // Check if we have a request filter
361 //
362  if (reqs || (reqs = getenv("XRDBT_REQFILTER")))
363  {line = strdup(reqs);
364  tokLine.Attach(line);
365  token = tokLine.GetLine();
366  while((token = tokLine.GetToken()))
367  {infoP = CvtReq(token, 0);
368  if (infoP->code > 0) reqFilter |= infoP->mask;
369  else aOK = false;
370  }
371  free(line);
372  }
373 
374 // Check if we have a response filter
375 //
376  if (rsps || (rsps = getenv("XRDBT_RSPFILTER")))
377  {line = strdup(rsps);
378  tokLine.Attach(line);
379  token = tokLine.GetLine();
380  while((token = tokLine.GetToken()))
381  {infoP = CvtRsp(token, 0);
382  if (infoP->code > 0) rspFilter |= infoP->mask;
383  else aOK = false;
384  }
385  free(line);
386  }
387 
388 // All done
389 //
390  return aOK;
391 }

References XrdOucTokenizer::Attach(), XrdOucTokenizer::GetLine(), and XrdOucTokenizer::GetToken().

+ Here is the call graph for this function:

◆ XrdBT()

void XrdOucBackTrace::XrdBT ( const char *  head = 0,
void *  thisP = 0,
void *  objP = 0,
int  rspN = 0,
int  reqN = 0,
const char *  tail = 0,
bool  force = false 
)
static

Produce an XrrotD specific back trace. The message header and corresponding back trace have the format below. The back trace lines may differ if an error occurs. This version is for for XRootD applications. See the DoBT().

TBT <thread_id> <thisP> <head> obj <objP> rsp <statN> req <reqN> <tail> TBT <thread_id> [<addr_of_ret>] <func>(<args>)+offs

Parameters
headPoints to text to be included in back trace header
thisPIs the this pointer of the caller. If there is no this pointer, pass nil. The address is included in the header. User Filter() to filter the pointer.
objPPointer to an object of interest. It's address is included in the header. Use Filter() to filter the pointer.
rspNThe kXR_ status code reflected in an XRootD response. It's corresponding name, if any, is included in the header. Use Init() to filter the code value.
reqNThe kXR_ request code of an XRootD request. It's corresponding name, if any, is included in the header. Use Init() to filter the code value.
tailPointer to text to be included at the end of the header. A nil pointer does not add any additional text.
forceWhen true, all filters are ignored.

Definition at line 467 of file XrdOucBackTrace.cc.

470 {
471  XrdInfo *infoP, *reqInfo, *rspInfo;
472  TidType tid;
473  int k;
474  char btBuff[4096];
475  bool rrOK;
476 
477 // Apply any necessary filters
478 //
479  if (!force)
480  { if (!reqFilter && !rspFilter) rrOK = false;
481  else if (reqFilter && (infoP=CvtReq(0, reqN))
482  && !(reqFilter & infoP->mask)) rrOK = false;
483  else if (rspFilter && (infoP=CvtRsp(0, rspN))
484  && !(rspFilter & infoP->mask)) rrOK = false;
485  else rrOK = true;
486  if (AtomicGet(xeqPtrFilter)) {if (!Screen(thisP, objP, rrOK)) return;}
487  else if (!rrOK) return;
488  }
489 
490 // Prepare for formatting
491 //
492  if (!head) head = "";
493  if (!tail) tail = "";
494  reqInfo = CvtReq(0, reqN);
495  rspInfo = CvtRsp(0, rspN);
496 #if defined(__linux__) || defined(__APPLE__)
497  tid = syscall(SYS_gettid);
498 #else
499  tid = XrdSysThread::ID();
500 #endif
501 
502 // Format the header
503 //
504  k = snprintf(btBuff, sizeof(btBuff),
505  "\nTBT " TidFmt " %p %s obj %p req %s rsp %s %s\n",
506  tid, thisP, head, objP, reqInfo->name, rspInfo->name, tail);
507 
508 // Now dump the stack
509 //
510  DumpStack(btBuff+k, sizeof(btBuff)-k-8, tid);
511 
512 // Output the information
513 //
514  std::cerr <<btBuff <<std::flush;
515 }

References AtomicGet, XrdSysThread::ID(), TidFmt, and TidType.

+ Here is the call graph for this function:

The documentation for this class was generated from the following files: