[{"id":20131,"web_url":"https://patchwork.libcamera.org/comment/20131/","msgid":"<163403523771.2837254.4892420917055359573@Monstersaurus>","date":"2021-10-12T10:40:37","subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2021-10-03 23:36:04)\n> libdw provides access to debugging information. This allows creating\n> better stack trace entries, with file names and line numbers, but also\n> with demangled symbols as the symbol name is available and can be passed\n> to abi::__cxa_demangle().\n> \n> With libdw, the backtrace previously generated by backtrace_symbols()\n> \n> src/cam/../libcamera/libcamera.so(_ZN9libcamera14VimcCameraData4initEv+0xbd) [0x7f7dbb73222d]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera19PipelineHandlerVimc5matchEPNS_16DeviceEnumeratorE+0x3e0) [0x7f7dbb731c40]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private22createPipelineHandlersEv+0x1a7) [0x7f7dbb5ea027]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private4initEv+0x98) [0x7f7dbb5e9dc8]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private3runEv+0x9f) [0x7f7dbb5e9c5f]\n> src/cam/../libcamera/base/libcamera-base.so(_ZN9libcamera6Thread11startThreadEv+0xee) [0x7f7dbb3e95be]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f9d7) [0x7f7dbb3ec9d7]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f90e) [0x7f7dbb3ec90e]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f2c2) [0x7f7dbb3ec2c2]\n> /lib64/libpthread.so.0(+0x7e8e) [0x7f7dbab65e8e]\n> /lib64/libc.so.6(clone+0x3f) [0x7f7dbb10b26f]\n> \n> becomes\n> \n> libcamera::VimcCameraData::init()+0xbd (src/libcamera/libcamera.so [0x00007f9de605b22d])\n> libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0 (src/libcamera/libcamera.so [0x00007f9de605ac40])\n> libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7 (src/libcamera/libcamera.so [0x00007f9de5f13027])\n> libcamera::CameraManager::Private::init()+0x98 (src/libcamera/libcamera.so [0x00007f9de5f12dc8])\n> libcamera::CameraManager::Private::run()+0x9f (src/libcamera/libcamera.so [0x00007f9de5f12c5f])\n> libcamera::Thread::startThread()+0xee (src/libcamera/base/libcamera-base.so [0x00007f9de5d125be])\n> decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77 (src/libcamera/base/libcamera-base.so [0x00007f9de5d159d7])\n> void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*, 2ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*>&, std::__1::__tuple_indices<2ul>)+0x3e (src/libcamera/base/libcamera-base.so [0x00007f9de5d1590e])\n> void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*> >(void*)+0x62 (src/libcamera/base/libcamera-base.so [0x00007f9de5d152c2])\n> start_thread+0xde (/var/tmp/portage/sys-libs/glibc-2.33-r1/work/glibc-2.33/nptl/pthread_create.c:482)\n> __clone+0x3f (../sysdeps/unix/sysv/linux/x86_64/clone.S:97)\n> \n> The stack entries related to libcamera are missing source file name and\n> line information, which will be investigated separately, but this is\n> still an improvement.\n> \n> Use libdw when available, falling back to backtrace_symbols() otherwise,\n> or if libdw fails for any reason.\n\nWe still have the addresses printed, so there is no loss. Files and line\nnumbers would be a great addition indeed, but they can still be obtained\nmanually if required. (or often determined by looking at the next\nentry of the call stack to see what was called, but of course this isn't\nalways unique).\n\nWe might want to have a 'debug facilities dependecies' section added to\nthe README.rst for libdw(-dev?)\n\nBut either way...\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/libcamera/base/backtrace.cpp | 120 +++++++++++++++++++++++++++++++\n>  src/libcamera/base/meson.build   |   7 ++\n>  2 files changed, 127 insertions(+)\n> \n> diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp\n> index c010a7e42e4d..79e4a31f3d21 100644\n> --- a/src/libcamera/base/backtrace.cpp\n> +++ b/src/libcamera/base/backtrace.cpp\n> @@ -12,9 +12,16 @@\n>  #include <stdlib.h>\n>  #endif\n>  \n> +#ifdef HAVE_DW\n> +#include <cxxabi.h>\n> +#include <elfutils/libdwfl.h>\n> +#include <unistd.h>\n> +#endif\n> +\n>  #include <sstream>\n>  \n>  #include <libcamera/base/span.h>\n> +#include <libcamera/base/utils.h>\n>  \n>  /**\n>   * \\file backtrace.h\n> @@ -23,6 +30,101 @@\n>  \n>  namespace libcamera {\n>  \n> +namespace {\n> +\n> +#if HAVE_DW\n> +class DwflParser\n> +{\n> +public:\n> +       DwflParser();\n> +       ~DwflParser();\n> +\n> +       bool isValid() const { return valid_; }\n> +       std::string stackEntry(const void *ip);\n> +\n> +private:\n> +       Dwfl_Callbacks callbacks_;\n> +       Dwfl *dwfl_;\n> +       bool valid_;\n> +};\n> +\n> +DwflParser::DwflParser()\n> +       : callbacks_({}), dwfl_(nullptr), valid_(false)\n> +{\n> +       callbacks_.find_elf = dwfl_linux_proc_find_elf;\n> +       callbacks_.find_debuginfo = dwfl_standard_find_debuginfo;\n> +\n> +       dwfl_ = dwfl_begin(&callbacks_);\n> +       if (!dwfl_)\n> +               return;\n> +\n> +       int ret = dwfl_linux_proc_report(dwfl_, getpid());\n> +       if (ret)\n> +               return;\n> +\n> +       ret = dwfl_report_end(dwfl_, nullptr, nullptr);\n> +       if (ret)\n> +               return;\n> +\n> +       valid_ = true;\n> +}\n> +\n> +DwflParser::~DwflParser()\n> +{\n> +       if (dwfl_)\n> +               dwfl_end(dwfl_);\n> +}\n> +\n> +std::string DwflParser::stackEntry(const void *ip)\n> +{\n> +       Dwarf_Addr addr = reinterpret_cast<Dwarf_Addr>(ip);\n> +\n> +       Dwfl_Module *module = dwfl_addrmodule(dwfl_, addr);\n> +       if (!module)\n> +               return std::string();\n> +\n> +       std::ostringstream entry;\n> +\n> +       GElf_Off offset;\n> +       GElf_Sym sym;\n> +       const char *symbol = dwfl_module_addrinfo(module, addr, &offset, &sym,\n> +                                                 nullptr, nullptr, nullptr);\n> +       if (symbol) {\n> +               char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);\n> +               entry << (name ? name : symbol) << \"+0x\" << std::hex << offset\n> +                     << std::dec;\n> +               free(name);\n> +       } else {\n> +               entry << \"??? [\" << utils::hex(addr) << \"]\";\n> +       }\n> +\n> +       entry << \" (\";\n> +\n> +       Dwfl_Line *line = dwfl_module_getsrc(module, addr);\n> +       if (line) {\n> +               const char *filename;\n> +               int lineNumber = 0;\n> +\n> +               filename = dwfl_lineinfo(line, &addr, &lineNumber, nullptr,\n> +                                        nullptr, nullptr);\n> +\n> +               entry << (filename ? filename : \"???\") << \":\" << lineNumber;\n> +       } else {\n> +               const char *filename = nullptr;\n> +\n> +               dwfl_module_info(module, nullptr, nullptr, nullptr, nullptr,\n> +                                nullptr, &filename, nullptr);\n> +\n> +               entry << (filename ? filename : \"???\") << \" [\" << utils::hex(addr) << \"]\";\n> +       }\n> +\n> +       entry << \")\";\n> +       return entry.str();\n> +}\n> +#endif /* HAVE_DW */\n> +\n> +} /* namespace */\n> +\n>  /**\n>   * \\class Backtrace\n>   * \\brief Representation of a call stack backtrace\n> @@ -85,6 +187,24 @@ std::string Backtrace::toString(unsigned int skipLevels) const\n>         if (backtrace_.size() <= skipLevels)\n>                 return std::string();\n>  \n> +#if HAVE_DW\n> +       DwflParser dwfl;\n> +\n> +       if (dwfl.isValid()) {\n> +               std::ostringstream msg;\n> +\n> +               Span<void *const> trace{ backtrace_ };\n> +               for (const void *ip : trace.subspan(skipLevels)) {\n> +                       if (ip)\n> +                               msg << dwfl.stackEntry(ip) << std::endl;\n> +                       else\n> +                               msg << \"???\" << std::endl;\n> +               }\n> +\n> +               return msg.str();\n> +       }\n> +#endif\n> +\n>  #if HAVE_BACKTRACE\n>         Span<void *const> trace{ backtrace_ };\n>         trace = trace.subspan(skipLevels);\n> diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\n> index fc00296dfa8a..4c44b9f55011 100644\n> --- a/src/libcamera/base/meson.build\n> +++ b/src/libcamera/base/meson.build\n> @@ -19,13 +19,20 @@ libcamera_base_sources = files([\n>      'utils.cpp',\n>  ])\n>  \n> +libdw = cc.find_library('libdw', required : false)\n> +\n>  if cc.has_header_symbol('execinfo.h', 'backtrace')\n>      config_h.set('HAVE_BACKTRACE', 1)\n>  endif\n>  \n> +if libdw.found()\n> +    config_h.set('HAVE_DW', 1)\n> +endif\n> +\n>  libcamera_base_deps = [\n>      dependency('threads'),\n>      libatomic,\n> +    libdw,\n>  ]\n>  \n>  # Internal components must use the libcamera_base_private dependency to enable\n> -- \n> Regards,\n> \n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D9E8DBDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 12 Oct 2021 10:40:41 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6073A68F4F;\n\tTue, 12 Oct 2021 12:40:41 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A7A2B68F4C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 12:40:40 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 304F88C4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 12:40:40 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"O3A0pbur\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634035240;\n\tbh=LgH2x0Y36u7TPl9i8Act+UmjkqSC8V9b++F8+8qrn9E=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=O3A0pburt3hGD/6uYqgH5zwUt/UuxwScXsDEst/mvQ5Zuh00KgO/0YjVSOqb6G1cg\n\ty3KXc5aghHbb4pLc7ohmA6f05VH3Mv6NpySijYuTkRONOdTzNCfanbijjeV62QEcbj\n\tpc0cuCjZ/yschAmk2tN6MhXsSL9+WsAE0CkiGHc0=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20211003223606.20016-3-laurent.pinchart@ideasonboard.com>","References":"<20211003223606.20016-1-laurent.pinchart@ideasonboard.com>\n\t<20211003223606.20016-3-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Tue, 12 Oct 2021 11:40:37 +0100","Message-ID":"<163403523771.2837254.4892420917055359573@Monstersaurus>","User-Agent":"alot/0.9.1","Subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":20152,"web_url":"https://patchwork.libcamera.org/comment/20152/","msgid":"<YWXzJYZworSPa9tq@pendragon.ideasonboard.com>","date":"2021-10-12T20:42:13","subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Tue, Oct 12, 2021 at 11:40:37AM +0100, Kieran Bingham wrote:\n> Quoting Laurent Pinchart (2021-10-03 23:36:04)\n> > libdw provides access to debugging information. This allows creating\n> > better stack trace entries, with file names and line numbers, but also\n> > with demangled symbols as the symbol name is available and can be passed\n> > to abi::__cxa_demangle().\n> > \n> > With libdw, the backtrace previously generated by backtrace_symbols()\n> > \n> > src/cam/../libcamera/libcamera.so(_ZN9libcamera14VimcCameraData4initEv+0xbd) [0x7f7dbb73222d]\n> > src/cam/../libcamera/libcamera.so(_ZN9libcamera19PipelineHandlerVimc5matchEPNS_16DeviceEnumeratorE+0x3e0) [0x7f7dbb731c40]\n> > src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private22createPipelineHandlersEv+0x1a7) [0x7f7dbb5ea027]\n> > src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private4initEv+0x98) [0x7f7dbb5e9dc8]\n> > src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private3runEv+0x9f) [0x7f7dbb5e9c5f]\n> > src/cam/../libcamera/base/libcamera-base.so(_ZN9libcamera6Thread11startThreadEv+0xee) [0x7f7dbb3e95be]\n> > src/cam/../libcamera/base/libcamera-base.so(+0x4f9d7) [0x7f7dbb3ec9d7]\n> > src/cam/../libcamera/base/libcamera-base.so(+0x4f90e) [0x7f7dbb3ec90e]\n> > src/cam/../libcamera/base/libcamera-base.so(+0x4f2c2) [0x7f7dbb3ec2c2]\n> > /lib64/libpthread.so.0(+0x7e8e) [0x7f7dbab65e8e]\n> > /lib64/libc.so.6(clone+0x3f) [0x7f7dbb10b26f]\n> > \n> > becomes\n> > \n> > libcamera::VimcCameraData::init()+0xbd (src/libcamera/libcamera.so [0x00007f9de605b22d])\n> > libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0 (src/libcamera/libcamera.so [0x00007f9de605ac40])\n> > libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7 (src/libcamera/libcamera.so [0x00007f9de5f13027])\n> > libcamera::CameraManager::Private::init()+0x98 (src/libcamera/libcamera.so [0x00007f9de5f12dc8])\n> > libcamera::CameraManager::Private::run()+0x9f (src/libcamera/libcamera.so [0x00007f9de5f12c5f])\n> > libcamera::Thread::startThread()+0xee (src/libcamera/base/libcamera-base.so [0x00007f9de5d125be])\n> > decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77 (src/libcamera/base/libcamera-base.so [0x00007f9de5d159d7])\n> > void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*, 2ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*>&, std::__1::__tuple_indices<2ul>)+0x3e (src/libcamera/base/libcamera-base.so [0x00007f9de5d1590e])\n> > void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*> >(void*)+0x62 (src/libcamera/base/libcamera-base.so [0x00007f9de5d152c2])\n> > start_thread+0xde (/var/tmp/portage/sys-libs/glibc-2.33-r1/work/glibc-2.33/nptl/pthread_create.c:482)\n> > __clone+0x3f (../sysdeps/unix/sysv/linux/x86_64/clone.S:97)\n> > \n> > The stack entries related to libcamera are missing source file name and\n> > line information, which will be investigated separately, but this is\n> > still an improvement.\n> > \n> > Use libdw when available, falling back to backtrace_symbols() otherwise,\n> > or if libdw fails for any reason.\n> \n> We still have the addresses printed, so there is no loss. Files and line\n> numbers would be a great addition indeed, but they can still be obtained\n> manually if required. (or often determined by looking at the next\n> entry of the call stack to see what was called, but of course this isn't\n> always unique).\n> \n> We might want to have a 'debug facilities dependecies' section added to\n> the README.rst for libdw(-dev?)\n\nGood idea, I'll submit a separate patch for that.\n\n> But either way...\n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  src/libcamera/base/backtrace.cpp | 120 +++++++++++++++++++++++++++++++\n> >  src/libcamera/base/meson.build   |   7 ++\n> >  2 files changed, 127 insertions(+)\n> > \n> > diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp\n> > index c010a7e42e4d..79e4a31f3d21 100644\n> > --- a/src/libcamera/base/backtrace.cpp\n> > +++ b/src/libcamera/base/backtrace.cpp\n> > @@ -12,9 +12,16 @@\n> >  #include <stdlib.h>\n> >  #endif\n> >  \n> > +#ifdef HAVE_DW\n> > +#include <cxxabi.h>\n> > +#include <elfutils/libdwfl.h>\n> > +#include <unistd.h>\n> > +#endif\n> > +\n> >  #include <sstream>\n> >  \n> >  #include <libcamera/base/span.h>\n> > +#include <libcamera/base/utils.h>\n> >  \n> >  /**\n> >   * \\file backtrace.h\n> > @@ -23,6 +30,101 @@\n> >  \n> >  namespace libcamera {\n> >  \n> > +namespace {\n> > +\n> > +#if HAVE_DW\n> > +class DwflParser\n> > +{\n> > +public:\n> > +       DwflParser();\n> > +       ~DwflParser();\n> > +\n> > +       bool isValid() const { return valid_; }\n> > +       std::string stackEntry(const void *ip);\n> > +\n> > +private:\n> > +       Dwfl_Callbacks callbacks_;\n> > +       Dwfl *dwfl_;\n> > +       bool valid_;\n> > +};\n> > +\n> > +DwflParser::DwflParser()\n> > +       : callbacks_({}), dwfl_(nullptr), valid_(false)\n> > +{\n> > +       callbacks_.find_elf = dwfl_linux_proc_find_elf;\n> > +       callbacks_.find_debuginfo = dwfl_standard_find_debuginfo;\n> > +\n> > +       dwfl_ = dwfl_begin(&callbacks_);\n> > +       if (!dwfl_)\n> > +               return;\n> > +\n> > +       int ret = dwfl_linux_proc_report(dwfl_, getpid());\n> > +       if (ret)\n> > +               return;\n> > +\n> > +       ret = dwfl_report_end(dwfl_, nullptr, nullptr);\n> > +       if (ret)\n> > +               return;\n> > +\n> > +       valid_ = true;\n> > +}\n> > +\n> > +DwflParser::~DwflParser()\n> > +{\n> > +       if (dwfl_)\n> > +               dwfl_end(dwfl_);\n> > +}\n> > +\n> > +std::string DwflParser::stackEntry(const void *ip)\n> > +{\n> > +       Dwarf_Addr addr = reinterpret_cast<Dwarf_Addr>(ip);\n> > +\n> > +       Dwfl_Module *module = dwfl_addrmodule(dwfl_, addr);\n> > +       if (!module)\n> > +               return std::string();\n> > +\n> > +       std::ostringstream entry;\n> > +\n> > +       GElf_Off offset;\n> > +       GElf_Sym sym;\n> > +       const char *symbol = dwfl_module_addrinfo(module, addr, &offset, &sym,\n> > +                                                 nullptr, nullptr, nullptr);\n> > +       if (symbol) {\n> > +               char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);\n> > +               entry << (name ? name : symbol) << \"+0x\" << std::hex << offset\n> > +                     << std::dec;\n> > +               free(name);\n> > +       } else {\n> > +               entry << \"??? [\" << utils::hex(addr) << \"]\";\n> > +       }\n> > +\n> > +       entry << \" (\";\n> > +\n> > +       Dwfl_Line *line = dwfl_module_getsrc(module, addr);\n> > +       if (line) {\n> > +               const char *filename;\n> > +               int lineNumber = 0;\n> > +\n> > +               filename = dwfl_lineinfo(line, &addr, &lineNumber, nullptr,\n> > +                                        nullptr, nullptr);\n> > +\n> > +               entry << (filename ? filename : \"???\") << \":\" << lineNumber;\n> > +       } else {\n> > +               const char *filename = nullptr;\n> > +\n> > +               dwfl_module_info(module, nullptr, nullptr, nullptr, nullptr,\n> > +                                nullptr, &filename, nullptr);\n> > +\n> > +               entry << (filename ? filename : \"???\") << \" [\" << utils::hex(addr) << \"]\";\n> > +       }\n> > +\n> > +       entry << \")\";\n> > +       return entry.str();\n> > +}\n> > +#endif /* HAVE_DW */\n> > +\n> > +} /* namespace */\n> > +\n> >  /**\n> >   * \\class Backtrace\n> >   * \\brief Representation of a call stack backtrace\n> > @@ -85,6 +187,24 @@ std::string Backtrace::toString(unsigned int skipLevels) const\n> >         if (backtrace_.size() <= skipLevels)\n> >                 return std::string();\n> >  \n> > +#if HAVE_DW\n> > +       DwflParser dwfl;\n> > +\n> > +       if (dwfl.isValid()) {\n> > +               std::ostringstream msg;\n> > +\n> > +               Span<void *const> trace{ backtrace_ };\n> > +               for (const void *ip : trace.subspan(skipLevels)) {\n> > +                       if (ip)\n> > +                               msg << dwfl.stackEntry(ip) << std::endl;\n> > +                       else\n> > +                               msg << \"???\" << std::endl;\n> > +               }\n> > +\n> > +               return msg.str();\n> > +       }\n> > +#endif\n> > +\n> >  #if HAVE_BACKTRACE\n> >         Span<void *const> trace{ backtrace_ };\n> >         trace = trace.subspan(skipLevels);\n> > diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\n> > index fc00296dfa8a..4c44b9f55011 100644\n> > --- a/src/libcamera/base/meson.build\n> > +++ b/src/libcamera/base/meson.build\n> > @@ -19,13 +19,20 @@ libcamera_base_sources = files([\n> >      'utils.cpp',\n> >  ])\n> >  \n> > +libdw = cc.find_library('libdw', required : false)\n> > +\n> >  if cc.has_header_symbol('execinfo.h', 'backtrace')\n> >      config_h.set('HAVE_BACKTRACE', 1)\n> >  endif\n> >  \n> > +if libdw.found()\n> > +    config_h.set('HAVE_DW', 1)\n> > +endif\n> > +\n> >  libcamera_base_deps = [\n> >      dependency('threads'),\n> >      libatomic,\n> > +    libdw,\n> >  ]\n> >  \n> >  # Internal components must use the libcamera_base_private dependency to enable","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 07969C323E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 12 Oct 2021 20:42:29 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CBBE368F4F;\n\tTue, 12 Oct 2021 22:42:28 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C59BB68F4C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 22:42:27 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 661E1F1;\n\tTue, 12 Oct 2021 22:42:27 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"LZWMRLOe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634071347;\n\tbh=ieAyhbT1e6y6+Pzq07vi4zAN7hf94uXgPvyl/7/KkZA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=LZWMRLOe2ljef6GuZtHr7k8VlF3BnHnhPfyJ05qBzY+TrFQ8UiQDdxLeBqPEr/pNp\n\tiSVAUtMlNKvGRSoZabn0BPtiNMMv8QMhLR4EqxPnxxbZ8PoPr7jb/jxN42P56Jpe9s\n\tNwJeKnjfR/RnYhpG8KqHk8sQmuzLgQeWW9foYCYQ=","Date":"Tue, 12 Oct 2021 23:42:13 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YWXzJYZworSPa9tq@pendragon.ideasonboard.com>","References":"<20211003223606.20016-1-laurent.pinchart@ideasonboard.com>\n\t<20211003223606.20016-3-laurent.pinchart@ideasonboard.com>\n\t<163403523771.2837254.4892420917055359573@Monstersaurus>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<163403523771.2837254.4892420917055359573@Monstersaurus>","Subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":20256,"web_url":"https://patchwork.libcamera.org/comment/20256/","msgid":"<20211018035830.GB2066071@pyrite.rasen.tech>","date":"2021-10-18T03:58:30","subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Hi Laurent,\n\nOn Mon, Oct 04, 2021 at 01:36:04AM +0300, Laurent Pinchart wrote:\n> libdw provides access to debugging information. This allows creating\n> better stack trace entries, with file names and line numbers, but also\n> with demangled symbols as the symbol name is available and can be passed\n> to abi::__cxa_demangle().\n> \n> With libdw, the backtrace previously generated by backtrace_symbols()\n> \n> src/cam/../libcamera/libcamera.so(_ZN9libcamera14VimcCameraData4initEv+0xbd) [0x7f7dbb73222d]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera19PipelineHandlerVimc5matchEPNS_16DeviceEnumeratorE+0x3e0) [0x7f7dbb731c40]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private22createPipelineHandlersEv+0x1a7) [0x7f7dbb5ea027]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private4initEv+0x98) [0x7f7dbb5e9dc8]\n> src/cam/../libcamera/libcamera.so(_ZN9libcamera13CameraManager7Private3runEv+0x9f) [0x7f7dbb5e9c5f]\n> src/cam/../libcamera/base/libcamera-base.so(_ZN9libcamera6Thread11startThreadEv+0xee) [0x7f7dbb3e95be]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f9d7) [0x7f7dbb3ec9d7]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f90e) [0x7f7dbb3ec90e]\n> src/cam/../libcamera/base/libcamera-base.so(+0x4f2c2) [0x7f7dbb3ec2c2]\n> /lib64/libpthread.so.0(+0x7e8e) [0x7f7dbab65e8e]\n> /lib64/libc.so.6(clone+0x3f) [0x7f7dbb10b26f]\n> \n> becomes\n> \n> libcamera::VimcCameraData::init()+0xbd (src/libcamera/libcamera.so [0x00007f9de605b22d])\n> libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0 (src/libcamera/libcamera.so [0x00007f9de605ac40])\n> libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7 (src/libcamera/libcamera.so [0x00007f9de5f13027])\n> libcamera::CameraManager::Private::init()+0x98 (src/libcamera/libcamera.so [0x00007f9de5f12dc8])\n> libcamera::CameraManager::Private::run()+0x9f (src/libcamera/libcamera.so [0x00007f9de5f12c5f])\n> libcamera::Thread::startThread()+0xee (src/libcamera/base/libcamera-base.so [0x00007f9de5d125be])\n> decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77 (src/libcamera/base/libcamera-base.so [0x00007f9de5d159d7])\n> void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*, 2ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*>&, std::__1::__tuple_indices<2ul>)+0x3e (src/libcamera/base/libcamera-base.so [0x00007f9de5d1590e])\n> void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (libcamera::Thread::*)(), libcamera::Thread*> >(void*)+0x62 (src/libcamera/base/libcamera-base.so [0x00007f9de5d152c2])\n> start_thread+0xde (/var/tmp/portage/sys-libs/glibc-2.33-r1/work/glibc-2.33/nptl/pthread_create.c:482)\n> __clone+0x3f (../sysdeps/unix/sysv/linux/x86_64/clone.S:97)\n> \n> The stack entries related to libcamera are missing source file name and\n> line information, which will be investigated separately, but this is\n> still an improvement.\n> \n> Use libdw when available, falling back to backtrace_symbols() otherwise,\n> or if libdw fails for any reason.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nI agree with Kieran, that an addition to the dependencies page with a\ndebug section would be good.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n>  src/libcamera/base/backtrace.cpp | 120 +++++++++++++++++++++++++++++++\n>  src/libcamera/base/meson.build   |   7 ++\n>  2 files changed, 127 insertions(+)\n> \n> diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp\n> index c010a7e42e4d..79e4a31f3d21 100644\n> --- a/src/libcamera/base/backtrace.cpp\n> +++ b/src/libcamera/base/backtrace.cpp\n> @@ -12,9 +12,16 @@\n>  #include <stdlib.h>\n>  #endif\n>  \n> +#ifdef HAVE_DW\n> +#include <cxxabi.h>\n> +#include <elfutils/libdwfl.h>\n> +#include <unistd.h>\n> +#endif\n> +\n>  #include <sstream>\n>  \n>  #include <libcamera/base/span.h>\n> +#include <libcamera/base/utils.h>\n>  \n>  /**\n>   * \\file backtrace.h\n> @@ -23,6 +30,101 @@\n>  \n>  namespace libcamera {\n>  \n> +namespace {\n> +\n> +#if HAVE_DW\n> +class DwflParser\n> +{\n> +public:\n> +\tDwflParser();\n> +\t~DwflParser();\n> +\n> +\tbool isValid() const { return valid_; }\n> +\tstd::string stackEntry(const void *ip);\n> +\n> +private:\n> +\tDwfl_Callbacks callbacks_;\n> +\tDwfl *dwfl_;\n> +\tbool valid_;\n> +};\n> +\n> +DwflParser::DwflParser()\n> +\t: callbacks_({}), dwfl_(nullptr), valid_(false)\n> +{\n> +\tcallbacks_.find_elf = dwfl_linux_proc_find_elf;\n> +\tcallbacks_.find_debuginfo = dwfl_standard_find_debuginfo;\n> +\n> +\tdwfl_ = dwfl_begin(&callbacks_);\n> +\tif (!dwfl_)\n> +\t\treturn;\n> +\n> +\tint ret = dwfl_linux_proc_report(dwfl_, getpid());\n> +\tif (ret)\n> +\t\treturn;\n> +\n> +\tret = dwfl_report_end(dwfl_, nullptr, nullptr);\n> +\tif (ret)\n> +\t\treturn;\n> +\n> +\tvalid_ = true;\n> +}\n> +\n> +DwflParser::~DwflParser()\n> +{\n> +\tif (dwfl_)\n> +\t\tdwfl_end(dwfl_);\n> +}\n> +\n> +std::string DwflParser::stackEntry(const void *ip)\n> +{\n> +\tDwarf_Addr addr = reinterpret_cast<Dwarf_Addr>(ip);\n> +\n> +\tDwfl_Module *module = dwfl_addrmodule(dwfl_, addr);\n> +\tif (!module)\n> +\t\treturn std::string();\n> +\n> +\tstd::ostringstream entry;\n> +\n> +\tGElf_Off offset;\n> +\tGElf_Sym sym;\n> +\tconst char *symbol = dwfl_module_addrinfo(module, addr, &offset, &sym,\n> +\t\t\t\t\t\t  nullptr, nullptr, nullptr);\n> +\tif (symbol) {\n> +\t\tchar *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);\n> +\t\tentry << (name ? name : symbol) << \"+0x\" << std::hex << offset\n> +\t\t      << std::dec;\n> +\t\tfree(name);\n> +\t} else {\n> +\t\tentry << \"??? [\" << utils::hex(addr) << \"]\";\n> +\t}\n> +\n> +\tentry << \" (\";\n> +\n> +\tDwfl_Line *line = dwfl_module_getsrc(module, addr);\n> +\tif (line) {\n> +\t\tconst char *filename;\n> +\t\tint lineNumber = 0;\n> +\n> +\t\tfilename = dwfl_lineinfo(line, &addr, &lineNumber, nullptr,\n> +\t\t\t\t\t nullptr, nullptr);\n> +\n> +\t\tentry << (filename ? filename : \"???\") << \":\" << lineNumber;\n> +\t} else {\n> +\t\tconst char *filename = nullptr;\n> +\n> +\t\tdwfl_module_info(module, nullptr, nullptr, nullptr, nullptr,\n> +\t\t\t\t nullptr, &filename, nullptr);\n> +\n> +\t\tentry << (filename ? filename : \"???\") << \" [\" << utils::hex(addr) << \"]\";\n> +\t}\n> +\n> +\tentry << \")\";\n> +\treturn entry.str();\n> +}\n> +#endif /* HAVE_DW */\n> +\n> +} /* namespace */\n> +\n>  /**\n>   * \\class Backtrace\n>   * \\brief Representation of a call stack backtrace\n> @@ -85,6 +187,24 @@ std::string Backtrace::toString(unsigned int skipLevels) const\n>  \tif (backtrace_.size() <= skipLevels)\n>  \t\treturn std::string();\n>  \n> +#if HAVE_DW\n> +\tDwflParser dwfl;\n> +\n> +\tif (dwfl.isValid()) {\n> +\t\tstd::ostringstream msg;\n> +\n> +\t\tSpan<void *const> trace{ backtrace_ };\n> +\t\tfor (const void *ip : trace.subspan(skipLevels)) {\n> +\t\t\tif (ip)\n> +\t\t\t\tmsg << dwfl.stackEntry(ip) << std::endl;\n> +\t\t\telse\n> +\t\t\t\tmsg << \"???\" << std::endl;\n> +\t\t}\n> +\n> +\t\treturn msg.str();\n> +\t}\n> +#endif\n> +\n>  #if HAVE_BACKTRACE\n>  \tSpan<void *const> trace{ backtrace_ };\n>  \ttrace = trace.subspan(skipLevels);\n> diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\n> index fc00296dfa8a..4c44b9f55011 100644\n> --- a/src/libcamera/base/meson.build\n> +++ b/src/libcamera/base/meson.build\n> @@ -19,13 +19,20 @@ libcamera_base_sources = files([\n>      'utils.cpp',\n>  ])\n>  \n> +libdw = cc.find_library('libdw', required : false)\n> +\n>  if cc.has_header_symbol('execinfo.h', 'backtrace')\n>      config_h.set('HAVE_BACKTRACE', 1)\n>  endif\n>  \n> +if libdw.found()\n> +    config_h.set('HAVE_DW', 1)\n> +endif\n> +\n>  libcamera_base_deps = [\n>      dependency('threads'),\n>      libatomic,\n> +    libdw,\n>  ]\n>  \n>  # Internal components must use the libcamera_base_private dependency to enable\n> -- \n> Regards,\n> \n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 64CA7C323E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 18 Oct 2021 03:58:41 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CF10A68F59;\n\tMon, 18 Oct 2021 05:58:40 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D661760128\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 18 Oct 2021 05:58:37 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 802DF12A;\n\tMon, 18 Oct 2021 05:58:36 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"XDs/ivHY\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634529517;\n\tbh=y8OhEvq0W1NXHWoZ3M8G2QGMlKLwT6cwR0e8dCW9kNc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=XDs/ivHY+2D32GboejkbkJGCtX0XKXvGOEOGNDu/Dhi5Zq9T67jZYS3+sc80Q7hst\n\tUT7FNJiAfs+x8KhkJn25MvR4T8QO9mR8APNNB7syEuJdygcWqG8s26Fnyg3u082BhK\n\t4BsmRy9vzCcWzvS/82RlOqS7q92Sbfi7+21PLFFk=","Date":"Mon, 18 Oct 2021 12:58:30 +0900","From":"paul.elder@ideasonboard.com","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20211018035830.GB2066071@pyrite.rasen.tech>","References":"<20211003223606.20016-1-laurent.pinchart@ideasonboard.com>\n\t<20211003223606.20016-3-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20211003223606.20016-3-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v2 2/4] libcamera: base: backtrace:\n\tUse libdw to provide symbolic names","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]