From patchwork Sat Nov 23 12:43:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 2346 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1434B6136C for ; Sat, 23 Nov 2019 13:43:18 +0100 (CET) Received: from pendragon.ideasonboard.com (fs96f9c64d.tkyc509.ap.nuro.jp [150.249.198.77]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7CF22440 for ; Sat, 23 Nov 2019 13:43:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1574512997; bh=IEwooAWK+6st23gE0ydFRUG5O5s7awDMmlxL+ysUBx8=; h=From:To:Subject:Date:From; b=kPVGYzQZNHPuUDNoIjFelDaNuRKTCAfJlerqkiwlQn/Z1p+VG1GWBweEd4T2mSWfW iBaD1XPIhMAU+xbUQsHQkEqAh0XP2Jm2+RKA4RzqVi5yAM5I1+IR9ZobpcE/qCVMNy +UpNEJH0mqkL4q6Q9CwuYfeBZxhidP1OF5ejgsqo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 23 Nov 2019 14:43:02 +0200 Message-Id: <20191123124302.25863-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.23.0 MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH] libcamera: Print backtrace on fatal errors X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Nov 2019 12:43:18 -0000 When a fatal error occurs the program aborts, and all the logger provides is the location of the line that caused the error. Extend this with a full backtrace to help debugging. The backtrace is generated using the backtrace() call, a GNU extension to the C library. It is available in glibc and uClibc but not in musl. Test for availability of the function to condition compilation of the backtrace printing. Implementing backtrace support with musl is an exercise left to the reader if desired. Signed-off-by: Laurent Pinchart --- meson.build | 4 ++ src/libcamera/log.cpp | 93 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/meson.build b/meson.build index 0a222ba96dcb..634488589a46 100644 --- a/meson.build +++ b/meson.build @@ -26,6 +26,10 @@ libcamera_version = libcamera_git_version.split('+')[0] cc = meson.get_compiler('c') config_h = configuration_data() +if cc.has_header_symbol('execinfo.h', 'backtrace') + config_h.set('HAVE_BACKTRACE', 1) +endif + if cc.has_header_symbol('stdlib.h', 'secure_getenv', prefix : '#define _GNU_SOURCE') config_h.set('HAVE_SECURE_GETENV', 1) endif diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 50f345b98c74..f4eb8c11adc3 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -7,6 +7,9 @@ #include "log.h" +#if HAVE_BACKTRACE +#include +#endif #include #include #include @@ -108,10 +111,11 @@ public: bool isValid() const; void write(const LogMessage &msg); + void write(const std::string &msg); private: - void writeSyslog(const LogMessage &msg); - void writeStream(const LogMessage &msg); + void writeSyslog(LogSeverity severity, const std::string &msg); + void writeStream(const std::string &msg); std::ostream *stream_; LoggingTarget target_; @@ -180,34 +184,55 @@ bool LogOutput::isValid() const * \param[in] msg Message to write */ void LogOutput::write(const LogMessage &msg) +{ + std::string str; + + switch (target_) { + case LoggingTargetSyslog: + str = std::string(log_severity_name(msg.severity())) + " " + + msg.category().name() + " " + msg.fileInfo() + " " + + msg.msg(); + writeSyslog(msg.severity(), str); + break; + case LoggingTargetStream: + case LoggingTargetFile: + str = "[" + utils::time_point_to_string(msg.timestamp()) + "]" + + log_severity_name(msg.severity()) + " " + + msg.category().name() + " " + msg.fileInfo() + " " + + msg.msg(); + writeStream(str); + break; + default: + break; + } +} + +/** + * \brief Write string to log output + * \param[in] str String to write + */ +void LogOutput::write(const std::string &str) { switch (target_) { case LoggingTargetSyslog: - writeSyslog(msg); + writeSyslog(LogDebug, str); break; case LoggingTargetStream: case LoggingTargetFile: - writeStream(msg); + writeStream(str); break; default: break; } } -void LogOutput::writeSyslog(const LogMessage &msg) +void LogOutput::writeSyslog(LogSeverity severity, const std::string &str) { - std::string str = std::string(log_severity_name(msg.severity())) + " " + - msg.category().name() + " " + msg.fileInfo() + " " + - msg.msg(); - syslog(log_severity_to_syslog(msg.severity()), "%s", str.c_str()); + syslog(log_severity_to_syslog(severity), "%s", str.c_str()); } -void LogOutput::writeStream(const LogMessage &msg) +void LogOutput::writeStream(const std::string &str) { - std::string str = "[" + utils::time_point_to_string(msg.timestamp()) + - "]" + log_severity_name(msg.severity()) + " " + - msg.category().name() + " " + msg.fileInfo() + " " + - msg.msg(); stream_->write(str.c_str(), str.size()); stream_->flush(); } @@ -223,6 +248,7 @@ public: static Logger *instance(); void write(const LogMessage &msg); + void backtrace(); int logSetFile(const char *path); int logSetStream(std::ostream *stream); @@ -240,9 +266,6 @@ private: void registerCategory(LogCategory *category); void unregisterCategory(LogCategory *category); - void writeSyslog(const LogMessage &msg); - void writeStream(const LogMessage &msg); - std::unordered_set categories_; std::list> levels_; @@ -370,6 +393,38 @@ void Logger::write(const LogMessage &msg) output->write(msg); } +/** + * \brief Write a backtrace to the log + */ +void Logger::backtrace() +{ +#if HAVE_BACKTRACE + std::shared_ptr output = std::atomic_load(&output_); + if (!output) + return; + + void *buffer[32]; + int num_entries = ::backtrace(buffer, ARRAY_SIZE(buffer)); + char **strings = backtrace_symbols(buffer, num_entries); + if (!strings) + return; + + std::ostringstream msg; + msg << "Backtrace:" << std::endl; + + /* + * Skip the first two entries that correspond to this method and + * ~LogMessage(). + */ + for (int i = 2; i < num_entries; ++i) + msg << strings[i] << std::endl; + + output->write(msg.str()); + + free(strings); +#endif +} + /** * \brief Set the log file * \param[in] path Full path to the log file @@ -783,8 +838,10 @@ LogMessage::~LogMessage() if (severity_ >= category_.severity()) Logger::instance()->write(*this); - if (severity_ == LogSeverity::LogFatal) + if (severity_ == LogSeverity::LogFatal) { + Logger::instance()->backtrace(); std::abort(); + } } /**