[{"id":20133,"web_url":"https://patchwork.libcamera.org/comment/20133/","msgid":"<163403623104.2837254.16299964452241312879@Monstersaurus>","date":"2021-10-12T10:57:11","subject":"Re: [libcamera-devel] [PATCH v2 4/4] libcamera: base: backtrace:\n\tFallback to libunwind for 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:06)\n> libunwind has an API to provide symbolic names for functions. It's less\n> optimal than using backtrace_symbols() or libdw, as it doesn't allow\n> deferring the symbolic names lookup, but it can be usefull as a fallback\n> if no other option is available.\n> \n> A sample backtrace when falling back to libunwind looks like\n> \n> libcamera::VimcCameraData::init()+0xbd\n> libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0\n> libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7\n> libcamera::CameraManager::Private::init()+0x98\n> libcamera::CameraManager::Private::run()+0x9f\n> libcamera::Thread::startThread()+0xee\n> decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77\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\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\n> start_thread+0xde\n> ???\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/base/backtrace.h |  1 +\n>  src/libcamera/base/backtrace.cpp   | 37 +++++++++++++++++++++++++++++-\n>  2 files changed, 37 insertions(+), 1 deletion(-)\n> \n> diff --git a/include/libcamera/base/backtrace.h b/include/libcamera/base/backtrace.h\n> index 58ccc14c8f81..bb77c73b67e3 100644\n> --- a/include/libcamera/base/backtrace.h\n> +++ b/include/libcamera/base/backtrace.h\n> @@ -30,6 +30,7 @@ private:\n>         bool unwindTrace();\n>  \n>         std::vector<void *> backtrace_;\n> +       std::vector<std::string> backtraceText_;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp\n> index 0aafc6a366c5..d93e5518670d 100644\n> --- a/src/libcamera/base/backtrace.cpp\n> +++ b/src/libcamera/base/backtrace.cpp\n> @@ -202,6 +202,12 @@ bool Backtrace::unwindTrace()\n>                 return false;\n>  \n>         do {\n> +#if HAVE_BACKTRACE || HAVE_DW\n> +               /*\n> +                * If backtrace() or libdw is available, they will be used in\n> +                * toString() to provide symbol information for the stack\n> +                * frames using the IP register value.\n> +                */\n>                 unw_word_t ip;\n>                 ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);\n>                 if (ret) {\n> @@ -210,6 +216,29 @@ bool Backtrace::unwindTrace()\n>                 }\n>  \n>                 backtrace_.push_back(reinterpret_cast<void *>(ip));\n> +#else\n> +               /*\n> +                * Otherwise, use libunwind to get the symbol information. As\n> +                * the libunwind API uses cursors, we can't store the IP values\n> +                * and delay symbol lookup to toString().\n> +                */\n> +               char symbol[256];\n> +               unw_word_t offset = 0;\n> +               ret = unw_get_proc_name(&cursor, symbol, sizeof(symbol), &offset);\n> +               if (ret) {\n> +                       backtraceText_.emplace_back(\"???\\n\");\n> +                       continue;\n> +               }\n> +\n> +               std::ostringstream entry;\n> +\n> +               char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);\n> +               entry << (name ? name : symbol);\n> +               free(name);\n> +\n> +               entry << \"+0x\" << std::hex << offset << \"\\n\";\n> +               backtraceText_.emplace_back(entry.str());\n> +#endif\n>         } while (unw_step(&cursor) > 0);\n>  \n>         return true;\n> @@ -245,9 +274,15 @@ std::string Backtrace::toString(unsigned int skipLevels) const\n>          */\n>         skipLevels += 2;\n>  \n> -       if (backtrace_.size() <= skipLevels)\n> +       if (backtrace_.size() <= skipLevels &&\n> +           backtraceText_.size() <= skipLevels)\n>                 return std::string();\n>  \n> +       if (!backtraceText_.empty()) {\n> +               Span<const std::string> trace{ backtraceText_ };\n> +               return utils::join(trace.subspan(skipLevels), \"\");\n\nOh I see. Took a bit of looking to realise that this is concatenating\nall of the std::strings in a vector into a single string, while skipping\nthe number of levels. Neat, but a little bit obtuse to read at first.\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +       }\n> +\n>  #if HAVE_DW\n>         DwflParser dwfl;\n>  \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 7F0F2BDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 12 Oct 2021 10:57:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0E89868F4F;\n\tTue, 12 Oct 2021 12:57:15 +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 88A6168F4C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 12:57:13 +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 28143F1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 12:57:13 +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=\"rvzbxvMB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634036233;\n\tbh=AWrXyZLwjBrngwf2ZN6k5C1+RM3H8ZeJepWpGGHQXL0=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=rvzbxvMBI5l+MG6/+5QfUZK4xwTb5WXDB+S3lZlgvt9GTuXRf5j38OUTjiljZjg1m\n\tY5eKUUcCTPmKi276gLnTQgS1PbM5Z+/UDiAF6x62+x8zdVNHv5AZ7r3BonAdL2jDS5\n\tztxSdKYWYcQNXiFwaGdIRvUF7UpXM4geg1vL4QMY=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20211003223606.20016-5-laurent.pinchart@ideasonboard.com>","References":"<20211003223606.20016-1-laurent.pinchart@ideasonboard.com>\n\t<20211003223606.20016-5-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Tue, 12 Oct 2021 11:57:11 +0100","Message-ID":"<163403623104.2837254.16299964452241312879@Monstersaurus>","User-Agent":"alot/0.9.1","Subject":"Re: [libcamera-devel] [PATCH v2 4/4] libcamera: base: backtrace:\n\tFallback to libunwind for 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":20153,"web_url":"https://patchwork.libcamera.org/comment/20153/","msgid":"<YWX4vuNtK02ajf0k@pendragon.ideasonboard.com>","date":"2021-10-12T21:06:06","subject":"Re: [libcamera-devel] [PATCH v2 4/4] libcamera: base: backtrace:\n\tFallback to libunwind for 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:57:11AM +0100, Kieran Bingham wrote:\n> Quoting Laurent Pinchart (2021-10-03 23:36:06)\n> > libunwind has an API to provide symbolic names for functions. It's less\n> > optimal than using backtrace_symbols() or libdw, as it doesn't allow\n> > deferring the symbolic names lookup, but it can be usefull as a fallback\n> > if no other option is available.\n> > \n> > A sample backtrace when falling back to libunwind looks like\n> > \n> > libcamera::VimcCameraData::init()+0xbd\n> > libcamera::PipelineHandlerVimc::match(libcamera::DeviceEnumerator*)+0x3e0\n> > libcamera::CameraManager::Private::createPipelineHandlers()+0x1a7\n> > libcamera::CameraManager::Private::init()+0x98\n> > libcamera::CameraManager::Private::run()+0x9f\n> > libcamera::Thread::startThread()+0xee\n> > decltype(*(std::__1::forward<libcamera::Thread*>(fp0)).*fp()) std::__1::__invoke<void (libcamera::Thread::*)(), libcamera::Thread*, void>(void (libcamera::Thread::*&&)(), libcamera::Thread*&&)+0x77\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\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\n> > start_thread+0xde\n> > ???\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  include/libcamera/base/backtrace.h |  1 +\n> >  src/libcamera/base/backtrace.cpp   | 37 +++++++++++++++++++++++++++++-\n> >  2 files changed, 37 insertions(+), 1 deletion(-)\n> > \n> > diff --git a/include/libcamera/base/backtrace.h b/include/libcamera/base/backtrace.h\n> > index 58ccc14c8f81..bb77c73b67e3 100644\n> > --- a/include/libcamera/base/backtrace.h\n> > +++ b/include/libcamera/base/backtrace.h\n> > @@ -30,6 +30,7 @@ private:\n> >         bool unwindTrace();\n> >  \n> >         std::vector<void *> backtrace_;\n> > +       std::vector<std::string> backtraceText_;\n> >  };\n> >  \n> >  } /* namespace libcamera */\n> > diff --git a/src/libcamera/base/backtrace.cpp b/src/libcamera/base/backtrace.cpp\n> > index 0aafc6a366c5..d93e5518670d 100644\n> > --- a/src/libcamera/base/backtrace.cpp\n> > +++ b/src/libcamera/base/backtrace.cpp\n> > @@ -202,6 +202,12 @@ bool Backtrace::unwindTrace()\n> >                 return false;\n> >  \n> >         do {\n> > +#if HAVE_BACKTRACE || HAVE_DW\n> > +               /*\n> > +                * If backtrace() or libdw is available, they will be used in\n> > +                * toString() to provide symbol information for the stack\n> > +                * frames using the IP register value.\n> > +                */\n> >                 unw_word_t ip;\n> >                 ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);\n> >                 if (ret) {\n> > @@ -210,6 +216,29 @@ bool Backtrace::unwindTrace()\n> >                 }\n> >  \n> >                 backtrace_.push_back(reinterpret_cast<void *>(ip));\n> > +#else\n> > +               /*\n> > +                * Otherwise, use libunwind to get the symbol information. As\n> > +                * the libunwind API uses cursors, we can't store the IP values\n> > +                * and delay symbol lookup to toString().\n> > +                */\n> > +               char symbol[256];\n> > +               unw_word_t offset = 0;\n> > +               ret = unw_get_proc_name(&cursor, symbol, sizeof(symbol), &offset);\n> > +               if (ret) {\n> > +                       backtraceText_.emplace_back(\"???\\n\");\n> > +                       continue;\n> > +               }\n> > +\n> > +               std::ostringstream entry;\n> > +\n> > +               char *name = abi::__cxa_demangle(symbol, nullptr, nullptr, nullptr);\n> > +               entry << (name ? name : symbol);\n> > +               free(name);\n> > +\n> > +               entry << \"+0x\" << std::hex << offset << \"\\n\";\n> > +               backtraceText_.emplace_back(entry.str());\n> > +#endif\n> >         } while (unw_step(&cursor) > 0);\n> >  \n> >         return true;\n> > @@ -245,9 +274,15 @@ std::string Backtrace::toString(unsigned int skipLevels) const\n> >          */\n> >         skipLevels += 2;\n> >  \n> > -       if (backtrace_.size() <= skipLevels)\n> > +       if (backtrace_.size() <= skipLevels &&\n> > +           backtraceText_.size() <= skipLevels)\n> >                 return std::string();\n> >  \n> > +       if (!backtraceText_.empty()) {\n> > +               Span<const std::string> trace{ backtraceText_ };\n> > +               return utils::join(trace.subspan(skipLevels), \"\");\n> \n> Oh I see. Took a bit of looking to realise that this is concatenating\n> all of the std::strings in a vector into a single string, while skipping\n> the number of levels. Neat, but a little bit obtuse to read at first.\n\nThe C++20 ranges library is supposed to enable more expressive syntaxes,\nsuch as\n\n\treturn backtraceText_ | std::views::drop(skipLevels) | std::views::join(\"\");\n\n(won't work as-is, it doesn't compile and I don't want to spend time\nfiguring out what's wrong :-)).\n\nThe concept is interesting, but it seems that in real life scenari it's\nactually difficult to use.\n\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> > +       }\n> > +\n> >  #if HAVE_DW\n> >         DwflParser dwfl;\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 64527BDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 12 Oct 2021 21:06:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D551C68F4F;\n\tTue, 12 Oct 2021 23:06:21 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A087168F4C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 12 Oct 2021 23:06:20 +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 13D5DF1;\n\tTue, 12 Oct 2021 23:06:19 +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=\"V3FKwEGN\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1634072780;\n\tbh=oRieRJM0xfbKZM1j1hJmdCc08WI6jEqjWtPJvxngB1k=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=V3FKwEGNPM5RMPEaLnjos86OadUVELXsTzVwHCe3LVYdha1m/5/oc4G7YyqAcrfgK\n\teHfPKJFQ7Y8XLECgXN/z1cX5YWyFznBq7G0k46oaWnI1pRat36lXxq7ep58xKY+1wC\n\tjJe0qNDZLoVn7UcU3yz5ICQ5A+ts8tulK89wL0bg=","Date":"Wed, 13 Oct 2021 00:06:06 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YWX4vuNtK02ajf0k@pendragon.ideasonboard.com>","References":"<20211003223606.20016-1-laurent.pinchart@ideasonboard.com>\n\t<20211003223606.20016-5-laurent.pinchart@ideasonboard.com>\n\t<163403623104.2837254.16299964452241312879@Monstersaurus>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<163403623104.2837254.16299964452241312879@Monstersaurus>","Subject":"Re: [libcamera-devel] [PATCH v2 4/4] libcamera: base: backtrace:\n\tFallback to libunwind for 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>"}}]