Re: [lldb-dev] Slow expression evaluation (ASTImporter is too eager?)

2019-11-14 Thread Gábor Márton via lldb-dev
Hi Jaroslav,

Thank you for digging into this. I think it may be possible to not eagerly
import a RecordDecl.  Perhaps we could control that from
clang::ASTNodeImporter::VisitPointerType and instead of a full import we
could just do a minimal import for the PointeeType always. Similarly to
references.
But I am not sure about whether we would know during a subsequent import
(where the full type is really needed) that the type had been minimally
imported before. This requires some more investigation, I'll come back to
you what I find, but it will take some time as this week is quite busy for
me.

Gabor

On Tue, Nov 12, 2019 at 11:14 AM Jaroslav Sevcik  wrote:

>
> Hi,
>
> thanks for the feedback, I did some more investigation and now I understand
> a bit better where the LayoutRecordType calls are coming from. They are
> initiated by
> Clang's code generation for types, which insists on generating full LLVM
> types
> for any complete RecordDecl (see
>
> https://github.com/llvm-mirror/clang/blob/65acf43270ea2894dffa0d0b292b92402f80c8cb/lib/CodeGen/CodeGenTypes.cpp#L752
> ,
> the bailout for incomplete record decls is at
>
> https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CodeGenTypes.cpp#L729
> ).
> Ideally, clang would only emit forward declarations for any type that is
> only
> used as a pointer, but that is not the case at the moment. It is not quite
> clear
> what else we could do on the lldb side to prevent clang from emitting
> types for all
> those structs. At the end of this email, I am pasting a stack trace that
> illustrates
> the recursive emit for a pointer-chain of structs.
>
> There is also one additional problem with importing base classes. This one
> is perhaps
> more related to AST importer. Again this is best illustrated with an
> example.
>
> struct F1 { int f1 = 30; };
> struct F0 { int f0 = 31; };
>
> struct B0 {
>   F0 b0f;
> };
>
> struct C0 : B0 {
> };
>
> struct B1 {
>   F1 b1f;
>   int f(C0* c0);
> };
>
> struct C1 : B1 {};
> struct C2 { int x = 4; C1* c1 = 0; };
>
> int main() {
>   C0 c0;
>   C1 c1;
>   C2 c2;
>
>   return 0;  // break here
> }
>
> If we evaluate c2.x in lldb after evaluating c1 and c0, the AST importer
> unnecessarily imports all the classes in this file. The main reason for
> this is
> that the import for structs needs to set the DefaultedDestructorIsConstexpr
> bit, which is computed by looking at destructors of base classes. Looking
> at
> the destructors triggers completion and import of the base classes, which
> in
> turn might trigger more imports of base classes. In the example above,
> importing C1 will cause completion and import of B1, which in turn causes
> import of C0, and recursively completion and import of B0. Below is a
> stack trace showing import of field F0::f0 from evaluation of c2.x. The
> stack traces going through the
> VisitRecordDecl-->ImportDefinition-->setBases path appear to be very hot
> in the workloads we see (debugging large codebases). Below is a stack
> trace that illustrates visiting F0::f0 from the evaluation of c2.x.  The
> question is what is the right place to break this long chain of imports.
> Ideally, we would not have to import fields of C1 or B1 when evaluating
> c2.x. Any ideas?
>
> Stack trace visiting F0::f0 from eval of c2.x, I have tried to highlight
> what is imported/completed where.
>
> clang::ASTNodeImporter::VisitFieldDecl;; Visit F0::f0
> clang::declvisitor::Base<...>::Visit
> clang::ASTImporter::ImportImpl
> lldb_private::ClangASTImporter::ASTImporterDelegate::ImportImpl
> clang::ASTImporter::Import
> lldb_private::ClangASTImporter::CopyDecl
> lldb_private::ClangASTSource::CopyDecl
> lldb_private::ClangASTSource::FindExternalLexicalDecls
> lldb_private::ClangASTSource::ClangASTSourceProxy::FindExternalLexicalDecls
> clang::ExternalASTSource::FindExternalLexicalDecls
> clang::DeclContext::LoadLexicalDeclsFromExternalStorage const
> clang::DeclContext::buildLookup   ;; lookup destructor
> of B0
> clang::DeclContext::lookup const
> clang::CXXRecordDecl::getDestructor const
> clang::CXXRecordDecl::hasConstexprDestructor const
> clang::CXXRecordDecl::addedClassSubobject
> clang::CXXRecordDecl::addedMember
> clang::DeclContext::addHiddenDecl
> clang::DeclContext::addDeclInternal
> clang::ASTNodeImporter::VisitFieldDecl;; visit B0::b0f
> clang::declvisitor::Base<...>::Visit
> clang::ASTImporter::ImportImpl
> lldb_private::ClangASTImporter::ASTImporterDelegate::ImportImpl
> clang::ASTImporter::Import
> lldb_private::ClangASTImporter::CopyDecl
> lldb_private::ClangASTSource::CopyDecl
> lldb_private::ClangASTSource::FindExternalLexicalDecls
> lldb_private::ClangASTSource::ClangASTSourceProxy::FindExternalLexicalDecls
> clang::RecordDecl::LoadFieldsFromExternalStorage const
> clang::RecordDecl::field_begin const
> clang::RecordDecl::field_empty const  ;; fields of B0
> clang::CXXRecordDecl::setBases
> clang::ASTNodeImporter::ImportDefi

Re: [lldb-dev] Slow expression evaluation (ASTImporter is too eager?)

2019-11-14 Thread Jaroslav Sevcik via lldb-dev
Hi Gabor,

I was thinking about a different idea: perhaps we could try to track on
lldb side which recorddecls were requested to be completed during a
particular parsing session and only import full definitions if they were
requested in this session. If completion was not requested in this session,
we would only import forward declaration (even if we already happen to have
full definition). Just like you, I have other things to attend to, so it
might take some time to prototype that.

I will think about your idea, it is not quite clear to me yet how it solves
either of the problems. In the codegen case, it seems to be clang that
walks through pointers. In the base class case we already import minimally
(I think), but even minimal import causes full import of base classes
(perhaps the const destructor check could only import the destructor,
though).

Thanks, Jaro

On Thu, Nov 14, 2019 at 11:14 AM Gábor Márton 
wrote:

> Hi Jaroslav,
>
> Thank you for digging into this. I think it may be possible to not eagerly
> import a RecordDecl.  Perhaps we could control that from
> clang::ASTNodeImporter::VisitPointerType and instead of a full import we
> could just do a minimal import for the PointeeType always. Similarly to
> references.
> But I am not sure about whether we would know during a subsequent import
> (where the full type is really needed) that the type had been minimally
> imported before. This requires some more investigation, I'll come back to
> you what I find, but it will take some time as this week is quite busy for
> me.
>
> Gabor
>
> On Tue, Nov 12, 2019 at 11:14 AM Jaroslav Sevcik  wrote:
>
>>
>> Hi,
>>
>> thanks for the feedback, I did some more investigation and now I
>> understand
>> a bit better where the LayoutRecordType calls are coming from. They are
>> initiated by
>> Clang's code generation for types, which insists on generating full LLVM
>> types
>> for any complete RecordDecl (see
>>
>> https://github.com/llvm-mirror/clang/blob/65acf43270ea2894dffa0d0b292b92402f80c8cb/lib/CodeGen/CodeGenTypes.cpp#L752
>> ,
>> the bailout for incomplete record decls is at
>>
>> https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CodeGenTypes.cpp#L729
>> ).
>> Ideally, clang would only emit forward declarations for any type that is
>> only
>> used as a pointer, but that is not the case at the moment. It is not
>> quite clear
>> what else we could do on the lldb side to prevent clang from emitting
>> types for all
>> those structs. At the end of this email, I am pasting a stack trace that
>> illustrates
>> the recursive emit for a pointer-chain of structs.
>>
>> There is also one additional problem with importing base classes. This
>> one is perhaps
>> more related to AST importer. Again this is best illustrated with an
>> example.
>>
>> struct F1 { int f1 = 30; };
>> struct F0 { int f0 = 31; };
>>
>> struct B0 {
>>   F0 b0f;
>> };
>>
>> struct C0 : B0 {
>> };
>>
>> struct B1 {
>>   F1 b1f;
>>   int f(C0* c0);
>> };
>>
>> struct C1 : B1 {};
>> struct C2 { int x = 4; C1* c1 = 0; };
>>
>> int main() {
>>   C0 c0;
>>   C1 c1;
>>   C2 c2;
>>
>>   return 0;  // break here
>> }
>>
>> If we evaluate c2.x in lldb after evaluating c1 and c0, the AST importer
>> unnecessarily imports all the classes in this file. The main reason for
>> this is
>> that the import for structs needs to set the
>> DefaultedDestructorIsConstexpr
>> bit, which is computed by looking at destructors of base classes. Looking
>> at
>> the destructors triggers completion and import of the base classes, which
>> in
>> turn might trigger more imports of base classes. In the example above,
>> importing C1 will cause completion and import of B1, which in turn causes
>> import of C0, and recursively completion and import of B0. Below is a
>> stack trace showing import of field F0::f0 from evaluation of c2.x. The
>> stack traces going through the
>> VisitRecordDecl-->ImportDefinition-->setBases path appear to be very hot
>> in the workloads we see (debugging large codebases). Below is a stack
>> trace that illustrates visiting F0::f0 from the evaluation of c2.x.  The
>> question is what is the right place to break this long chain of imports.
>> Ideally, we would not have to import fields of C1 or B1 when evaluating
>> c2.x. Any ideas?
>>
>> Stack trace visiting F0::f0 from eval of c2.x, I have tried to highlight
>> what is imported/completed where.
>>
>> clang::ASTNodeImporter::VisitFieldDecl;; Visit F0::f0
>> clang::declvisitor::Base<...>::Visit
>> clang::ASTImporter::ImportImpl
>> lldb_private::ClangASTImporter::ASTImporterDelegate::ImportImpl
>> clang::ASTImporter::Import
>> lldb_private::ClangASTImporter::CopyDecl
>> lldb_private::ClangASTSource::CopyDecl
>> lldb_private::ClangASTSource::FindExternalLexicalDecls
>>
>> lldb_private::ClangASTSource::ClangASTSourceProxy::FindExternalLexicalDecls
>> clang::ExternalASTSource::FindExternalLexicalDecls
>> clang::DeclContext::LoadLexicalDeclsFromExternalStorage const
>> cla

Re: [lldb-dev] Slow expression evaluation (ASTImporter is too eager?)

2019-11-14 Thread Gábor Márton via lldb-dev
Ok, sounds good.

> In the base class case we already import minimally (I think), but even
minimal import causes full import
This is deliberate. During construction of ASTImporter the minimal import
flag is set. And then when ASTImporter::ImportDefinition is called, it will
do a full import, even though minimal import is set. Otherwise we would not
be able to get a full type for LLDB.

> In the codegen case, it seems to be clang that walks through pointers.
Yes, you are right, my idea probably would not solve that problem. But the
base class related problem may be handled with that because the stack trace
you sent does include clang::ASTNodeImporter::VisitPointerType. I will
elaborate the idea once I found that feasible.

Gabor

On Thu, Nov 14, 2019 at 11:49 AM Jaroslav Sevcik  wrote:

> Hi Gabor,
>
> I was thinking about a different idea: perhaps we could try to track on
> lldb side which recorddecls were requested to be completed during a
> particular parsing session and only import full definitions if they were
> requested in this session. If completion was not requested in this session,
> we would only import forward declaration (even if we already happen to have
> full definition). Just like you, I have other things to attend to, so it
> might take some time to prototype that.
>
> I will think about your idea, it is not quite clear to me yet how it
> solves either of the problems. In the codegen case, it seems to be clang
> that walks through pointers. In the base class case we already import
> minimally (I think), but even minimal import causes full import of base
> classes (perhaps the const destructor check could only import the
> destructor, though).
>
> Thanks, Jaro
>
> On Thu, Nov 14, 2019 at 11:14 AM Gábor Márton 
> wrote:
>
>> Hi Jaroslav,
>>
>> Thank you for digging into this. I think it may be possible to not
>> eagerly import a RecordDecl.  Perhaps we could control that from
>> clang::ASTNodeImporter::VisitPointerType and instead of a full import we
>> could just do a minimal import for the PointeeType always. Similarly to
>> references.
>> But I am not sure about whether we would know during a subsequent import
>> (where the full type is really needed) that the type had been minimally
>> imported before. This requires some more investigation, I'll come back to
>> you what I find, but it will take some time as this week is quite busy for
>> me.
>>
>> Gabor
>>
>> On Tue, Nov 12, 2019 at 11:14 AM Jaroslav Sevcik 
>> wrote:
>>
>>>
>>> Hi,
>>>
>>> thanks for the feedback, I did some more investigation and now I
>>> understand
>>> a bit better where the LayoutRecordType calls are coming from. They are
>>> initiated by
>>> Clang's code generation for types, which insists on generating full LLVM
>>> types
>>> for any complete RecordDecl (see
>>>
>>> https://github.com/llvm-mirror/clang/blob/65acf43270ea2894dffa0d0b292b92402f80c8cb/lib/CodeGen/CodeGenTypes.cpp#L752
>>> ,
>>> the bailout for incomplete record decls is at
>>>
>>> https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CodeGenTypes.cpp#L729
>>> ).
>>> Ideally, clang would only emit forward declarations for any type that is
>>> only
>>> used as a pointer, but that is not the case at the moment. It is not
>>> quite clear
>>> what else we could do on the lldb side to prevent clang from emitting
>>> types for all
>>> those structs. At the end of this email, I am pasting a stack trace that
>>> illustrates
>>> the recursive emit for a pointer-chain of structs.
>>>
>>> There is also one additional problem with importing base classes. This
>>> one is perhaps
>>> more related to AST importer. Again this is best illustrated with an
>>> example.
>>>
>>> struct F1 { int f1 = 30; };
>>> struct F0 { int f0 = 31; };
>>>
>>> struct B0 {
>>>   F0 b0f;
>>> };
>>>
>>> struct C0 : B0 {
>>> };
>>>
>>> struct B1 {
>>>   F1 b1f;
>>>   int f(C0* c0);
>>> };
>>>
>>> struct C1 : B1 {};
>>> struct C2 { int x = 4; C1* c1 = 0; };
>>>
>>> int main() {
>>>   C0 c0;
>>>   C1 c1;
>>>   C2 c2;
>>>
>>>   return 0;  // break here
>>> }
>>>
>>> If we evaluate c2.x in lldb after evaluating c1 and c0, the AST importer
>>> unnecessarily imports all the classes in this file. The main reason for
>>> this is
>>> that the import for structs needs to set the
>>> DefaultedDestructorIsConstexpr
>>> bit, which is computed by looking at destructors of base classes.
>>> Looking at
>>> the destructors triggers completion and import of the base classes,
>>> which in
>>> turn might trigger more imports of base classes. In the example above,
>>> importing C1 will cause completion and import of B1, which in turn causes
>>> import of C0, and recursively completion and import of B0. Below is a
>>> stack trace showing import of field F0::f0 from evaluation of c2.x. The
>>> stack traces going through the
>>> VisitRecordDecl-->ImportDefinition-->setBases path appear to be very hot
>>> in the workloads we see (debugging large codebases). Below is a stack
>>> trace that illustrates visi

Re: [lldb-dev] Segfault using the lldb python module with a non-Xcode python binary

2019-11-14 Thread Jonas Devlieghere via lldb-dev
Hey António,

If I understand correctly, you're trying to mix between two versions
of the Python interpreter and library. That's not something that's
supported and has always been an issue. Internally we get the
occasional bug report where somebody install python via homebrew or
python.org and the corresponding interpreter ends up first in their
path because /usr/local/bin comes before /usr/bin. The same is true if
you build your own LLDB, if you link against Homebrew's Python3 dylib,
you need to use the Homebrew interpreter. In CMake we try really hard
to ensure those two are in sync for when we run the (Python) test
suite.

On macOS Catalina, there's a shim for python3 in /usr/bin/ that will
launch the interpreter from Xcode, which matches what the LLDB from
Xcode is linked against.

Given that this is an issue that comes up frequently, I'm going to add
a bit of documentation about this on the LLDB website.

Best,
Jonas

On Wed, Nov 13, 2019 at 10:53 PM António Afonso via lldb-dev
 wrote:
>
> I'm building lldb with python3 support by using the framework that is shipped 
> with the latest versions of Xcode.
>
> I'm able to build and run lldb just fine but if I try to use the lldb python 
> module on a python binary that is not the one from Xcode it segfaults when 
> creating the module. I then tried with the stock lldb from Xcode and found 
> the exact same issue ☹. I don’t think this was a problem before?
>
>
>
> I'm not sure why this happens and I wasn't able to debug the issue. I've 
> already tried with a binary that has the exact same version of python but 
> still the same problem:
>
>
>
> Works fine with the Xcode binary:
>
> $ PYTHONPATH=`lldb -P` 
> /Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/bin/python3
>
> Python 3.7.3 (default, Sep 18 2019, 14:29:06)
>
> [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
>
> Type "help", "copyright", "credits" or "license" for more information.
>
> >>> import lldb
>
> >>>
>
>
>
> Fails with any other:
>
> $ PYTHONPATH=`lldb -P` /Users/aadsm/.pyenv/versions/3.7.3/bin/python
>
> Python 3.7.3 (default, Nov 12 2019, 23:19:54)
>
> [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
>
> Type "help", "copyright", "credits" or "license" for more information.
>
> >>> import lldb
>
> Segmentation fault: 11
>
>
>
> I attached lldb to see where it was failing and it's right after liblldb is 
> loaded and python is trying to create the module itself, in the 
> PyModule_Create2 function 
> (https://github.com/python/cpython/blob/master/Objects/moduleobject.c#L173-L179).
>
> The disassembly shows:
>
>
>
> Process 89097 stopped
>
> * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS 
> (code=1, address=0x10)
>
> frame #0: 0x00010f4cae5b Python3`PyModule_Create2 + 27
>
> Python3`PyModule_Create2:
>
> ->  0x10f4cae5b <+27>: movq   0x10(%rax), %rdi
>
> 0x10f4cae5f <+31>: callq  0x10f5823b0   ; 
> _PyImport_IsInitialized
>
> 0x10f4cae64 <+36>: testl  %eax, %eax
>
> 0x10f4cae66 <+38>: je 0x10f4cae77   ; <+55>
>
> Target 0: (Python) stopped.
>
> (lldb) dis
>
> Python3`PyModule_Create2:
>
> 0x10f4cae40 <+0>:  pushq  %rbp
>
> 0x10f4cae41 <+1>:  movq   %rsp, %rbp
>
> 0x10f4cae44 <+4>:  pushq  %r14
>
> 0x10f4cae46 <+6>:  pushq  %rbx
>
> 0x10f4cae47 <+7>:  movl   %esi, %r14d
>
> 0x10f4cae4a <+10>: movq   %rdi, %rbx
>
> 0x10f4cae4d <+13>: leaq   0x2226ac(%rip), %rax  ; _PyRuntime
>
> 0x10f4cae54 <+20>: movq   0x5a0(%rax), %rax
>
> ->  0x10f4cae5b <+27>: movq   0x10(%rax), %rdi
>
> 0x10f4cae5f <+31>: callq  0x10f5823b0   ; 
> _PyImport_IsInitialized
>
> 0x10f4cae64 <+36>: testl  %eax, %eax
>
> 0x10f4cae66 <+38>: je 0x10f4cae77   ; <+55>
>
> 0x10f4cae68 <+40>: movq   %rbx, %rdi
>
> 0x10f4cae6b <+43>: movl   %r14d, %esi
>
> 0x10f4cae6e <+46>: popq   %rbx
>
> 0x10f4cae6f <+47>: popq   %r14
>
> 0x10f4cae71 <+49>: popq   %rbp
>
> 0x10f4cae72 <+50>: jmp0x10f4cae90   ; 
> _PyModule_CreateInitialized
>
> 0x10f4cae77 <+55>: leaq   0x14f111(%rip), %rdi  ; "Python import 
> machinery not initialized"
>
> 0x10f4cae7e <+62>: callq  0x10f593d40   ; Py_FatalError
>
> 0x10f4cae83 <+67>: nopw   %cs:(%rax,%rax)
>
> 0x10f4cae8d <+77>: nopl   (%rax)
>
>
>
> Not really sure how to debug this besides trying to build my own version of 
> python and see if I can repro (I don't have this issue on linux). I’ve also 
> checked the sys.abiflags and both binaries have the same ones.
>
> Has anyone experienced this before or has any pointers to debug it?
>
> - Afonso
>
> --
> Best regards,
> António Afonso
> ___
> lldb-dev mailing list
> lldb-dev@lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
___
lldb-dev mailing list
lldb-dev@lists.llvm.org
https://lists

Re: [lldb-dev] Segfault using the lldb python module with a non-Xcode python binary

2019-11-14 Thread Jonas Devlieghere via lldb-dev
I've put up a patch to extend the documentation: https://reviews.llvm.org/D70252

Please have a look let me know if you have any comments or suggestions!

On Thu, Nov 14, 2019 at 9:17 AM Jonas Devlieghere  wrote:
>
> Hey António,
>
> If I understand correctly, you're trying to mix between two versions
> of the Python interpreter and library. That's not something that's
> supported and has always been an issue. Internally we get the
> occasional bug report where somebody install python via homebrew or
> python.org and the corresponding interpreter ends up first in their
> path because /usr/local/bin comes before /usr/bin. The same is true if
> you build your own LLDB, if you link against Homebrew's Python3 dylib,
> you need to use the Homebrew interpreter. In CMake we try really hard
> to ensure those two are in sync for when we run the (Python) test
> suite.
>
> On macOS Catalina, there's a shim for python3 in /usr/bin/ that will
> launch the interpreter from Xcode, which matches what the LLDB from
> Xcode is linked against.
>
> Given that this is an issue that comes up frequently, I'm going to add
> a bit of documentation about this on the LLDB website.
>
> Best,
> Jonas
>
> On Wed, Nov 13, 2019 at 10:53 PM António Afonso via lldb-dev
>  wrote:
> >
> > I'm building lldb with python3 support by using the framework that is 
> > shipped with the latest versions of Xcode.
> >
> > I'm able to build and run lldb just fine but if I try to use the lldb 
> > python module on a python binary that is not the one from Xcode it 
> > segfaults when creating the module. I then tried with the stock lldb from 
> > Xcode and found the exact same issue ☹. I don’t think this was a problem 
> > before?
> >
> >
> >
> > I'm not sure why this happens and I wasn't able to debug the issue. I've 
> > already tried with a binary that has the exact same version of python but 
> > still the same problem:
> >
> >
> >
> > Works fine with the Xcode binary:
> >
> > $ PYTHONPATH=`lldb -P` 
> > /Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/bin/python3
> >
> > Python 3.7.3 (default, Sep 18 2019, 14:29:06)
> >
> > [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
> >
> > Type "help", "copyright", "credits" or "license" for more information.
> >
> > >>> import lldb
> >
> > >>>
> >
> >
> >
> > Fails with any other:
> >
> > $ PYTHONPATH=`lldb -P` /Users/aadsm/.pyenv/versions/3.7.3/bin/python
> >
> > Python 3.7.3 (default, Nov 12 2019, 23:19:54)
> >
> > [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
> >
> > Type "help", "copyright", "credits" or "license" for more information.
> >
> > >>> import lldb
> >
> > Segmentation fault: 11
> >
> >
> >
> > I attached lldb to see where it was failing and it's right after liblldb is 
> > loaded and python is trying to create the module itself, in the 
> > PyModule_Create2 function 
> > (https://github.com/python/cpython/blob/master/Objects/moduleobject.c#L173-L179).
> >
> > The disassembly shows:
> >
> >
> >
> > Process 89097 stopped
> >
> > * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS 
> > (code=1, address=0x10)
> >
> > frame #0: 0x00010f4cae5b Python3`PyModule_Create2 + 27
> >
> > Python3`PyModule_Create2:
> >
> > ->  0x10f4cae5b <+27>: movq   0x10(%rax), %rdi
> >
> > 0x10f4cae5f <+31>: callq  0x10f5823b0   ; 
> > _PyImport_IsInitialized
> >
> > 0x10f4cae64 <+36>: testl  %eax, %eax
> >
> > 0x10f4cae66 <+38>: je 0x10f4cae77   ; <+55>
> >
> > Target 0: (Python) stopped.
> >
> > (lldb) dis
> >
> > Python3`PyModule_Create2:
> >
> > 0x10f4cae40 <+0>:  pushq  %rbp
> >
> > 0x10f4cae41 <+1>:  movq   %rsp, %rbp
> >
> > 0x10f4cae44 <+4>:  pushq  %r14
> >
> > 0x10f4cae46 <+6>:  pushq  %rbx
> >
> > 0x10f4cae47 <+7>:  movl   %esi, %r14d
> >
> > 0x10f4cae4a <+10>: movq   %rdi, %rbx
> >
> > 0x10f4cae4d <+13>: leaq   0x2226ac(%rip), %rax  ; _PyRuntime
> >
> > 0x10f4cae54 <+20>: movq   0x5a0(%rax), %rax
> >
> > ->  0x10f4cae5b <+27>: movq   0x10(%rax), %rdi
> >
> > 0x10f4cae5f <+31>: callq  0x10f5823b0   ; 
> > _PyImport_IsInitialized
> >
> > 0x10f4cae64 <+36>: testl  %eax, %eax
> >
> > 0x10f4cae66 <+38>: je 0x10f4cae77   ; <+55>
> >
> > 0x10f4cae68 <+40>: movq   %rbx, %rdi
> >
> > 0x10f4cae6b <+43>: movl   %r14d, %esi
> >
> > 0x10f4cae6e <+46>: popq   %rbx
> >
> > 0x10f4cae6f <+47>: popq   %r14
> >
> > 0x10f4cae71 <+49>: popq   %rbp
> >
> > 0x10f4cae72 <+50>: jmp0x10f4cae90   ; 
> > _PyModule_CreateInitialized
> >
> > 0x10f4cae77 <+55>: leaq   0x14f111(%rip), %rdi  ; "Python import 
> > machinery not initialized"
> >
> > 0x10f4cae7e <+62>: callq  0x10f593d40   ; Py_FatalError
> >
> > 0x10f4cae83 <+67>: nopw   %cs:(%rax,%rax)
> >
> > 0x10f4cae8d <+77>: nopl   (%rax)
> >
> >
> >
> > Not really sure how to debug this besides trying to build my own version of 
> >