[lldb-dev] [cfe-dev] clang CL breaks LLDB std::string printing

David Blaikie dblaikie at gmail.com
Fri Feb 27 10:28:10 PST 2015


On Fri, Feb 27, 2015 at 10:04 AM, Greg Clayton <clayborg at gmail.com> wrote:

>
> > On Feb 27, 2015, at 9:40 AM, David Blaikie <dblaikie at gmail.com> wrote:
> >
> >
> >
> > On Fri, Feb 27, 2015 at 9:31 AM, Greg Clayton <clayborg at gmail.com>
> wrote:
> > I recommend telling the compiler to not do this using (set
> -no-fstandalone-debug in OTHER_CFLAGS) if you want to debug with LLDB. If
> you don't you can DWARF for the following code:
> >
> >
> > class A : public B
> > {
> > };
> >
> > Where the compiler says "no one used 'B' so I am going to emit a forward
> declaration for 'B'.
> >
> > That's not quite the logic used here. Certainly if you use A then you've
> used B. B may be emitted as a declaration if we know that some other CU
> will contain the definition (eg: using the vtable optimization - if B has
> virtual functions, we'll only emit the definition of B where the vtable
> goes (if B has a key function, this means the debug info definition of B
> goes in exactly one place: where the definition of the key function
> appears))
>
> Sure, then only if B has a vtable this will happen.
>

(or an explicit instantiation declaration (such as std::string) - or is
only used in ways that don't require the complete type)


>
> >
> > Then LLDB tries to make class 'A' in a clang AST context and then we try
> to parse 'B' so we can have 'A' inherit from it and clang of course would
> assert and kill LLDB (if we actually try to give clang a class 'B' that is
> a forward declaration as a base class) so LLDB has to lie to keep clang
> from asserting and just say that 'B' class that contains nothing.
> >
> > Shouldn't it go & find B in another file? The same way you would find
> the definition of foo if one file contained "struct foo; foo *f;" and the
> user executed the command "p f->bar"?
>
> LLDB is designed to parse each shared library individually so that we can
> re-use shared libraries from between multiple runs. If liba.so doesn't
> changed, we don't need to re-parse anything in liba.so or its debug info
> file. If you recompile libb.so, we don't have any dependencies in liba.so
> on types like 'B' from elsewhere otherwise the types passed out by each
> shared library have dependencies and have to throw everything away when any
> dependent shared library is loaded.
>

Ah, thanks for the architectural explanation - this is a detail I hadn't
read about/understood before.


> But in LLDB, when we have a process, _will_ find the real definition
> elsewhere when displaying things to you for things that can legally be
> forward declarations in sources (pointers and references). So we will have
> a variable of type "A" from liba.so and we will be displaying it and if it
> has an instance variable, whose type is "C *" and that 'C' is a forward
> declaration, we will search and find "C" elsewhere (in libb.so) for display
> purposed by switching over to using the type from 'libb.so'. But we can't
> do this for things that can't be forward declarations in sources, like base
> classes.
>

OK, so you switch contexts to find the type (knowing where it is - with
some index, etc).

It seems to me that to support this kind of optimized debug info with
LLDB's architecture similar things could be done during AST building time -
switching library context to find the definition elsewhere. The extra
wrinkle being you'd want to keep track of the dependent libraries used in
this case - and, yes, it'd come with some performance cost - if you had to
reload the dependent library, you'd reload any libraries that depended upon
it (or possibly only the specific types that were dependent)

I mean that's up to you guys/whoever's working on the project if it's
important - I get that Google's needs for small debug info are somewhat
more dire than other projects, but even before I started on debug info it
seemed like size was a continuous concern/priority - so I'm still somewhat
surprised/confused by the apparent priorities here, but we have a flag &
the choice is easy enough to make.

I imagine at some point, the Googlers working on LLDB will ultimately
want/need to implement this to keep our debug info size improvements on
while being usable with LLDB, but I don't actually know their
plans/goals/tradeoffs. (also, we tend to build everything statically, as I
understand it - so shared library features aren't as valuable for our use
cases)

- David


>
> >
> > The idea was that someone will certainly declare 'B' somewhere in your
> current source base.
> >
> > It's more robust than that - the vtable optimization, assuming you
> compile your whole program with debug info, is guaranteed by the C++
> standard (odr use of the class means you have a definition of all the
> virtual members /somewhere/ in your program).
>
> Yes, but this doesn't guarantee that this debug info is in the current
> shared library or executable. So if the other shared library doesn't have
> debug info, then you end up missing debug info. LLDB parses shared
> libraries individually because it can have multiple debug sessions running
> simultaneously, each using different combinations of shared libraries at
> the same time. So we can't take type 'B' from libb.so and copy it into type
> 'A' from liba.so because if libb.so changes and we restart a debug session,
> we would have to throw away all type info (or maintain dependency lists).
> Further we can't do it because process 123 might be still be using the old
> version of libb.so while process 124 restarted and is using the new version.
>
> > GCC has been doing this optimization for a while now, Clang was doing
> similar optimizations ("struct foo { }; foo *f;" - we'd only emit the
> declaration of 'foo' since it was never dereferenced) for a while too - I
> believe Eric implemented the first versions of that on a suggestion from
> Chris Lattner, FWIW.
>
> Again, for places that can have forward declarations (for pointers and
> references), this is quite OK. Our variable display logic will find the
> right definition. It is just in the base class case where this falls down
> for LLDB.
> >
> > This mostly holds true, but if you have a header file from a shared
> library that has a C++ class that people might inherit from (like we do in
> Darwin Kernel Extensions),
> >
> > If you don't have debug info for that shared library (hence the
> suggestion to install debug info for the standard library - there are
> packages for it). Granted I imagine it'll take some finagling to change the
> Darwin Kernel Extensions build system to build a partial debug info package
> (presumably you don't want to ship all the debug info for the
> implementation of that library - for size and privacy reasons).
>
> We do have this issue and we won't be changing the default on MacOSX for
> this very reason.
>
> The performance and memory benefits we get in LLDB from having each shared
> library be independent are huge. Re-starting a debug session in Xcode for
> the same program (rerunning) is instant as we have a global cache of shared
> libraries that are all stand alone and have no dependencies. When we still
> used GDB, every restart was a new delay as it loaded all shared libraries
> and debug info for each run. Each debug session was a unique new instance
> of GDB running in a separate process so that GDB could hack its shared
> libraries up any way it chose to with no worries of dependencies because
> there was only 1 debug session going on at a time. If a shared library
> doesn't change in LLDB, we still have a live copy all pre-parsed and ready
> to go in our global cache.
>
> >
> > we end up with a class we use for debugging that isn't allowed to see
> any ivars from "B", nor call any functions declared inside 'B' or any of
> its subclasses (because we told clang 'B' has no contents when creating the
> type in the clang AST. So we default to -no-fstandalone-debug for all of
> Darwin to avoid this.
> >
> > Greg Clayton
> >
> > > On Feb 26, 2015, at 4:35 PM, Ed Maste <emaste at freebsd.org> wrote:
> > >
> > > On 26 February 2015 at 17:28, Adrian Prantl <aprantl at apple.com> wrote:
> > >>
> > >>           The -fstandalone-debug option turns off these
> optimizations.  This is useful when working with 3rd-party libraries that
> don't come with
> > >>           debug information.  This is the default on Darwin.  Note
> that Clang will never emit type information for types that are not
> referenced at
> > >>           all by the program.
> > >
> > > Note that this is also the default on FreeBSD. This might be an
> > > important point when comparing test results on FreeBSD and Linux since
> > > they otherwise share a lot of attributes.
> > >
> > > -Ed
> >
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20150227/779114f3/attachment.html>


More information about the lldb-dev mailing list