From cc9bdbcf19354c323c3f090949636267f54851e0 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Mon, 18 Nov 2019 18:43:01 -0500
Subject: DRTVWR-476: Introduce LLStacktrace, a token to stream stack trace.

LLStacktrace has no behavior except when you stream an instance to a
std::ostream. Then it reports the current traceback at that point to the
ostream.

This bit of indirection is intended to avoid the boost/stacktrace.hpp header
from being included everywhere.
---
 indra/llcommon/llerror.cpp | 245 +++++++++++++++++++++++----------------------
 indra/llcommon/llerror.h   |  54 +++++-----
 2 files changed, 158 insertions(+), 141 deletions(-)

(limited to 'indra')

diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index ea0d06b93c..1cb93d27f7 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -53,6 +53,13 @@
 #include "llstl.h"
 #include "lltimer.h"
 
+// On Mac, got:
+// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define
+// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if
+// _Unwind_Backtrace is available without `_GNU_SOURCE`."
+#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
+#include <boost/stacktrace.hpp>
+
 namespace {
 #if LL_WINDOWS
 	void debugger_print(const std::string& s)
@@ -1554,124 +1561,128 @@ namespace LLError
 	S32    LLCallStacks::sIndex  = 0 ;
 
 	//static
-   void LLCallStacks::allocateStackBuffer()
-   {
-	   if(sBuffer == NULL)
-	   {
-		   sBuffer = new char*[512] ;
-		   sBuffer[0] = new char[512 * 128] ;
-		   for(S32 i = 1 ; i < 512 ; i++)
-		   {
-			   sBuffer[i] = sBuffer[i-1] + 128 ;
-		   }
-		   sIndex = 0 ;
-	   }
-   }
-
-   void LLCallStacks::freeStackBuffer()
-   {
-	   if(sBuffer != NULL)
-	   {
-		   delete [] sBuffer[0] ;
-		   delete [] sBuffer ;
-		   sBuffer = NULL ;
-	   }
-   }
-
-   //static
-   void LLCallStacks::push(const char* function, const int line)
-   {
-       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
-       if (!lock.isLocked())
-       {
-           return;
-       }
-
-	   if(sBuffer == NULL)
-	   {
-		   allocateStackBuffer();
-	   }
-
-	   if(sIndex > 511)
-	   {
-		   clear() ;
-	   }
-
-	   strcpy(sBuffer[sIndex], function) ;
-	   sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
-	   sIndex++ ;
-
-	   return ;
-   }
+    void LLCallStacks::allocateStackBuffer()
+    {
+        if(sBuffer == NULL)
+        {
+            sBuffer = new char*[512] ;
+            sBuffer[0] = new char[512 * 128] ;
+            for(S32 i = 1 ; i < 512 ; i++)
+            {
+                sBuffer[i] = sBuffer[i-1] + 128 ;
+            }
+            sIndex = 0 ;
+        }
+    }
 
-	//static
-   std::ostringstream* LLCallStacks::insert(const char* function, const int line)
-   {
-       std::ostringstream* _out = LLError::Log::out();
-	   *_out << function << " line " << line << " " ;
-             
-	   return _out ;
-   }
-
-   //static
-   void LLCallStacks::end(std::ostringstream* _out)
-   {
-       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
-       if (!lock.isLocked())
-       {
-           return;
-       }
-
-	   if(sBuffer == NULL)
-	   {
-		   allocateStackBuffer();
-	   }
-
-	   if(sIndex > 511)
-	   {
-		   clear() ;
-	   }
-
-	   LLError::Log::flush(_out, sBuffer[sIndex++]) ;
-   }
-
-   //static
-   void LLCallStacks::print()
-   {
-       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
-       if (!lock.isLocked())
-       {
-           return;
-       }
-
-       if(sIndex > 0)
-       {
-           LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
-           while(sIndex > 0)
-           {                  
-			   sIndex-- ;
-               LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
-           }
-           LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
-       }
-
-	   if(sBuffer != NULL)
-	   {
-		   freeStackBuffer();
-	   }
-   }
-
-   //static
-   void LLCallStacks::clear()
-   {
-       sIndex = 0 ;
-   }
-
-   //static
-   void LLCallStacks::cleanup()
-   {
-	   freeStackBuffer();
-   }
+    void LLCallStacks::freeStackBuffer()
+    {
+        if(sBuffer != NULL)
+        {
+            delete [] sBuffer[0] ;
+            delete [] sBuffer ;
+            sBuffer = NULL ;
+        }
+    }
+
+    //static
+    void LLCallStacks::push(const char* function, const int line)
+    {
+        LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+        if (!lock.isLocked())
+        {
+            return;
+        }
+
+        if(sBuffer == NULL)
+        {
+            allocateStackBuffer();
+        }
+
+        if(sIndex > 511)
+        {
+            clear() ;
+        }
+
+        strcpy(sBuffer[sIndex], function) ;
+        sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ;
+        sIndex++ ;
+
+        return ;
+    }
+
+    //static
+    std::ostringstream* LLCallStacks::insert(const char* function, const int line)
+    {
+        std::ostringstream* _out = LLError::Log::out();
+        *_out << function << " line " << line << " " ;
+        return _out ;
+    }
+
+    //static
+    void LLCallStacks::end(std::ostringstream* _out)
+    {
+        LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+        if (!lock.isLocked())
+        {
+            return;
+        }
+
+        if(sBuffer == NULL)
+        {
+            allocateStackBuffer();
+        }
+
+        if(sIndex > 511)
+        {
+            clear() ;
+        }
+
+        LLError::Log::flush(_out, sBuffer[sIndex++]) ;
+    }
+
+    //static
+    void LLCallStacks::print()
+    {
+        LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
+        if (!lock.isLocked())
+        {
+            return;
+        }
+
+        if(sIndex > 0)
+        {
+            LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL;
+            while(sIndex > 0)
+            {                  
+                sIndex-- ;
+                LL_INFOS() << sBuffer[sIndex] << LL_ENDL;
+            }
+            LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;
+        }
+
+        if(sBuffer != NULL)
+        {
+            freeStackBuffer();
+        }
+    }
+
+    //static
+    void LLCallStacks::clear()
+    {
+        sIndex = 0 ;
+    }
+
+    //static
+    void LLCallStacks::cleanup()
+    {
+        freeStackBuffer();
+    }
+
+    std::ostream& operator<<(std::ostream& out, const LLStacktrace&)
+    {
+        return out << boost::stacktrace::stacktrace();
+    }
 }
 
 bool debugLoggingEnabled(const std::string& tag)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 9613911531..48162eca9e 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -262,30 +262,36 @@ namespace LLError
 	class LL_COMMON_API NoClassInfo { };
 		// used to indicate no class info known for logging
 
-   //LLCallStacks keeps track of call stacks and output the call stacks to log file
-   //when LLAppViewer::handleViewerCrash() is triggered.
-   //
-   //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
-	//LLCallStacks is designed not to be thread-safe.
-   //so try not to use it in multiple parallel threads at same time.
-   //Used in a single thread at a time is fine.
-   class LL_COMMON_API LLCallStacks
-   {
-   private:
-       static char**  sBuffer ;
-	   static S32     sIndex ;
-
-	   static void allocateStackBuffer();
-	   static void freeStackBuffer();
-          
-   public:   
-	   static void push(const char* function, const int line) ;
-	   static std::ostringstream* insert(const char* function, const int line) ;
-       static void print() ;
-       static void clear() ;
-	   static void end(std::ostringstream* _out) ;
-	   static void cleanup();
-   }; 
+    //LLCallStacks keeps track of call stacks and output the call stacks to log file
+    //when LLAppViewer::handleViewerCrash() is triggered.
+    //
+    //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
+    //LLCallStacks is designed not to be thread-safe.
+    //so try not to use it in multiple parallel threads at same time.
+    //Used in a single thread at a time is fine.
+    class LL_COMMON_API LLCallStacks
+    {
+    private:
+        static char**  sBuffer ;
+        static S32     sIndex ;
+
+        static void allocateStackBuffer();
+        static void freeStackBuffer();
+              
+    public:   
+        static void push(const char* function, const int line) ;
+        static std::ostringstream* insert(const char* function, const int line) ;
+        static void print() ;
+        static void clear() ;
+        static void end(std::ostringstream* _out) ;
+        static void cleanup();
+    };
+
+    // class which, when streamed, inserts the current stack trace
+    struct LLStacktrace
+    {
+        friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&);
+    };
 }
 
 //this is cheaper than llcallstacks if no need to output other variables to call stacks. 
-- 
cgit v1.2.3