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 309 of file XrdOucBackTrace.cc.

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

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

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

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 463 of file XrdOucBackTrace.cc.

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

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: