[lldb-dev] [BUG?] Confusion between translation units?

Ramkumar Ramachandra via lldb-dev lldb-dev at lists.llvm.org
Tue Oct 20 17:04:09 PDT 2015


[Quoting entire email for the benefit of everyone else]

On Tue, Oct 20, 2015 at 7:39 PM, Greg Clayton <gclayton at apple.com> wrote:
> Ok, so try this on all of your dSYM files:
>
> 1 - load the dsym file into lldb:
>
> % xcrun lldb libmwcgir_vm_rt.dylib.dSYM/Contents/Resources/DWARF/libmwcgir_vm_rt.dylib
> (lldb) image lookup -t "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >"
> 2 matches found in /Volumes/work/gclayton/Downloads/libmwcgir_vm_rt.dylib.dSYM/Contents/Resources/DWARF/libmwcgir_vm_rt.dylib:
> id = {0x000211dc}, name = "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", qualified = "llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", byte-size = 24, decl = ilist.h:313, clang_type = "class iplist : public llvm::ilist_traits<llvm::Function> {
>     llvm::Function *Head;
>     llvm::Function *getTail();
>     const llvm::Function *getTail() const;
>     void setTail(llvm::Function *) const;
>     void CreateLazySentinel() const;
>     static bool op_less(llvm::Function &, llvm::Function &);
>     static bool op_equal(llvm::Function &, llvm::Function &);
>     iplist(const llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void operator=(const llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     iplist();
>     ~iplist();
>     iterator begin();
>     const_iterator begin() const;
>     iterator end();
>     const_iterator end() const;
>     reverse_iterator rbegin();
>     const_reverse_iterator rbegin() const;
>     reverse_iterator rend();
>     const_reverse_iterator rend() const;
>     size_type max_size() const;
>     bool empty() const;
>     reference front();
>     const_reference front() const;
>     reference back();
>     const_reference back() const;
>     void swap(llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     iterator insert(iterator, llvm::Function *);
>     iterator insertAfter(iterator, llvm::Function *);
>     llvm::Function *remove(iterator &);
>     llvm::Function *remove(const iterator &);
>     iterator erase(iterator);
>     void clearAndLeakNodesUnsafely();
>     void transfer(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator, iterator);
>     size_type size() const;
>     iterator erase(iterator, iterator);
>     void clear();
>     void push_front(llvm::Function *);
>     void push_back(llvm::Function *);
>     void pop_front();
>     void pop_back();
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator);
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator, iterator);
>     void erase(const llvm::Function &);
>     void unique();
>     void merge(llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void sort();
> }
> "
> id = {0x001a658a}, name = "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", qualified = "llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", byte-size = 24, decl = ilist.h:313, clang_type = "class iplist : public llvm::ilist_traits<llvm::Function> {
>     llvm::Function *Head;
>     llvm::Function *getTail();
>     const llvm::Function *getTail() const;
>     void setTail(llvm::Function *) const;
>     void CreateLazySentinel() const;
>     static bool op_less(llvm::Function &, llvm::Function &);
>     static bool op_equal(llvm::Function &, llvm::Function &);
>     iplist(const llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void operator=(const llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     iplist();
>     ~iplist();
>     iterator begin();
>     const_iterator begin() const;
>     iterator end();
>     const_iterator end() const;
>     reverse_iterator rbegin();
>     const_reverse_iterator rbegin() const;
>     reverse_iterator rend();
>     const_reverse_iterator rend() const;
>     size_type max_size() const;
>     bool empty() const;
>     reference front();
>     const_reference front() const;
>     reference back();
>     const_reference back() const;
>     void swap(llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     iterator insert(iterator, llvm::Function *);
>     iterator insertAfter(iterator, llvm::Function *);
>     llvm::Function *remove(iterator &);
>     llvm::Function *remove(const iterator &);
>     iterator erase(iterator);
>     void clearAndLeakNodesUnsafely();
>     void transfer(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator, iterator);
>     size_type size() const;
>     iterator erase(iterator, iterator);
>     void clear();
>     void push_front(llvm::Function *);
>     void push_back(llvm::Function *);
>     void pop_front();
>     void pop_back();
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator);
>     void splice(iterator, llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &, iterator, iterator);
>     void erase(const llvm::Function &);
>     void unique();
>     void merge(llvm::iplist<llvm::Function, llvm::ilist_traits<llvm::Function> > &);
>     void sort();
> }
> "
>
>
> Do the same thing for any other shared libraries that you have and compare the data in quotes of the 'clang_type = "<copy>"' and save the <copy> to a file. See if any of them differ from each other.
>
>
> What is interesting here is that we have two of the same copies of this type in the same file, this shouldn't happen. I looked into why this is happening and found the reason:
>
> Looking at the two types that were found above we see two types:
>
> id = {0x000211dc}, name = "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", ...
> id = {0x001a658a}, name = "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >", ...
>
> The "id" in this case is actually the DWARF offset: 0x000211dc and 0x001a658a which we can use to dump the DWARF in the dSYM file:
>
> % dwarfdump --show-parents --debug-info=0x000211dc libmwcgir_vm_rt.dylib.dSYM/
> ----------------------------------------------------------------------
>  File: libmwcgir_vm_rt.dylib.dSYM/Contents/Resources/DWARF/libmwcgir_vm_rt.dylib (x86_64)
> ----------------------------------------------------------------------
> .debug_info[0x000211dc]:
>
> 0x00017fa3: TAG_compile_unit [1] *
>              AT_producer( "Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)" )
>              AT_language( DW_LANG_C_plus_plus )
>              AT_name( "vm/CgInstDbgPrint.cpp" )
>              AT_stmt_list( 0x000012a1 )
>              AT_comp_dir( "/mathworks/devel/sbs/34/rramacha.idivide-final-lap/matlab/src/cgir_vm_rt" )
>              AT_low_pc( 0x0000000000002ef0 )
>
> 0x00017fbe:     TAG_namespace [2] *
>                  AT_name( "llvm" )
>                  AT_decl_file( "../../../3p_mirror/maci64/LLVM/include/llvm/ADT/iterator_range.h" )
>                  AT_decl_line( 24 )
>
> 0x000211dc:         TAG_class_type [3] *
>                      AT_name( "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >" )
>                      AT_byte_size( 0x18 )
>                      AT_decl_file( "../../../3p_mirror/maci64/LLVM/include/llvm/ADT/ilist.h" )
>                      AT_decl_line( 313 )
>
>
> % dwarfdump --show-parents --debug-info=0x001a658a libmwcgir_vm_rt.dylib.dSYM/
> ----------------------------------------------------------------------
>  File: libmwcgir_vm_rt.dylib.dSYM/Contents/Resources/DWARF/libmwcgir_vm_rt.dylib (x86_64)
> ----------------------------------------------------------------------
> .debug_info[0x001a658a]:
>
> 0x00172c2a: TAG_compile_unit [185] *
>              AT_producer( "Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)" )
>              AT_language( DW_LANG_C_plus_plus )
>              AT_name( "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp" )
>              AT_low_pc( 0x0000000000027460 )
>              AT_stmt_list( 0x00013f74 )
>              AT_comp_dir( "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/build/lib/Transforms/ObjCARC" )
>
> 0x001a601c:     TAG_namespace [2] *
>                  AT_name( "llvm" )
>                  AT_decl_file( "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/include/llvm/IR/SymbolTableListTraits.h" )
>                  AT_decl_line( 30 )
>
> 0x001a658a:         TAG_class_type [3] *
>                      AT_name( "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >" )
>                      AT_byte_size( 0x18 )
>                      AT_decl_file( "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/include/llvm/ADT/ilist.h" )
>
>
> LLDB uniques types based off of decl file + decl line + full qualified named + byte size. Note that the decl file is "../../../3p_mirror/maci64/LLVM/include/llvm/ADT/ilist.h" and "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/include/llvm/ADT/ilist.h" for the other... This is why we incorrectly create two types, because the keys (decl file) we are using to unique the types are not the same.
>
> So the easy way to fix your problem is fix your build system so that it doesn't do this. It seems that your build is using a relative path for one file "vm/CgInstDbgPrint.cpp" and a full path for another: "/mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp". If you can fix your build system to always use full paths for source files this problem might go away (if no other competing versions of "iplist<llvm::Function, llvm::ilist_traits<llvm::Function> >" exist anywhere).
>
> The other bad thing is even after you normalize the paths you are comparing:
>
> /mathworks/devel/sbs/34/rramacha.idivide-final-lap/3p_mirror/maci64/LLVM/include/llvm/ADT/ilist.h
> /mathworks/devel/sandbox/rramacha/3p-tmw-osx/3p/derived/maci64/LLVM/llvm/include/llvm/ADT/ilist.h
>
> Are you pulling in data from two different copies of LLVM in your project? Or is something in here symlink to the other somewhere?

Excellent find. Yes, 3p_mirror is a symlink to the 3p-tmw-osx location.

> So to sum up: LLDB uniques types by decl file + decl line + byte size + fully qualified typename and that is failing because the decl files are different for these two types from the debug infos point of view. And these types could actually differ since they come from different files and we need to allow this so that we can display these types.

I'm slightly confused: can't we ask Clang to tell us if the two types
are structurally equivalent? Is this some short-cut? We need to
account for symlinks then, it seems.

Thanks!

Ram


More information about the lldb-dev mailing list