diff options
Diffstat (limited to 'scripts/Python')
| -rw-r--r-- | scripts/Python/Makefile | 15 | ||||
| -rw-r--r-- | scripts/Python/android/host_art_bt.py | 192 | ||||
| -rwxr-xr-x | scripts/Python/finish-swig-Python-LLDB.sh | 310 | ||||
| -rw-r--r-- | scripts/Python/finishSwigPythonLLDB.py | 793 | ||||
| -rw-r--r-- | scripts/Python/modify-python-lldb.py | 486 | ||||
| -rw-r--r-- | scripts/Python/modules/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | scripts/Python/modules/Makefile | 20 | ||||
| -rw-r--r-- | scripts/Python/modules/readline/CMakeLists.txt | 25 | ||||
| -rw-r--r-- | scripts/Python/modules/readline/Makefile | 100 | ||||
| -rw-r--r-- | scripts/Python/modules/readline/readline.cpp | 76 | ||||
| -rw-r--r-- | scripts/Python/prepare_binding_Python.py | 435 | ||||
| -rw-r--r-- | scripts/Python/python-extensions.swig | 1087 | ||||
| -rw-r--r-- | scripts/Python/python-swigsafecast.swig | 142 | ||||
| -rw-r--r-- | scripts/Python/python-typemaps.swig | 601 | ||||
| -rw-r--r-- | scripts/Python/python-wrapper.swig | 936 | ||||
| -rwxr-xr-x | scripts/Python/remote-build.py | 300 | ||||
| -rw-r--r-- | scripts/Python/use_lldb_suite.py | 22 | 
17 files changed, 5551 insertions, 0 deletions
diff --git a/scripts/Python/Makefile b/scripts/Python/Makefile new file mode 100644 index 000000000000..ad6c0af442b4 --- /dev/null +++ b/scripts/Python/Makefile @@ -0,0 +1,15 @@ +##===- scripts/Python/Makefile------------------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../.. +include $(LLDB_LEVEL)/../../Makefile.config + +DIRS := modules + +include $(LLDB_LEVEL)/Makefile diff --git a/scripts/Python/android/host_art_bt.py b/scripts/Python/android/host_art_bt.py new file mode 100644 index 000000000000..0893662869f2 --- /dev/null +++ b/scripts/Python/android/host_art_bt.py @@ -0,0 +1,192 @@ +# Usage: +#   art/test/run-test --host --gdb [--64] [--interpreter] 004-JniTest +#   'b Java_Main_shortMethod' +#   'r' +#   'command script import host_art_bt.py' +#   'host_art_bt' + +import sys +import re + +import lldb + +def host_art_bt(debugger, command, result, internal_dict): +  prettified_frames = [] +  lldb_frame_index = 0 +  art_frame_index = 0 +  target = debugger.GetSelectedTarget() +  process = target.GetProcess() +  thread = process.GetSelectedThread() +  while lldb_frame_index < thread.GetNumFrames(): +    frame = thread.GetFrameAtIndex(lldb_frame_index) +    if frame.GetModule() and re.match(r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()): +      # Compiled Java frame + +      # Get function/filename/lineno from symbol context +      symbol = frame.GetSymbol() +      if not symbol: +        print 'No symbol info for compiled Java frame: ', frame +        sys.exit(1) +      line_entry = frame.GetLineEntry() +      prettified_frames.append({ +        'function': symbol.GetName(), +        'file'    : str(line_entry.GetFileSpec()) if line_entry else None, +        'line'    : line_entry.GetLine() if line_entry else -1 +      }) + +      # Skip art frames +      while True: +        art_stack_visitor = frame.EvaluateExpression("""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" + str(art_frame_index) + """); visitor.WalkStack(true); visitor""") +        art_method = frame.EvaluateExpression(art_stack_visitor.GetName() + """.GetMethod()""") +        if art_method.GetValueAsUnsigned() != 0: +          art_method_name = frame.EvaluateExpression("""art::PrettyMethod(""" + art_method.GetName() + """, true)""") +          art_method_name_data = frame.EvaluateExpression(art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() +          art_method_name_size = frame.EvaluateExpression(art_method_name.GetName() + """.length()""").GetValueAsUnsigned() +          error = lldb.SBError() +          art_method_name = process.ReadCStringFromMemory(art_method_name_data, art_method_name_size + 1, error) +          if not error.Success: +            print 'Failed to read method name' +            sys.exit(1) +          if art_method_name != symbol.GetName(): +            print 'Function names in native symbol and art runtime stack do not match: ', symbol.GetName(), ' != ', art_method_name +          art_frame_index = art_frame_index + 1 +          break +        art_frame_index = art_frame_index + 1 + +      # Skip native frames +      lldb_frame_index = lldb_frame_index + 1 +      if lldb_frame_index < thread.GetNumFrames(): +        frame = thread.GetFrameAtIndex(lldb_frame_index) +        if frame.GetModule() and re.match(r'JIT\(.*?\)', frame.GetModule().GetFileSpec().GetFilename()): +          # Another compile Java frame +          # Don't skip; leave it to the next iteration +          continue +        elif frame.GetSymbol() and (frame.GetSymbol().GetName() == 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'): +          # art_quick_invoke_stub / art_quick_invoke_static_stub +          # Skip until we get past the next ArtMethod::Invoke() +          while True: +            lldb_frame_index = lldb_frame_index + 1 +            if lldb_frame_index >= thread.GetNumFrames(): +              print 'ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub' +              sys.exit(1) +            frame = thread.GetFrameAtIndex(lldb_frame_index) +            if frame.GetSymbol() and frame.GetSymbol().GetName() == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': +              lldb_frame_index = lldb_frame_index + 1 +              break +        else: +          print 'Invalid frame below compiled Java frame: ', frame +    elif frame.GetSymbol() and frame.GetSymbol().GetName() == 'art_quick_generic_jni_trampoline': +      # Interpreted JNI frame for x86_64 + +      # Skip art frames +      while True: +        art_stack_visitor = frame.EvaluateExpression("""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" + str(art_frame_index) + """); visitor.WalkStack(true); visitor""") +        art_method = frame.EvaluateExpression(art_stack_visitor.GetName() + """.GetMethod()""") +        if art_method.GetValueAsUnsigned() != 0: +          # Get function/filename/lineno from ART runtime +          art_method_name = frame.EvaluateExpression("""art::PrettyMethod(""" + art_method.GetName() + """, true)""") +          art_method_name_data = frame.EvaluateExpression(art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() +          art_method_name_size = frame.EvaluateExpression(art_method_name.GetName() + """.length()""").GetValueAsUnsigned() +          error = lldb.SBError() +          function = process.ReadCStringFromMemory(art_method_name_data, art_method_name_size + 1, error) + +          prettified_frames.append({ +            'function': function, +            'file'    : None, +            'line'    : -1 +          }) + +          art_frame_index = art_frame_index + 1 +          break +        art_frame_index = art_frame_index + 1 + +      # Skip native frames +      lldb_frame_index = lldb_frame_index + 1 +      if lldb_frame_index < thread.GetNumFrames(): +        frame = thread.GetFrameAtIndex(lldb_frame_index) +        if frame.GetSymbol() and (frame.GetSymbol().GetName() == 'art_quick_invoke_stub' or frame.GetSymbol().GetName() == 'art_quick_invoke_static_stub'): +          # art_quick_invoke_stub / art_quick_invoke_static_stub +          # Skip until we get past the next ArtMethod::Invoke() +          while True: +            lldb_frame_index = lldb_frame_index + 1 +            if lldb_frame_index >= thread.GetNumFrames(): +              print 'ArtMethod::Invoke not found below art_quick_invoke_stub/art_quick_invoke_static_stub' +              sys.exit(1) +            frame = thread.GetFrameAtIndex(lldb_frame_index) +            if frame.GetSymbol() and frame.GetSymbol().GetName() == 'art::mirror::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)': +              lldb_frame_index = lldb_frame_index + 1 +              break +        else: +          print 'Invalid frame below compiled Java frame: ', frame +    elif frame.GetSymbol() and re.search(r'art::interpreter::', frame.GetSymbol().GetName()): +      # Interpreted Java frame + +      while True: +        lldb_frame_index = lldb_frame_index + 1 +        if lldb_frame_index >= thread.GetNumFrames(): +          print 'art::interpreter::Execute not found in interpreter frame' +          sys.exit(1) +        frame = thread.GetFrameAtIndex(lldb_frame_index) +        if frame.GetSymbol() and frame.GetSymbol().GetName() == 'art::interpreter::Execute(art::Thread*, art::MethodHelper&, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue)': +          break + +      # Skip art frames +      while True: +        art_stack_visitor = frame.EvaluateExpression("""struct GetStackVisitor : public StackVisitor { GetStackVisitor(int depth_) : StackVisitor(Thread::Current(), NULL), depth(depth_) {} bool VisitFrame() { if (cur_depth_ == depth) { return false; } else { return true; } } int depth; }; GetStackVisitor visitor(""" + str(art_frame_index) + """); visitor.WalkStack(true); visitor""") +        art_method = frame.EvaluateExpression(art_stack_visitor.GetName() + """.GetMethod()""") +        if art_method.GetValueAsUnsigned() != 0: +          # Get function/filename/lineno from ART runtime +          art_method_name = frame.EvaluateExpression("""art::PrettyMethod(""" + art_method.GetName() + """, true)""") +          art_method_name_data = frame.EvaluateExpression(art_method_name.GetName() + """.c_str()""").GetValueAsUnsigned() +          art_method_name_size = frame.EvaluateExpression(art_method_name.GetName() + """.length()""").GetValueAsUnsigned() +          error = lldb.SBError() +          function = process.ReadCStringFromMemory(art_method_name_data, art_method_name_size + 1, error) + +          line = frame.EvaluateExpression(art_stack_visitor.GetName() + """.GetMethod()->GetLineNumFromDexPC(""" + art_stack_visitor.GetName() + """.GetDexPc(true))""").GetValueAsUnsigned() +           +          file_name = frame.EvaluateExpression(art_method.GetName() + """->GetDeclaringClassSourceFile()""") +          file_name_data = file_name.GetValueAsUnsigned() +          file_name_size = frame.EvaluateExpression("""(size_t)strlen(""" + file_name.GetName() + """)""").GetValueAsUnsigned() +          error = lldb.SBError() +          file_name = process.ReadCStringFromMemory(file_name_data, file_name_size + 1, error) +          if not error.Success(): +            print 'Failed to read source file name' +            sys.exit(1) + +          prettified_frames.append({ +            'function': function, +            'file'    : file_name, +            'line'    : line +          }) + +          art_frame_index = art_frame_index + 1 +          break +        art_frame_index = art_frame_index + 1 + +      # Skip native frames +      while True: +        lldb_frame_index = lldb_frame_index + 1 +        if lldb_frame_index >= thread.GetNumFrames(): +          print 'Can not get past interpreter native frames' +          sys.exit(1) +        frame = thread.GetFrameAtIndex(lldb_frame_index) +        if frame.GetSymbol() and not re.search(r'art::interpreter::', frame.GetSymbol().GetName()): +          break +    else: +      # Other frames. Add them as-is. +      frame = thread.GetFrameAtIndex(lldb_frame_index) +      lldb_frame_index = lldb_frame_index + 1 +      if frame.GetModule(): +        module_name = frame.GetModule().GetFileSpec().GetFilename() +        if not module_name in ['libartd.so', 'dalvikvm32', 'dalvikvm64', 'libc.so.6']: +          prettified_frames.append({ +            'function': frame.GetSymbol().GetName() if frame.GetSymbol() else None, +            'file'    : str(frame.GetLineEntry().GetFileSpec()) if frame.GetLineEntry() else None, +            'line'    : frame.GetLineEntry().GetLine() if frame.GetLineEntry() else -1 +          }) + +  for prettified_frame in prettified_frames: +    print prettified_frame['function'], prettified_frame['file'], prettified_frame['line'] + +def __lldb_init_module(debugger, internal_dict): +    debugger.HandleCommand('command script add -f host_art_bt.host_art_bt host_art_bt') diff --git a/scripts/Python/finish-swig-Python-LLDB.sh b/scripts/Python/finish-swig-Python-LLDB.sh new file mode 100755 index 000000000000..92b99181c7cc --- /dev/null +++ b/scripts/Python/finish-swig-Python-LLDB.sh @@ -0,0 +1,310 @@ +#!/bin/sh + +# finish-swig-Python.sh +# +# For the Python script interpreter (external to liblldb) to be able to import +# and use the lldb module, there must be two files, lldb.py and _lldb.so, that +# it can find. lldb.py is generated by SWIG at the same time it generates the +# C++ file.  _lldb.so is actually a symlink file that points to the +# LLDB shared library/framework. +# +# The Python script interpreter needs to be able to automatically find +# these two files. On Darwin systems it searches in the LLDB.framework, as +# well as in all the normal Python search paths.  On non-Darwin systems +# these files will need to be put someplace where Python will find them. +# +# This shell script creates the _lldb.so symlink in the appropriate place, +# and copies the lldb.py (and embedded_interpreter.py) file to the correct +# directory. +# + +# SRC_ROOT is the root of the lldb source tree. +# TARGET_DIR is where the lldb framework/shared library gets put. +# CONFIG_BUILD_DIR is where the build-swig-Python-LLDB.sh  shell script +#           put the lldb.py file it was generated from running SWIG. +# PYTHON_INSTALL_DIR is where non-Darwin systems want to put the .py and .so +#           files so that Python can find them automatically. +# debug_flag (optional) determines whether or not this script outputs +#           additional information when running. + +SRC_ROOT=$1 +TARGET_DIR=$2 +CONFIG_BUILD_DIR=$3 +PYTHON_INSTALL_DIR=$4 +debug_flag=$5 +makefile_flag=$6 + +# If we don't want Python, then just do nothing here. +# Note, at present iOS doesn't have Python, so if you're building for iOS be sure to +# set LLDB_DISABLE_PYTHON to 1. + +if [ ! "$LLDB_DISABLE_PYTHON" = "1" ] ; then + +if [ -n "$debug_flag" -a "$debug_flag" = "-debug" ] +then +    Debug=1 +else +    Debug=0 +fi + +if [ -n "$makefile_flag" -a "$makefile_flag" = "-m" ] +then +    MakefileCalled=1 +else +    MakefileCalled=0 +fi + +OS_NAME=`uname -s` +PYTHON=${PYTHON_EXECUTABLE:-/usr/bin/env python} +PYTHON_VERSION=`${PYTHON} --version 2>&1 | sed -e 's,Python ,,' -e 's,[.][0-9],,2' -e 's,[a-z][a-z][0-9],,'` + + +if [ $Debug -eq 1 ] +then +    echo "The current OS is $OS_NAME" +    echo "The Python version is $PYTHON_VERSION" +fi + +if [ ${OS_NAME} = "Darwin" ] +then +    SOEXT=".dylib" +else +    SOEXT=".so" +fi + +# +#  Determine where to put the files. + +if [ $MakefileCalled -eq 0 ] +then +    # We are being built by Xcode, so all the lldb Python files can go +    # into the LLDB.framework/Resources/Python subdirectory. + +    if [ ! -d "${TARGET_DIR}/LLDB.framework" ] +    then +        echo "Error:  Unable to find LLDB.framework" >&2 +        exit 1 +    else +        if [ $Debug -eq 1 ] +        then +            echo "Found ${TARGET_DIR}/LLDB.framework." +        fi +    fi + +    # Make the Python directory in the framework if it doesn't already exist + +    framework_python_dir="${TARGET_DIR}/LLDB.framework/Resources/Python/lldb" +else +    # We are being built by LLVM, so use the PYTHON_INSTALL_DIR argument, +    # and append the python version directory to the end of it.  Depending on +    # the system other stuff may need to be put here as well. + +    if [ -n "${PYTHON_INSTALL_DIR}" ] +    then +        framework_python_dir=`${PYTHON} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True, False, \"${PYTHON_INSTALL_DIR}\");"`/lldb +    else +        framework_python_dir=`${PYTHON} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True, False);"`/lldb +    fi +fi + +[ -n "${CONFIG_BUILD_DIR}" ] || CONFIG_BUILD_DIR=${framework_python_dir} + +# +# Look for the directory in which to put the Python files;  if it does not +# already exist, attempt to make it. +# + +if [ $Debug -eq 1 ] +then +    echo "Python files will be put in ${framework_python_dir}" +fi + +python_dirs="${framework_python_dir}" + +for python_dir in $python_dirs +do +    if [ ! -d "${python_dir}" ] +    then +        if [ $Debug -eq 1 ] +        then +            echo "Making directory ${python_dir}" +        fi +        mkdir -p "${python_dir}" +    else +        if [ $Debug -eq 1 ] +        then +            echo "${python_dir} already exists." +        fi +    fi + +    if [ ! -d "${python_dir}" ] +    then +        echo "Error: Unable to find or create ${python_dir}" >&2 +        exit 1 +    fi +done + +# Make the symlink that the script bridge for Python will need in the +# Python framework directory + +if [ ! -L "${framework_python_dir}/_lldb.so" ] +then +    if [ $Debug -eq 1 ] +    then +        echo "Creating symlink for _lldb.so" +    fi +    cd "${framework_python_dir}" +    if [ $MakefileCalled -eq 0 ] +    then +        ln -s "../../../LLDB" _lldb.so +	else +        ln -s "../../../liblldb${SOEXT}" _lldb.so +    fi +else +    if [ $Debug -eq 1 ] +    then +        echo "${framework_python_dir}/_lldb.so already exists." +    fi +fi + +# Make symlink for darwin-debug on Darwin +if [ ${OS_NAME} = "Darwin" ] && [ $MakefileCalled -ne 0 ] +then +    # We are being built by CMake on Darwin + +    if [ ! -L "${framework_python_dir}/darwin-debug" ] +    then +        if [ $Debug -eq 1 ] +        then +            echo "Creating symlink for darwin-debug" +        fi +        cd "${framework_python_dir}" +        ln -s "../../../../bin/lldb-launcher" darwin-debug +    else +        if [ $Debug -eq 1 ] +        then +            echo "${framework_python_dir}/darwin-debug already exists." +        fi +    fi +fi + +# Make symlink for lldb-argdumper on any platform +if [ $MakefileCalled -ne 0 ] +then +    # We are being built by CMake + +    if [ ! -L "${framework_python_dir}/lldb-argdumper" ] +    then +        if [ $Debug -eq 1 ] +        then +            echo "Creating symlink for lldb-argdumper" +        fi +        cd "${framework_python_dir}" +        ln -s "../../../../bin/lldb-argdumper" lldb-argdumper +    else +        if [ $Debug -eq 1 ] +        then +            echo "${framework_python_dir}/lldb-argdumper already exists." +        fi +    fi +fi + +create_python_package () { +    package_dir="${framework_python_dir}$1" +    package_files="$2" +    package_name=`echo $1 | tr '/' '.'` +    package_name="lldb${package_name}" + +    if [ ! -d "${package_dir}" ] +    then +        mkdir -p "${package_dir}" +    fi + +    for package_file in $package_files +    do +        if [ -f "${package_file}" ] +        then +            cp "${package_file}" "${package_dir}" +            package_file_basename=$(basename "${package_file}") +        fi +    done + + +    # Create a packate init file if there wasn't one +    package_init_file="${package_dir}/__init__.py" +    if [ ! -f "${package_init_file}" ] +    then +        printf "__all__ = [" > "${package_init_file}" +        python_module_separator="" +        for package_file in $package_files +        do +            if [ -f "${package_file}" ] +            then +                package_file_basename=$(basename "${package_file}") +                printf "${python_module_separator}\"${package_file_basename%.*}\"" >> "${package_init_file}" +                python_module_separator=", " +            fi +        done +        echo "]" >> "${package_init_file}" +        echo "for x in __all__:" >> "${package_init_file}" +        echo "    __import__('${package_name}.'+x)" >> "${package_init_file}" +    fi + + +} + +# Copy the lldb.py file into the lldb package directory and rename to __init_.py +cp "${CONFIG_BUILD_DIR}/lldb.py" "${framework_python_dir}/__init__.py" + +# lldb +package_files="${SRC_ROOT}/source/Interpreter/embedded_interpreter.py" +create_python_package "" "${package_files}" + +# lldb/formatters/cpp +package_files="${SRC_ROOT}/examples/synthetic/gnu_libstdcpp.py +${SRC_ROOT}/examples/synthetic/libcxx.py" +create_python_package "/formatters/cpp" "${package_files}" + +# make an empty __init__.py in lldb/runtime +# this is required for Python to recognize lldb.runtime as a valid package +# (and hence, lldb.runtime.objc as a valid contained package) +create_python_package "/runtime" "" + +# lldb/formatters +# having these files copied here ensures that lldb/formatters is a valid package itself +package_files="${SRC_ROOT}/examples/summaries/cocoa/cache.py +${SRC_ROOT}/examples/summaries/cocoa/metrics.py +${SRC_ROOT}/examples/summaries/cocoa/attrib_fromdict.py +${SRC_ROOT}/examples/summaries/cocoa/Logger.py" +create_python_package "/formatters" "${package_files}" + +# lldb/utils +package_files="${SRC_ROOT}/examples/python/symbolication.py" +create_python_package "/utils" "${package_files}" + +if [ ${OS_NAME} = "Darwin" ] +then +    # lldb/macosx +    package_files="${SRC_ROOT}/examples/python/crashlog.py +    ${SRC_ROOT}/examples/darwin/heap_find/heap.py" +    create_python_package "/macosx" "${package_files}" + +    # lldb/diagnose +    package_files="${SRC_ROOT}/examples/python/diagnose_unwind.py +    ${SRC_ROOT}/examples/python/diagnose_nsstring.py" +    create_python_package "/diagnose" "${package_files}" + +    # Copy files needed by lldb/macosx/heap.py to build libheap.dylib +    heap_dir="${framework_python_dir}/macosx/heap" +    if [ ! -d "${heap_dir}" ] +    then +        mkdir -p "${heap_dir}" +        cp "${SRC_ROOT}/examples/darwin/heap_find/heap/heap_find.cpp" "${heap_dir}" +        cp "${SRC_ROOT}/examples/darwin/heap_find/heap/Makefile" "${heap_dir}" +    fi +fi + +fi + +exit 0 + diff --git a/scripts/Python/finishSwigPythonLLDB.py b/scripts/Python/finishSwigPythonLLDB.py new file mode 100644 index 000000000000..435cb88c20f0 --- /dev/null +++ b/scripts/Python/finishSwigPythonLLDB.py @@ -0,0 +1,793 @@ +""" Python SWIG post process script for each language + +    -------------------------------------------------------------------------- +    File:           finishSwigPythonLLDB.py + +    Overview:       Python script(s) to post process SWIG Python C++ Script +                    Bridge wrapper code on the Windows/LINUX/OSX platform. +                    The Python scripts are equivalent to the shell script (.sh) +                    files. +                    For the Python script interpreter (external to liblldb) to +                    be able to import and use the lldb module, there must be +                    two files, lldb.py and _lldb.so, that it can find. lldb.py +                    is generated by SWIG at the same time it generates the C++ +                    file.  _lldb.so is actually a symlink file that points to +                    the LLDB shared library/framework. +                    The Python script interpreter needs to be able to +                    automatically find these two files. On Darwin systems it +                    searches in the LLDB.framework, as well as in all the normal +                    Python search paths.  On non-Darwin systems these files will +                    need to be put some place where Python will find them. +                    This shell script creates the _lldb.so symlink in the +                    appropriate place, and copies the lldb.py (and +                    embedded_interpreter.py) file to the correct directory. + +    Gotchas:        Python debug complied pythonXX_d.lib is required for SWIG +                    to build correct LLDBWrapperPython.cpp in order for Visual +                    Studio to compile successfully. The release version of the +                    Python lib will not work (20/12/2013). +                    LLDB (dir) CMakeLists.txt uses windows environmental +                    variables $PYTHON_INCLUDE and $PYTHON_LIB to locate +                    Python files required for the build. + +    Copyright:      None. +    -------------------------------------------------------------------------- + +""" + +# Python modules: +import os           # Provide directory and file handling, determine OS information +import sys          # System specific parameters and functions +import shutil       # High-level operations on files and collections of files +import ctypes       # Invoke Windows API for creating symlinks + +# Third party modules: + +# In-house modules: +import utilsOsType      # Determine the OS type this script is running on +import utilsDebug       # Debug Python scripts + +# User facing text: +strMsgOsVersion = "The current OS is %s" +strMsgPyVersion = "The Python version is %d.%d" +strErrMsgProgFail = "Program failure: " +strErrMsgLLDBPyFileNotNotFound = "Unable to locate lldb.py at path '%s'" +strMsgCopyLLDBPy = "Copying lldb.py from '%s' to '%s'" +strErrMsgFrameWkPyDirNotExist = "Unable to find the LLDB.framework directory '%s'" +strMsgCreatePyPkgCopyPkgFile = "create_py_pkg: Copied file '%s' to folder '%s'" +strMsgCreatePyPkgInitFile = "create_py_pkg: Creating pakage init file '%s'" +strMsgCreatePyPkgMkDir = "create_py_pkg: Created folder '%s'" +strMsgConfigBuildDir = "Configuration build directory located at '%s'" +strMsgFoundLldbFrameWkDir = "Found '%s'" +strMsgPyFileLocatedHere = "Python file will be put in '%s'" +strMsgFrameWkPyExists = "Python output folder '%s' already exists" +strMsgFrameWkPyMkDir = "Python output folder '%s' will be created" +strErrMsgCreateFrmWkPyDirFailed = "Unable to create directory '%s' error: %s" +strMsgSymlinkExists = "Symlink for '%s' already exists" +strMsgSymlinkMk = "Creating symlink for %s  (%s -> %s)" +strErrMsgCpLldbpy = "copying lldb to lldb package directory" +strErrMsgCreatePyPkgMissingSlash = "Parameter 3 fn create_py_pkg() missing slash" +strErrMsgMkLinkExecute = "Command mklink failed: %s" +strErrMsgMakeSymlink = "creating symbolic link" +strErrMsgUnexpected = "Unexpected error: %s" +strMsgCopySixPy = "Copying six.py from '%s' to '%s'" +strErrMsgCopySixPyFailed = "Unable to copy '%s' to '%s'" + +def is_debug_interpreter(): +    return hasattr(sys, 'gettotalrefcount') + +#++--------------------------------------------------------------------------- +# Details:  Copy files needed by lldb/macosx/heap.py to build libheap.dylib. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def macosx_copy_file_for_heap(vDictArgs, vstrFrameworkPythonDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script macosx_copy_file_for_heap()") +    bOk = True +    strMsg = "" + +    eOSType = utilsOsType.determine_os_type() +    if eOSType != utilsOsType.EnumOsType.Darwin: +        return (bOk, strMsg) + +    strHeapDir = os.path.join(vstrFrameworkPythonDir, "macosx", "heap") +    strHeapDir = os.path.normcase(strHeapDir) +    if os.path.exists(strHeapDir) and os.path.isdir(strHeapDir): +        return (bOk, strMsg) + +    os.makedirs(strHeapDir) + +    strRoot = os.path.normpath(vDictArgs["--srcRoot"]) +    strSrc = os.path.join(strRoot, "examples", "darwin", "heap_find", "heap", "heap_find.cpp") +    shutil.copy(strSrc, strHeapDir) +    strSrc = os.path.join(strRoot, "examples", "darwin", "heap_find", "heap", "Makefile") +    shutil.copy(strSrc, strHeapDir) + +    return (bOk, strMsg) + +#++--------------------------------------------------------------------------- +# Details:  Create Python packages and Python __init__ files. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrPkgDir              - (R) Destination for copied Python files. +#           vListPkgFiles           - (R) List of source Python files. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def create_py_pkg(vDictArgs, vstrFrameworkPythonDir, vstrPkgDir, vListPkgFiles): +    dbg = utilsDebug.CDebugFnVerbose("Python script create_py_pkg()") +    dbg.dump_object("Package file(s):", vListPkgFiles) +    bDbg = "-d" in vDictArgs + +    bOk = True +    strMsg = "" + +    if vstrPkgDir.__len__() != 0 and vstrPkgDir[0] != "/": +        bOk = False +        strMsg = strErrMsgCreatePyPkgMissingSlash +        return (bOk, strMsg) + +    strPkgName = vstrPkgDir +    strPkgName = "lldb" + strPkgName.replace("/", ".") + +    strPkgDir = vstrFrameworkPythonDir +    strPkgDir += vstrPkgDir +    strPkgDir = os.path.normcase(strPkgDir) + +    if not(os.path.exists(strPkgDir) and os.path.isdir(strPkgDir)): +        if bDbg: +            print((strMsgCreatePyPkgMkDir % strPkgDir)) +        os.makedirs(strPkgDir) + +    for strPkgFile in vListPkgFiles: +        if os.path.exists(strPkgFile) and os.path.isfile(strPkgFile): +            if bDbg: +                print((strMsgCreatePyPkgCopyPkgFile % (strPkgFile, strPkgDir))) +            shutil.copy(strPkgFile, strPkgDir) + +    # Create a packet init files if there wasn't one +    strPkgIniFile = os.path.normpath(os.path.join(strPkgDir, "__init__.py")) +    if os.path.exists(strPkgIniFile) and os.path.isfile(strPkgIniFile): +        return (bOk, strMsg) + +    strPyScript = "__all__ = [" +    strDelimiter = "" +    for strPkgFile in vListPkgFiles: +        if os.path.exists(strPkgFile) and os.path.isfile(strPkgFile): +            strBaseName = os.path.basename(strPkgFile) +            nPos = strBaseName.find(".") +            if nPos != -1: +                strBaseName = strBaseName[0 : nPos] +            strPyScript += "%s\"%s\"" % (strDelimiter, strBaseName) +            strDelimiter = "," +    strPyScript += "]\n" +    strPyScript += "for x in __all__:\n" +    strPyScript += "\t__import__('%s.' + x)" % strPkgName + +    if bDbg: +        print((strMsgCreatePyPkgInitFile % strPkgIniFile)) +    file = open(strPkgIniFile, "w") +    file.write(strPyScript) +    file.close() + +    return (bOk, strMsg) + +#++--------------------------------------------------------------------------- +# Details:  Copy the lldb.py file into the lldb package directory and rename +#           to __init_.py. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrCfgBldDir           - (R) Config directory path. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def copy_lldbpy_file_to_lldb_pkg_dir(vDictArgs, vstrFrameworkPythonDir, vstrCfgBldDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script copy_lldbpy_file_to_lldb_pkg_dir()") +    bOk = True +    bDbg = "-d" in vDictArgs +    strMsg = "" + +    strSrc = os.path.join(vstrCfgBldDir, "lldb.py") +    strSrc = os.path.normcase(strSrc) +    strDst = os.path.join(vstrFrameworkPythonDir, "__init__.py") +    strDst = os.path.normcase(strDst) + +    if not os.path.exists(strSrc): +        strMsg = strErrMsgLLDBPyFileNotNotFound % strSrc +        return (bOk, strMsg) + +    try: +        if bDbg: +            print((strMsgCopyLLDBPy % (strSrc, strDst))) +        shutil.copyfile(strSrc, strDst) +    except IOError as e: +        bOk = False +        strMsg = "I/O error(%d): %s %s" % (e.errno, e.strerror, strErrMsgCpLldbpy) +        if e.errno == 2: +            strMsg += " Src:'%s' Dst:'%s'" % (strSrc, strDst) +    except: +        bOk = False +        strMsg = strErrMsgUnexpected % sys.exec_info()[0] + +    return (bOk, strMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic link on a Windows platform. +# Args:     vstrSrcFile             - (R) Source file name. +#           vstrTargetFile          - (R) Destination file name. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink_windows(vstrSrcPath, vstrTargetPath): +    print(("Making symlink from %s to %s" % (vstrSrcPath, vstrTargetPath))) +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink_windows()") +    bOk = True +    strErrMsg = "" + +    try: +        csl = ctypes.windll.kernel32.CreateHardLinkW +        csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) +        csl.restype = ctypes.c_ubyte +        if csl(vstrTargetPath, vstrSrcPath, 0) == 0: +            raise ctypes.WinError() +    except Exception as e: +        if e.errno != 17: +            bOk = False +            strErrMsg = "WinError(%d): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink) +            strErrMsg += " Src:'%s' Target:'%s'" % (vstrSrcPath, vstrTargetPath) + +    return (bOk, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic link on a UNIX style platform. +# Args:     vstrSrcFile             - (R) Source file name. +#           vstrTargetFile          - (R) Destination file name. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink_other_platforms(vstrSrcPath, vstrTargetPath): +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink_other_platforms()") +    bOk = True +    strErrMsg = "" + +    try: +        os.symlink(vstrSrcPath, vstrTargetPath) +    except OSError as e: +        bOk = False +        strErrMsg = "OSError(%d): %s %s" % (e.errno, e.strerror, strErrMsgMakeSymlink) +        strErrMsg += " Src:'%s' Target:'%s'" % (vstrSrcPath, vstrTargetPath) +    except: +        bOk = False +        strErrMsg = strErrMsgUnexpected % sys.exec_info()[0] + +    return (bOk, strErrMsg) + +def make_symlink_native(vDictArgs, strSrc, strTarget): +    eOSType = utilsOsType.determine_os_type() +    bDbg = "-d" in vDictArgs +    bOk = True +    strErrMsg = "" + +    target_filename = os.path.basename(strTarget) +    if eOSType == utilsOsType.EnumOsType.Unknown: +        bOk = False +        strErrMsg = strErrMsgOsTypeUnknown +    elif eOSType == utilsOsType.EnumOsType.Windows: +        if os.path.isfile(strTarget): +            if bDbg: +                print((strMsgSymlinkExists % target_filename)) +            return (bOk, strErrMsg) +        if bDbg: +            print((strMsgSymlinkMk % (target_filename, strSrc, strTarget))) +        bOk, strErrMsg = make_symlink_windows(strSrc, +                                              strTarget) +    else: +        if os.path.islink(strTarget): +            if bDbg: +                print((strMsgSymlinkExists % target_filename)) +            return (bOk, strErrMsg) +        if bDbg: +            print((strMsgSymlinkMk % (target_filename, strSrc, strTarget))) +        bOk, strErrMsg = make_symlink_other_platforms(strSrc, +                                                      strTarget) + +    return (bOk, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic link. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrSrcFile             - (R) Source file name. +#           vstrTargetFile          - (R) Destination file name. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink(vDictArgs, vstrFrameworkPythonDir, vstrSrcFile, vstrTargetFile): +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink()") +    bOk = True +    strErrMsg = "" +    bDbg = "-d" in vDictArgs +    strTarget = os.path.join(vstrFrameworkPythonDir, vstrTargetFile) +    strTarget = os.path.normcase(strTarget) +    strSrc = "" + +    os.chdir(vstrFrameworkPythonDir) +    bMakeFileCalled = "-m" in vDictArgs +    eOSType = utilsOsType.determine_os_type() +    if not bMakeFileCalled: +        return (bOk, strErrMsg) +    else: +        # Resolve vstrSrcFile path relatively the build directory +        if eOSType == utilsOsType.EnumOsType.Windows: +            # On a Windows platform the vstrFrameworkPythonDir looks like: +            # llvm\\build\\Lib\\site-packages\\lldb +            strBuildDir = os.path.join("..", "..", "..") +        else: +            # On a UNIX style platform the vstrFrameworkPythonDir looks like: +            # llvm/build/lib/python2.7/site-packages/lldb +            strBuildDir = os.path.join("..", "..", "..", "..") +        strSrc = os.path.normcase(os.path.join(strBuildDir, vstrSrcFile)) + +    return make_symlink_native(vDictArgs, strSrc, strTarget) + + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic that the script bridge for Python will need in +#           the Python framework directory. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrLiblldbName         - (R) File name for _lldb library. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink_liblldb(vDictArgs, vstrFrameworkPythonDir, vstrLiblldbFileName): +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink_liblldb()") +    bOk = True +    strErrMsg = "" +    strTarget = vstrLiblldbFileName +    strSrc = "" + +    eOSType = utilsOsType.determine_os_type() +    if eOSType == utilsOsType.EnumOsType.Windows: +        # When importing an extension module using a debug version of python, you +        # write, for example, "import foo", but the interpreter searches for +        # "foo_d.pyd" +        if is_debug_interpreter(): +            strTarget += "_d" +        strTarget += ".pyd" +    else: +        strTarget += ".so" + +    bMakeFileCalled = "-m" in vDictArgs +    if not bMakeFileCalled: +        strSrc = os.path.join("lib", "LLDB") +    else: +        strLibFileExtn = "" +        if eOSType == utilsOsType.EnumOsType.Windows: +            strSrc = os.path.join("bin", "liblldb.dll") +        else: +            if eOSType == utilsOsType.EnumOsType.Darwin: +                strLibFileExtn = ".dylib" +            else: +                strLibFileExtn = ".so" +            strSrc = os.path.join("lib", "liblldb" + strLibFileExtn) + +    bOk, strErrMsg = make_symlink(vDictArgs, vstrFrameworkPythonDir, strSrc, strTarget) + +    return (bOk, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic link to the darwin-debug. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrDarwinDebugFileName - (R) File name for darwin-debug. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink_darwin_debug(vDictArgs, vstrFrameworkPythonDir, vstrDarwinDebugFileName): +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink_darwin_debug()") +    bOk = True +    strErrMsg = "" +    strTarget = vstrDarwinDebugFileName +    strSrc = "" + +    bMakeFileCalled = "-m" in vDictArgs +    if not bMakeFileCalled: +        return (bOk, strErrMsg) +    else: +        strSrc = os.path.join("bin", "lldb-launcher") + +    bOk, strErrMsg = make_symlink(vDictArgs, vstrFrameworkPythonDir, strSrc, strTarget) + +    return (bOk, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symbolic link to the lldb-argdumper. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +#           vstrArgdumperFileName   - (R) File name for lldb-argdumper. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def make_symlink_lldb_argdumper(vDictArgs, vstrFrameworkPythonDir, vstrArgdumperFileName): +    dbg = utilsDebug.CDebugFnVerbose("Python script make_symlink_lldb_argdumper()") +    bOk = True +    strErrMsg = "" +    strTarget = vstrArgdumperFileName +    strSrc = "" + +    eOSType = utilsOsType.determine_os_type() +    if eOSType == utilsOsType.EnumOsType.Windows: +        strTarget += ".exe" + +    bMakeFileCalled = "-m" in vDictArgs +    if not bMakeFileCalled: +        return (bOk, strErrMsg) +    else: +        strExeFileExtn = "" +        if eOSType == utilsOsType.EnumOsType.Windows: +            strExeFileExtn = ".exe" +        strSrc = os.path.join("bin", "lldb-argdumper" + strExeFileExtn) + +    bOk, strErrMsg = make_symlink(vDictArgs, vstrFrameworkPythonDir, strSrc, strTarget) + +    return (bOk, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Make the symlink that the script bridge for Python will need in +#           the Python framework directory. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +# Returns:  Bool - True = function success, False = failure. +#           strErrMsg - Error description on task failure. +# Throws:   None. +#-- +def create_symlinks(vDictArgs, vstrFrameworkPythonDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script create_symlinks()") +    bOk = True +    strErrMsg = "" +    eOSType = utilsOsType.determine_os_type() + +    # Make symlink for _lldb +    strLibLldbFileName = "_lldb" +    if bOk: +        bOk, strErrMsg = make_symlink_liblldb(vDictArgs, +                                              vstrFrameworkPythonDir, +                                              strLibLldbFileName) + +    # Make symlink for darwin-debug on Darwin +    strDarwinDebugFileName = "darwin-debug" +    if bOk and eOSType == utilsOsType.EnumOsType.Darwin: +        bOk, strErrMsg = make_symlink_darwin_debug(vDictArgs, +                                                   vstrFrameworkPythonDir, +                                                   strDarwinDebugFileName) + +    # Make symlink for lldb-argdumper +    strArgdumperFileName = "lldb-argdumper" +    if bOk: +        bOk, strErrMsg = make_symlink_lldb_argdumper(vDictArgs, +                                                     vstrFrameworkPythonDir, +                                                     strArgdumperFileName) + +    return (bOk, strErrMsg) + +def copy_six(vDictArgs, vstrFrameworkPythonDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script copy_six()") +    bDbg = "-d" in vDictArgs +    bOk = True +    strMsg = "" +    site_packages_dir = os.path.dirname(vstrFrameworkPythonDir) +    six_module_filename = "six.py" +    src_file = os.path.join(vDictArgs['--srcRoot'], "third_party", "Python", "module", "six", six_module_filename) +    src_file = os.path.normpath(src_file) +    target = os.path.join(site_packages_dir, six_module_filename) + +    if bDbg: +        print((strMsgCopySixPy % (src_file, target))) +    try: +        shutil.copyfile(src_file, target) +    except: +        bOk = False +        strMsg = strErrMsgCopySixPyFailed % (src_file, target) + +    return (bOk, strMsg) + +#++--------------------------------------------------------------------------- +# Details:  Look for the directory in which to put the Python files if it +#           does not already exist, attempt to make it. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +# Returns:  Bool - True = function success, False = failure. +#           Str - Error description on task failure. +# Throws:   None. +#-- +def find_or_create_python_dir(vDictArgs, vstrFrameworkPythonDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script find_or_create_python_dir()") +    bOk = True +    strMsg = "" +    bDbg = "-d" in vDictArgs + +    if os.path.isdir(vstrFrameworkPythonDir): +        if bDbg: +            print((strMsgFrameWkPyExists % vstrFrameworkPythonDir)) +        return (bOk, strMsg) + +    if bDbg: +        print((strMsgFrameWkPyMkDir % vstrFrameworkPythonDir)) + +    try: +        os.makedirs(vstrFrameworkPythonDir) +    except OSError as exception: +        bOk = False +        strMsg = strErrMsgCreateFrmWkPyDirFailed % (vstrFrameworkPythonDir, +                                                    os.strerror(exception.errno)) + +    return (bOk, strMsg) + +#++--------------------------------------------------------------------------- +# Details:  Retrieve the configuration build path if present and valid (using +#           parameter --cfgBlddir or copy the Python Framework directory. +# Args:     vDictArgs               - (R) Program input parameters. +#           vstrFrameworkPythonDir  - (R) Python framework directory. +# Returns:  Bool - True = function success, False = failure. +#           Str - Config directory path. +#           strErrMsg - Error description on task failure. +# Throws:   None. +#-- +def get_config_build_dir(vDictArgs, vstrFrameworkPythonDir): +    dbg = utilsDebug.CDebugFnVerbose("Python script get_config_build_dir()") +    bOk = True +    strErrMsg = "" + +    strConfigBldDir = "" +    bHaveConfigBldDir = "--cfgBldDir" in vDictArgs +    if bHaveConfigBldDir: +        strConfigBldDir = vDictArgs["--cfgBldDir"] +    if (bHaveConfigBldDir == False) or (strConfigBldDir.__len__() == 0): +        strConfigBldDir = vstrFrameworkPythonDir + +    return (bOk, strConfigBldDir, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Determine where to put the files. Retrieve the directory path for +#           Python's dist_packages/ site_package folder on a Windows platform. +# Args:     vDictArgs   - (R) Program input parameters. +# Returns:  Bool - True = function success, False = failure. +#           Str - Python Framework directory path. +#           strErrMsg - Error description on task failure. +# Throws:   None. +#-- +def get_framework_python_dir_windows(vDictArgs): +    dbg = utilsDebug.CDebugFnVerbose("Python script get_framework_python_dir_windows()") +    bOk = True +    strWkDir = "" +    strErrMsg = "" + +    # We are being built by LLVM, so use the PYTHON_INSTALL_DIR argument, +    # and append the python version directory to the end of it.  Depending +    # on the system other stuff may need to be put here as well. +    from distutils.sysconfig import get_python_lib +    strPythonInstallDir = "" +    bHaveArgPrefix = "--prefix" in vDictArgs +    if bHaveArgPrefix: +        strPythonInstallDir = os.path.normpath(vDictArgs["--prefix"]) + +    bHaveArgCmakeBuildConfiguration = "--cmakeBuildConfiguration" in vDictArgs +    if bHaveArgCmakeBuildConfiguration: +        strPythonInstallDir = os.path.join(strPythonInstallDir, vDictArgs["--cmakeBuildConfiguration"]) + +    if strPythonInstallDir.__len__() != 0: +        strWkDir = get_python_lib(True, False, strPythonInstallDir) +    else: +        strWkDir = get_python_lib(True, False) +    strWkDir = os.path.normcase(os.path.join(strWkDir, "lldb")) + +    return (bOk, strWkDir, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Retrieve the directory path for Python's dist_packages/ +#           site_package folder on a UNIX style platform. +# Args:     vDictArgs   - (R) Program input parameters. +# Returns:  Bool - True = function success, False = failure. +#           Str - Python Framework directory path. +#           strErrMsg - Error description on task failure. +# Throws:   None. +#-- +def get_framework_python_dir_other_platforms(vDictArgs): +    dbg = utilsDebug.CDebugFnVerbose("Python script get_framework_python_dir_other_platform()") +    bOk = True +    strWkDir = "" +    strErrMsg = "" +    bDbg = "-d" in vDictArgs + +    bMakeFileCalled = "-m" in vDictArgs +    if bMakeFileCalled: +        dbg.dump_text("Built by LLVM") +        return get_framework_python_dir_windows(vDictArgs) +    else: +        dbg.dump_text("Built by XCode") +        # We are being built by XCode, so all the lldb Python files can go +        # into the LLDB.framework/Resources/Python subdirectory. +        strWkDir = vDictArgs["--targetDir"] +        strWkDir += os.path.join(strWkDir, "LLDB.framework") +        if os.path.exists(strWkDir): +            if bDbg: +                print((strMsgFoundLldbFrameWkDir % strWkDir)) +            strWkDir = os.path.join(strWkDir, "Resources", "Python", "lldb") +            strWkDir = os.path.normcase(strWkDir) +        else: +            bOk = False +            strErrMsg = strErrMsgFrameWkPyDirNotExist % strWkDir + +    return (bOk, strWkDir, strErrMsg) + +#++--------------------------------------------------------------------------- +# Details:  Retrieve the directory path for Python's dist_packages/ +#           site_package folder depending on the type of OS platform being +#           used. +# Args:     vDictArgs   - (R) Program input parameters. +# Returns:  Bool - True = function success, False = failure. +#           Str - Python Framework directory path. +#           strErrMsg - Error description on task failure. +# Throws:   None. +#-- +def get_framework_python_dir(vDictArgs): +    dbg = utilsDebug.CDebugFnVerbose("Python script get_framework_python_dir()") +    bOk = True +    strWkDir = "" +    strErrMsg = "" + +    eOSType = utilsOsType.determine_os_type() +    if eOSType == utilsOsType.EnumOsType.Unknown: +        bOk = False +        strErrMsg = strErrMsgOsTypeUnknown +    elif eOSType == utilsOsType.EnumOsType.Windows: +        bOk, strWkDir, strErrMsg = get_framework_python_dir_windows(vDictArgs) +    else: +        bOk, strWkDir, strErrMsg = get_framework_python_dir_other_platforms(vDictArgs) + +    return (bOk, strWkDir, strErrMsg) + +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- + +""" Details: Program main entry point fn. Called by another Python script. + +    -------------------------------------------------------------------------- +    Details: This script is to be called by another Python script. It is not +             intended to be called directly i.e from the command line. +    Args:   vDictArgs   - (R) Map of parameter names to values. +            -d (optional)   Determines whether or not this script +                            outputs additional information when running. +            -m (optional)   Specify called from Makefile system. If given locate +                            the LLDBWrapPython.cpp in --srcRoot/source folder +                            else in the --targetDir folder. +            --srcRoot       The root of the lldb source tree. +            --targetDir     Where the lldb framework/shared library gets put. +            --cfgBlddir     Where the buildSwigPythonLLDB.py program will +            (optional)      put the lldb.py file it generated from running +                            SWIG. +            --prefix        Is the root directory used to determine where +            (optional)      third-party modules for scripting languages should +                            be installed. Where non-Darwin systems want to put +                            the .py and .so files so that Python can find them +                            automatically. Python install directory. +    Results:    0       Success +                -100+   Error from this script to the caller script. +                -100    Error program failure with optional message. + +    -------------------------------------------------------------------------- + +""" +def main(vDictArgs): +    dbg = utilsDebug.CDebugFnVerbose("Python script main()") +    bOk = True +    strMsg = "" +    strErrMsgProgFail = "" + +    bDbg = "-d" in vDictArgs + +    eOSType = utilsOsType.determine_os_type() +    if bDbg: +        pyVersion = sys.version_info +        print((strMsgOsVersion % utilsOsType.EnumOsType.name_of(eOSType))) +        print((strMsgPyVersion % (pyVersion[0], pyVersion[1]))) + +    bOk, strFrameworkPythonDir, strMsg = get_framework_python_dir(vDictArgs) + +    if bOk: +        bOk, strCfgBldDir, strMsg = get_config_build_dir(vDictArgs, strFrameworkPythonDir) +    if bOk and bDbg: +        print((strMsgPyFileLocatedHere % strFrameworkPythonDir)) +        print((strMsgConfigBuildDir % strCfgBldDir)) + +    if bOk: +        bOk, strMsg = find_or_create_python_dir(vDictArgs, strFrameworkPythonDir) + +    if bOk: +        bOk, strMsg = create_symlinks(vDictArgs, strFrameworkPythonDir) + +    if bOk: +        bOk, strMsg = copy_six(vDictArgs, strFrameworkPythonDir) + +    if bOk: +        bOk, strMsg = copy_lldbpy_file_to_lldb_pkg_dir(vDictArgs, +                                                       strFrameworkPythonDir, +                                                       strCfgBldDir) +    strRoot = os.path.normpath(vDictArgs["--srcRoot"]) +    if bOk: +        # lldb +        listPkgFiles = [os.path.join(strRoot, "source", "Interpreter", "embedded_interpreter.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "", listPkgFiles) + +    if bOk: +        # lldb/formatters/cpp +        listPkgFiles = [os.path.join(strRoot, "examples", "synthetic", "gnu_libstdcpp.py"), +                        os.path.join(strRoot, "examples", "synthetic", "libcxx.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/formatters/cpp", listPkgFiles) + +    if bOk: +        # Make an empty __init__.py in lldb/runtime as this is required for +        # Python to recognize lldb.runtime as a valid package (and hence, +        # lldb.runtime.objc as a valid contained package) +        listPkgFiles = [] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/runtime", listPkgFiles) + +    if bOk: +        # lldb/formatters +        # Having these files copied here ensure that lldb/formatters is a +        # valid package itself +        listPkgFiles = [os.path.join(strRoot, "examples", "summaries", "cocoa", "cache.py"), +                        os.path.join(strRoot, "examples", "summaries", "cocoa", "metrics.py"), +                        os.path.join(strRoot, "examples", "summaries", "cocoa", "attrib_fromdict.py"), +                        os.path.join(strRoot, "examples", "summaries", "cocoa", "Logger.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/formatters", listPkgFiles) + +    if bOk: +        # lldb/utils +        listPkgFiles = [os.path.join(strRoot, "examples", "python", "symbolication.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/utils", listPkgFiles) + +    if bOk and (eOSType == utilsOsType.EnumOsType.Darwin): +        # lldb/macosx +        listPkgFiles = [os.path.join(strRoot, "examples", "python", "crashlog.py"), +                        os.path.join(strRoot, "examples", "darwin", "heap_find", "heap.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/macosx", listPkgFiles) + +    if bOk and (eOSType == utilsOsType.EnumOsType.Darwin): +        # lldb/diagnose +        listPkgFiles = [os.path.join(strRoot, "examples", "python", "diagnose_unwind.py"), +                        os.path.join(strRoot, "examples", "python", "diagnose_nsstring.py")] +        bOk, strMsg = create_py_pkg(vDictArgs, strFrameworkPythonDir, "/diagnose", listPkgFiles) + +    if bOk: +        bOk, strMsg = macosx_copy_file_for_heap(vDictArgs, strFrameworkPythonDir) + +    if bOk: +        return (0, strMsg) +    else: +        strErrMsgProgFail += strMsg +        return (-100, strErrMsgProgFail) + + +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- + +# This script can be called by another Python script by calling the main() +# function directly +if __name__ == "__main__": +    print("Script cannot be called directly, called by finishSwigWrapperClasses.py") + diff --git a/scripts/Python/modify-python-lldb.py b/scripts/Python/modify-python-lldb.py new file mode 100644 index 000000000000..56323d6679a1 --- /dev/null +++ b/scripts/Python/modify-python-lldb.py @@ -0,0 +1,486 @@ +# +# modify-python-lldb.py +# +# This script modifies the lldb module (which was automatically generated via +# running swig) to support iteration and/or equality operations for certain lldb +# objects, implements truth value testing for certain lldb objects, and adds a +# global variable 'debugger_unique_id' which is initialized to 0. +# +# As a cleanup step, it also removes the 'residues' from the autodoc features of +# swig.  For an example, take a look at SBTarget.h header file, where we take +# advantage of the already existing doxygen C++-docblock and make it the Python +# docstring for the same method.  The 'residues' in this context include the +# '#endif', the '#ifdef SWIG', the c comment marker, the trailing blank (SPC's) +# line, and the doxygen comment start marker. +# +# In addition to the 'residues' removal during the cleanup step, it also +# transforms the 'char' data type (which was actually 'char *' but the 'autodoc' +# feature of swig removes ' *' from it) into 'str' (as a Python str type). +# +# It also calls SBDebugger.Initialize() to initialize the lldb debugger +# subsystem. +# + +# System modules +import sys, re +if sys.version_info.major >= 3: +    import io as StringIO +else: +    import StringIO + +# import use_lldb_suite so we can find third-party and helper modules +import use_lldb_suite + +# Third party modules +import six + +# LLDB modules + +if len(sys.argv) != 2: +    output_name = "./lldb.py" +else: +    output_name = sys.argv[1] + "/lldb.py" + +# print "output_name is '" + output_name + "'" + +# +# Version string +#  +version_line = "swig_version = %s" + +# +# Residues to be removed. +# +c_endif_swig = "#endif" +c_ifdef_swig = "#ifdef SWIG" +c_comment_marker = "//------------" +# The pattern for recognizing the doxygen comment block line. +doxygen_comment_start = re.compile("^\s*(/// ?)") +# The demarcation point for turning on/off residue removal state. +# When bracketed by the lines, the CLEANUP_DOCSTRING state (see below) is ON. +toggle_docstring_cleanup_line = '        """' + +def char_to_str_xform(line): +    """This transforms the 'char', i.e, 'char *' to 'str', Python string.""" +    line = line.replace(' char', ' str') +    line = line.replace('char ', 'str ') +    # Special case handling of 'char **argv' and 'char **envp'. +    line = line.replace('str argv', 'list argv') +    line = line.replace('str envp', 'list envp') +    return line + +# +# The one-liner docstring also needs char_to_str transformation, btw. +# +TWO_SPACES = ' ' * 2 +EIGHT_SPACES = ' ' * 8 +one_liner_docstring_pattern = re.compile('^(%s|%s)""".*"""$' % (TWO_SPACES, EIGHT_SPACES)) + +# +# lldb_helpers and lldb_iter() should appear before our first SB* class definition. +# +lldb_helpers = ''' +# ================================== +# Helper function for SBModule class +# ================================== +def in_range(symbol, section): +    """Test whether a symbol is within the range of a section.""" +    symSA = symbol.GetStartAddress().GetFileAddress() +    symEA = symbol.GetEndAddress().GetFileAddress() +    secSA = section.GetFileAddress() +    secEA = secSA + section.GetByteSize() + +    if symEA != LLDB_INVALID_ADDRESS: +        if secSA <= symSA and symEA <= secEA: +            return True +        else: +            return False +    else: +        if secSA <= symSA and symSA < secEA: +            return True +        else: +            return False +''' + +lldb_iter_def = ''' +# =================================== +# Iterator for lldb container objects +# =================================== +def lldb_iter(obj, getsize, getelem): +    """A generator adaptor to support iteration for lldb container objects.""" +    size = getattr(obj, getsize) +    elem = getattr(obj, getelem) +    for i in range(size()): +        yield elem(i) + +# ============================================================================== +# The modify-python-lldb.py script is responsible for post-processing this SWIG- +# generated lldb.py module.  It is responsible for adding the above lldb_iter() +# function definition as well as the supports, in the following, for iteration +# protocol: __iter__, rich comparison methods: __eq__ and __ne__, truth value +# testing (and built-in operation bool()): __nonzero__, and built-in function +# len(): __len__. +# ============================================================================== +''' + +# +# linked_list_iter() is a special purpose iterator to treat the SBValue as the +# head of a list data structure, where you specify the child member name which +# points to the next item on the list and you specify the end-of-list function +# which takes an SBValue and returns True if EOL is reached and False if not. +# +linked_list_iter_def = ''' +    def __eol_test__(val): +        """Default function for end of list test takes an SBValue object. + +        Return True if val is invalid or it corresponds to a null pointer. +        Otherwise, return False. +        """ +        if not val or val.GetValueAsUnsigned() == 0: +            return True +        else: +            return False + +    # ================================================== +    # Iterator for lldb.SBValue treated as a linked list +    # ================================================== +    def linked_list_iter(self, next_item_name, end_of_list_test=__eol_test__): +        """Generator adaptor to support iteration for SBValue as a linked list. + +        linked_list_iter() is a special purpose iterator to treat the SBValue as +        the head of a list data structure, where you specify the child member +        name which points to the next item on the list and you specify the +        end-of-list test function which takes an SBValue for an item and returns +        True if EOL is reached and False if not. + +        linked_list_iter() also detects infinite loop and bails out early. + +        The end_of_list_test arg, if omitted, defaults to the __eol_test__ +        function above. + +        For example, + +        # Get Frame #0. +        ... + +        # Get variable 'task_head'. +        task_head = frame0.FindVariable('task_head') +        ... + +        for t in task_head.linked_list_iter('next'): +            print t +        """ +        if end_of_list_test(self): +            return +        item = self +        visited = set() +        try: +            while not end_of_list_test(item) and not item.GetValueAsUnsigned() in visited: +                visited.add(item.GetValueAsUnsigned()) +                yield item +                # Prepare for the next iteration. +                item = item.GetChildMemberWithName(next_item_name) +        except: +            # Exception occurred.  Stop the generator. +            pass + +        return +''' + +# This supports the iteration protocol. +iter_def = "    def __iter__(self): return lldb_iter(self, '%s', '%s')" +module_iter = "    def module_iter(self): return lldb_iter(self, '%s', '%s')" +breakpoint_iter = "    def breakpoint_iter(self): return lldb_iter(self, '%s', '%s')" +watchpoint_iter = "    def watchpoint_iter(self): return lldb_iter(self, '%s', '%s')" +section_iter = "    def section_iter(self): return lldb_iter(self, '%s', '%s')" +compile_unit_iter = "    def compile_unit_iter(self): return lldb_iter(self, '%s', '%s')" + +# Called to implement the built-in function len(). +# Eligible objects are those containers with unambiguous iteration support. +len_def = "    def __len__(self): return self.%s()" + +# This supports the rich comparison methods of __eq__ and __ne__. +eq_def = "    def __eq__(self, other): return isinstance(other, %s) and %s" +ne_def = "    def __ne__(self, other): return not self.__eq__(other)" + +# Called to implement truth value testing and the built-in operation bool(); +# Note that Python 2 uses __nonzero__(), whereas Python 3 uses __bool__() +# should return False or True, or their integer equivalents 0 or 1. +# Delegate to self.IsValid() if it is defined for the current lldb object. + +if six.PY2: +    nonzero_def = "    def __nonzero__(self): return self.IsValid()" +else: +    nonzero_def = "    def __bool__(self): return self.IsValid()" + +# A convenience iterator for SBSymbol! +symbol_in_section_iter_def = ''' +    def symbol_in_section_iter(self, section): +        """Given a module and its contained section, returns an iterator on the +        symbols within the section.""" +        for sym in self: +            if in_range(sym, section): +                yield sym +''' + +# +# This dictionary defines a mapping from classname to (getsize, getelem) tuple. +# +d = { 'SBBreakpoint':  ('GetNumLocations',   'GetLocationAtIndex'), +      'SBCompileUnit': ('GetNumLineEntries', 'GetLineEntryAtIndex'), +      'SBDebugger':    ('GetNumTargets',     'GetTargetAtIndex'), +      'SBModule':      ('GetNumSymbols',     'GetSymbolAtIndex'), +      'SBProcess':     ('GetNumThreads',     'GetThreadAtIndex'), +      'SBSection':     ('GetNumSubSections', 'GetSubSectionAtIndex'), +      'SBThread':      ('GetNumFrames',      'GetFrameAtIndex'), + +      'SBInstructionList':   ('GetSize', 'GetInstructionAtIndex'), +      'SBStringList':        ('GetSize', 'GetStringAtIndex',), +      'SBSymbolContextList': ('GetSize', 'GetContextAtIndex'), +      'SBTypeList':          ('GetSize', 'GetTypeAtIndex'), +      'SBValueList':         ('GetSize', 'GetValueAtIndex'), + +      'SBType':  ('GetNumberChildren', 'GetChildAtIndex'), +      'SBValue': ('GetNumChildren',    'GetChildAtIndex'), + +      # SBTarget needs special processing, see below. +      'SBTarget': {'module':     ('GetNumModules', 'GetModuleAtIndex'), +                   'breakpoint': ('GetNumBreakpoints', 'GetBreakpointAtIndex'), +                   'watchpoint': ('GetNumWatchpoints', 'GetWatchpointAtIndex') +                   }, + +      # SBModule has an additional section_iter(), see below. +      'SBModule-section': ('GetNumSections', 'GetSectionAtIndex'), +      # And compile_unit_iter(). +      'SBModule-compile-unit': ('GetNumCompileUnits', 'GetCompileUnitAtIndex'), +      # As well as symbol_in_section_iter(). +      'SBModule-symbol-in-section': symbol_in_section_iter_def +      } + +# +# This dictionary defines a mapping from classname to equality method name(s). +# +e = { 'SBAddress':            ['GetFileAddress', 'GetModule'], +      'SBBreakpoint':         ['GetID'], +      'SBWatchpoint':         ['GetID'], +      'SBFileSpec':           ['GetFilename', 'GetDirectory'], +      'SBModule':             ['GetFileSpec', 'GetUUIDString'], +      'SBType':               ['GetByteSize', 'GetName'] +      } + +def list_to_frag(list): +    """Transform a list to equality program fragment. + +    For example, ['GetID'] is transformed to 'self.GetID() == other.GetID()', +    and ['GetFilename', 'GetDirectory'] to 'self.GetFilename() == other.GetFilename() +    and self.GetDirectory() == other.GetDirectory()'. +    """ +    if not list: +        raise Exception("list should be non-empty") +    frag = StringIO.StringIO() +    for i in range(len(list)): +        if i > 0: +            frag.write(" and ") +        frag.write("self.{0}() == other.{0}()".format(list[i])) +    return frag.getvalue() + +class NewContent(StringIO.StringIO): +    """Simple facade to keep track of the previous line to be committed.""" +    def __init__(self): +        StringIO.StringIO.__init__(self) +        self.prev_line = None +    def add_line(self, a_line): +        """Add a line to the content, if there is a previous line, commit it.""" +        if self.prev_line != None: +            self.write(self.prev_line + "\n") +        self.prev_line = a_line +    def del_line(self): +        """Forget about the previous line, do not commit it.""" +        self.prev_line = None +    def del_blank_line(self): +        """Forget about the previous line if it is a blank line.""" +        if self.prev_line != None and not self.prev_line.strip(): +            self.prev_line = None +    def finish(self): +        """Call this when you're finished with populating content.""" +        if self.prev_line != None: +            self.write(self.prev_line + "\n") +        self.prev_line = None + +# The new content will have the iteration protocol defined for our lldb objects. +new_content = NewContent() + +with open(output_name, 'r') as f_in: +    content = f_in.read() + +# The pattern for recognizing the SWIG Version string +version_pattern = re.compile("^# Version:? (.*)$") + +# The pattern for recognizing the beginning of an SB class definition. +class_pattern = re.compile("^class (SB.*)\(_object\):$") + +# The pattern for recognizing the beginning of the __init__ method definition. +init_pattern = re.compile("^    def __init__\(self.*\):") + +# The pattern for recognizing the beginning of the IsValid method definition. +isvalid_pattern = re.compile("^    def IsValid\(") + +# These define the states of our finite state machine. +EXPECTING_VERSION = 0 +NORMAL = 1 +DEFINING_ITERATOR = 2 +DEFINING_EQUALITY = 4 +CLEANUP_DOCSTRING = 8 + +# The lldb_iter_def only needs to be inserted once. +lldb_iter_defined = False; + +# Our FSM begins its life in the NORMAL state, and transitions to the +# DEFINING_ITERATOR and/or DEFINING_EQUALITY state whenever it encounters the +# beginning of certain class definitions, see dictionaries 'd' and 'e' above. +# +# Note that the two states DEFINING_ITERATOR and DEFINING_EQUALITY are +# orthogonal in that our FSM can be in one, the other, or both states at the +# same time.  During such time, the FSM is eagerly searching for the __init__ +# method definition in order to insert the appropriate method(s) into the lldb +# module. +# +# The state CLEANUP_DOCSTRING can be entered from either the NORMAL or the +# DEFINING_ITERATOR/EQUALITY states.  While in this state, the FSM is fixing/ +# cleaning the Python docstrings generated by the swig docstring features. +# +# The FSM, in all possible states, also checks the current input for IsValid() +# definition, and inserts a __nonzero__() method definition to implement truth +# value testing and the built-in operation bool(). +state = EXPECTING_VERSION + +swig_version_tuple = None +for line in content.splitlines(): +    # Handle the state transition into CLEANUP_DOCSTRING state as it is possible +    # to enter this state from either NORMAL or DEFINING_ITERATOR/EQUALITY. +    # +    # If '        """' is the sole line, prepare to transition to the +    # CLEANUP_DOCSTRING state or out of it. +     +    if line == toggle_docstring_cleanup_line: +        if state & CLEANUP_DOCSTRING: +            # Special handling of the trailing blank line right before the '"""' +            # end docstring marker. +            new_content.del_blank_line() +            state ^= CLEANUP_DOCSTRING +        else: +            state |= CLEANUP_DOCSTRING + +    if state == EXPECTING_VERSION: +        # We haven't read the version yet, read it now. +        if swig_version_tuple is None: +            match = version_pattern.search(line) +            if match: +                v = match.group(1) +                swig_version_tuple = tuple(map(int, (v.split(".")))) +        elif not line.startswith('#'): +            # This is the first non-comment line after the header.  Inject the version +            new_line = version_line % str(swig_version_tuple) +            new_content.add_line(new_line) +            state = NORMAL + +    if state == NORMAL: +        match = class_pattern.search(line) +        # Inserts lldb_helpers and the lldb_iter() definition before the first +        # class definition. +        if not lldb_iter_defined and match: +            new_content.add_line(lldb_helpers) +            new_content.add_line(lldb_iter_def) +            lldb_iter_defined = True + +        # If we are at the beginning of the class definitions, prepare to +        # transition to the DEFINING_ITERATOR/DEFINING_EQUALITY state for the +        # right class names. +        if match: +            cls = match.group(1) +            if cls in d: +                # Adding support for iteration for the matched SB class. +                state |= DEFINING_ITERATOR +            if cls in e: +                # Adding support for eq and ne for the matched SB class. +                state |= DEFINING_EQUALITY + +    if (state & DEFINING_ITERATOR) or (state & DEFINING_EQUALITY): +        match = init_pattern.search(line) +        if match: +            # We found the beginning of the __init__ method definition. +            # This is a good spot to insert the iter and/or eq-ne support. +            # +            # But note that SBTarget has three types of iterations. +            if cls == "SBTarget": +                new_content.add_line(module_iter % (d[cls]['module'])) +                new_content.add_line(breakpoint_iter % (d[cls]['breakpoint'])) +                new_content.add_line(watchpoint_iter % (d[cls]['watchpoint'])) +            else: +                if (state & DEFINING_ITERATOR): +                    new_content.add_line(iter_def % d[cls]) +                    new_content.add_line(len_def % d[cls][0]) +                if (state & DEFINING_EQUALITY): +                    new_content.add_line(eq_def % (cls, list_to_frag(e[cls]))) +                    new_content.add_line(ne_def) + +            # SBModule has extra SBSection, SBCompileUnit iterators and symbol_in_section_iter()! +            if cls == "SBModule": +                new_content.add_line(section_iter % d[cls+'-section']) +                new_content.add_line(compile_unit_iter % d[cls+'-compile-unit']) +                new_content.add_line(d[cls+'-symbol-in-section']) + +            # This special purpose iterator is for SBValue only!!! +            if cls == "SBValue": +                new_content.add_line(linked_list_iter_def) + +            # Next state will be NORMAL. +            state = NORMAL + +    if (state & CLEANUP_DOCSTRING): +        # Cleanse the lldb.py of the autodoc'ed residues. +        if c_ifdef_swig in line or c_endif_swig in line: +            continue +        # As well as the comment marker line. +        if c_comment_marker in line: +            continue + +        # Also remove the '\a ' and '\b 'substrings. +        line = line.replace('\a ', '') +        line = line.replace('\b ', '') +        # And the leading '///' substring. +        doxygen_comment_match = doxygen_comment_start.match(line) +        if doxygen_comment_match: +            line = line.replace(doxygen_comment_match.group(1), '', 1) + +        line = char_to_str_xform(line) + +        # Note that the transition out of CLEANUP_DOCSTRING is handled at the +        # beginning of this function already. + +    # This deals with one-liner docstring, for example, SBThread.GetName: +    # """GetName(self) -> char""". +    if one_liner_docstring_pattern.match(line): +        line = char_to_str_xform(line) + +    # Look for 'def IsValid(*args):', and once located, add implementation +    # of truth value testing for this object by delegation. +    if isvalid_pattern.search(line): +        new_content.add_line(nonzero_def) + +    # Pass the original line of content to new_content. +    new_content.add_line(line) + +# We are finished with recording new content. +new_content.finish() + +with open(output_name, 'w') as f_out: +    f_out.write(new_content.getvalue()) +    f_out.write('''debugger_unique_id = 0 +SBDebugger.Initialize() +debugger = None +target = SBTarget() +process = SBProcess() +thread = SBThread() +frame = SBFrame()''') + diff --git a/scripts/Python/modules/CMakeLists.txt b/scripts/Python/modules/CMakeLists.txt new file mode 100644 index 000000000000..396d447ff267 --- /dev/null +++ b/scripts/Python/modules/CMakeLists.txt @@ -0,0 +1,11 @@ +# Disable some warnings triggered by Python's headers. +check_cxx_compiler_flag("-Wno-macro-redefined" +                        CXX_SUPPORTS_NO_MACRO_REDEFINED) +if (CXX_SUPPORTS_NO_MACRO_REDEFINED) +  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-macro-redefined") +endif () + +# build the Python readline suppression module only on Linux +if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT __ANDROID_NDK__) +   add_subdirectory(readline) +endif() diff --git a/scripts/Python/modules/Makefile b/scripts/Python/modules/Makefile new file mode 100644 index 000000000000..b6989889858d --- /dev/null +++ b/scripts/Python/modules/Makefile @@ -0,0 +1,20 @@ +##===- scripts/Python/modules/Makefile ---------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../.. +include $(LLDB_LEVEL)/../../Makefile.config + +DIRS:= + +# only build the readline suppression module on Linux, Kfreebsd & Hurd +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU GNU/kFreeBSD)) +DIRS += readline +endif + +include $(LLDB_LEVEL)/Makefile diff --git a/scripts/Python/modules/readline/CMakeLists.txt b/scripts/Python/modules/readline/CMakeLists.txt new file mode 100644 index 000000000000..0a4376c1c324 --- /dev/null +++ b/scripts/Python/modules/readline/CMakeLists.txt @@ -0,0 +1,25 @@ +# FIXME: if a non-standard version of python is requested, the cmake macro +# below will need Python_ADDITIONAL_VERSIONS set in order to find it. +include(FindPythonInterp) +SET(PYTHON_DIRECTORY python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages) + +# Build the readline python module +include_directories(${PYTHON_INCLUDE_DIR}) +add_library(readline SHARED readline.cpp) + +if (NOT LLDB_DISABLE_LIBEDIT) +  target_link_libraries(readline ${PYTHON_LIBRARY} edit) +else() +  target_link_libraries(readline ${PYTHON_LIBRARY}) +endif() + +# FIXME: the LIBRARY_OUTPUT_PATH seems to be ignored - this is not a +# functional issue for the build dir, though, since the shared lib dir +# for the build is in the python shared library load path, and thus +# python finds it when loading the python readline module. +set_target_properties(readline PROPERTIES +                               PREFIX "" +                               LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/${PYTHON_DIRECTORY}) + +# Install the readline module. +install(TARGETS readline LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LLVM_LIBDIR_SUFFIX}/${PYTHON_DIRECTORY}) diff --git a/scripts/Python/modules/readline/Makefile b/scripts/Python/modules/readline/Makefile new file mode 100644 index 000000000000..dc0d757bc175 --- /dev/null +++ b/scripts/Python/modules/readline/Makefile @@ -0,0 +1,100 @@ +##===- scripts/Python/modules/readline/Makefile ------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +# Skip this entire Makefile if python is disabled. +ifeq (,$(findstring -DLLDB_DISABLE_PYTHON,$(CXXFLAGS))) + +LEVEL := ../../../../../.. +LLDB_LEVEL := ../../../.. + +LIBRARYNAME = readline + +NO_BUILD_ARCHIVE = 1 +LINK_LIBS_IN_SHARED = 1 +SHARED_LIBRARY = 1 +LOADABLE_MODULE = 1 + +PYTHON_CONFIG?=	python-config +PYTHON_INC_DIR = $(shell $(PYTHON_CONFIG) --includes) + +# Include all archives in the shared lib +USEDLIBS := + +include $(LLDB_LEVEL)/../../Makefile.config + +LINK_COMPONENTS := + +include $(LEVEL)/Makefile.common + +# include python headers +CPP.Flags += $(PYTHON_INC_DIR) + +ifeq ($(HOST_OS),Darwin) +    LLVMLibsOptions += -Wl,-all_load +    # set dylib internal version number to llvmCore submission number +    ifdef LLDB_SUBMIT_VERSION +        LLVMLibsOptions += -Wl,-current_version \ +                           -Wl,$(LLDB_SUBMIT_VERSION).$(LLDB_SUBMIT_SUBVERSION) \ +                           -Wl,-compatibility_version -Wl,1 +    endif +    # extra options to override libtool defaults +    LVMLibsOptions += -F/System/Library/Frameworks -F/System/Library/PrivateFrameworks +    LLVMLibsOptions += -framework Foundation -framework CoreFoundation +    LLVMLibsOptions += -framework CoreServices -framework Carbon -framework Security +    LLVMLibsOptions += -framework DebugSymbols $(PYTHON_BUILD_FLAGS) -lobjc +    # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line +    DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') +    ifneq ($(DARWIN_VERS),8) +       LLVMLibsOptions  += -Wl,-install_name \ +                           -Wl,"@executable_path/../lib/$(LIBRARYNAME)$(SHLIBEXT)" +    endif +endif + +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU GNU/kFreeBSD)) +    # Include everything from the .a's into the shared library. +    ProjLibsOptions := -Wl,--whole-archive $(ProjLibsOptions) \ +                       -Wl,--no-whole-archive +    # Link in libedit +    # LLVMLibsOptions += -ledit +    LLVMLibsOptions += -Wl,--soname,$(LIBRARYNAME)$(SHLIBEXT) +endif + +ifeq ($(HOST_OS),FreeBSD) +    # Include everything from the .a's into the shared library. +    ProjLibsOptions := -Wl,--whole-archive $(ProjLibsOptions) \ +                       -Wl,--no-whole-archive +    # Allow unresolved symbols. +    LLVMLibsOptions += -Wl,--allow-shlib-undefined +    # Link in libedit +    # LLVMLibsOptions += -L/usr/local/lib -ledit +endif + +# FIXME: dynamically construct the version from `python -V` +PYTHON_VERSION:=2.7 +LLDB_PYTHON_MODULE_REL_DIR:=python$(PYTHON_VERSION)/site-packages +LLDB_PYTHON_MODULE_DIR:=$(LibDir)/$(LLDB_PYTHON_MODULE_REL_DIR) + +# Target to move readline module from shared lib build location to +# local python module directory. +all-local:: $(LLDB_PYTHON_MODULE_DIR)/$(LIBRARYNAME)$(SHLIBEXT) + +$(LLDB_PYTHON_MODULE_DIR)/$(LIBRARYNAME)$(SHLIBEXT): $(SharedLibDir)/$(LIBRARYNAME)$(SHLIBEXT) +	$(Echo) Staging $(BuildMode) $(LIBRARYNAME)$(SHLIBEXT) to $(LLDB_PYTHON_MODULE_DIR) +	$(Verb) $(MKDIR) "$(LLDB_PYTHON_MODULE_DIR)" +	$(Verb) $(ProgInstall) $(SharedLibDir)/$(LIBRARYNAME)$(SHLIBEXT) $(LLDB_PYTHON_MODULE_DIR) + +# Target to move the shared library from the build python lib dir to +# the install python lib dir. +install-local:: $(LLDB_PYTHON_MODULE_DIR)/$(LIBRARYNAME)$(SHLIBEXT) +	$(Echo) Installing $(BuildMode) $(LLDB_PYTHON_MODULE_DIR)/$(LIBRARYNAME)$(SHLIBEXT) to $(DESTDIR)$(prefix)/lib/$(LLDB_PYTHON_MODULE_REL_DIR) +	$(Verb) $(MKDIR) "$(DESTDIR)$(prefix)/lib/$(LLDB_PYTHON_MODULE_REL_DIR)" +	$(Verb) $(ProgInstall) "$(LLDB_PYTHON_MODULE_DIR)/$(LIBRARYNAME)$(SHLIBEXT)" "$(DESTDIR)$(prefix)/lib/$(LLDB_PYTHON_MODULE_REL_DIR)" +	$(Verb) $(RM) "$(DESTDIR)$(prefix)/lib/$(LIBRARYNAME)$(SHLIBEXT)" + +endif  # if !defined(LLDB_DISABLE_PYTHON) diff --git a/scripts/Python/modules/readline/readline.cpp b/scripts/Python/modules/readline/readline.cpp new file mode 100644 index 000000000000..d66ccf4b6b7d --- /dev/null +++ b/scripts/Python/modules/readline/readline.cpp @@ -0,0 +1,76 @@ +// NOTE: Since Python may define some pre-processor definitions which affect the +// standard headers on some systems, you must include Python.h before any +// standard headers are included. +#include "Python.h" + +#include <stdio.h> + +#ifndef LLDB_DISABLE_LIBEDIT +#include <editline/readline.h> +#endif + +// Simple implementation of the Python readline module using libedit. +// In the event that libedit is excluded from the build, this turns +// back into a null implementation that blocks the module from pulling +// in the GNU readline shared lib, which causes linkage confusion when +// both readline and libedit's readline compatibility symbols collide. +// +// Currently it only installs a PyOS_ReadlineFunctionPointer, without +// implementing any of the readline module methods. This is meant to +// work around LLVM pr18841 to avoid seg faults in the stock Python +// readline.so linked against GNU readline. + +static struct PyMethodDef moduleMethods[] = +{ +    {nullptr, nullptr, 0, nullptr} +}; + +#ifndef LLDB_DISABLE_LIBEDIT +PyDoc_STRVAR( +    moduleDocumentation, +    "Simple readline module implementation based on libedit."); +#else +PyDoc_STRVAR( +    moduleDocumentation, +    "Stub module meant to avoid linking GNU readline."); +#endif + +#ifndef LLDB_DISABLE_LIBEDIT +static char* +simple_readline(FILE *stdin, FILE *stdout, char *prompt) +{ +    rl_instream = stdin; +    rl_outstream = stdout; +    char* line = readline(prompt); +    if (!line) +    { +        char* ret = (char*)PyMem_Malloc(1); +        if (ret != NULL) +            *ret = '\0'; +        return ret; +    } +    if (*line) +        add_history(line); +    int n = strlen(line); +    char* ret = (char*)PyMem_Malloc(n + 2); +    strncpy(ret, line, n); +    free(line); +    ret[n] = '\n'; +    ret[n+1] = '\0'; +    return ret; +} +#endif + +PyMODINIT_FUNC +initreadline(void) +{ +#ifndef LLDB_DISABLE_LIBEDIT +    PyOS_ReadlineFunctionPointer = simple_readline; +#endif +    Py_InitModule4( +        "readline", +        moduleMethods, +        moduleDocumentation, +        static_cast<PyObject *>(NULL), +        PYTHON_API_VERSION); +} diff --git a/scripts/Python/prepare_binding_Python.py b/scripts/Python/prepare_binding_Python.py new file mode 100644 index 000000000000..1996841baf18 --- /dev/null +++ b/scripts/Python/prepare_binding_Python.py @@ -0,0 +1,435 @@ +""" +                     The LLVM Compiler Infrastructure + +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. + +Python binding preparation script. +""" + +# Python modules: +from __future__ import print_function + +import logging +import os +import re +import shutil +import subprocess +import sys + + +class SwigSettings(object): +    """Provides a single object to represent swig files and settings.""" +    def __init__(self): +        self.extensions_file = None +        self.header_files = None +        self.input_file = None +        self.interface_files = None +        self.output_file = None +        self.safecast_file = None +        self.typemaps_file = None +        self.wrapper_file = None + +    @classmethod +    def _any_files_newer(cls, files, check_mtime): +        """Returns if any of the given files has a newer modified time. + +        @param cls the class +        @param files a list of zero or more file paths to check +        @param check_mtime the modification time to use as a reference. + +        @return True if any file's modified time is newer than check_mtime. +        """ +        for path in files: +            path_mtime = os.path.getmtime(path) +            if path_mtime > check_mtime: +                # This path was modified more recently than the +                # check_mtime. +                return True +        # If we made it here, nothing was newer than the check_mtime +        return False + +    @classmethod +    def _file_newer(cls, path, check_mtime): +        """Tests how recently a file has been modified. + +        @param cls the class +        @param path a file path to check +        @param check_mtime the modification time to use as a reference. + +        @return True if the file's modified time is newer than check_mtime. +        """ +        path_mtime = os.path.getmtime(path) +        return path_mtime > check_mtime + +    def output_out_of_date(self): +        """Returns whether the output file is out of date. + +        Compares output file time to all the input files. + +        @return True if any of the input files are newer than +        the output file, or if the output file doesn't exist; +        False otherwise. +        """ +        if not os.path.exists(self.output_file): +            logging.info("will generate, missing binding output file") +            return True +        output_mtime = os.path.getmtime(self.output_file) +        if self._any_files_newer(self.header_files, output_mtime): +            logging.info("will generate, header files newer") +            return True +        if self._any_files_newer(self.interface_files, output_mtime): +            logging.info("will generate, interface files newer") +            return True +        if self._file_newer(self.input_file, output_mtime): +            logging.info("will generate, swig input file newer") +            return True +        if self._file_newer(self.extensions_file, output_mtime): +            logging.info("will generate, swig extensions file newer") +            return True +        if self._file_newer(self.wrapper_file, output_mtime): +            logging.info("will generate, swig wrapper file newer") +            return True +        if self._file_newer(self.typemaps_file, output_mtime): +            logging.info("will generate, swig typemaps file newer") +            return True +        if self._file_newer(self.safecast_file, output_mtime): +            logging.info("will generate, swig safecast file newer") +            return True + +        # If we made it here, nothing is newer than the output file. +        # Thus, the output file is not out of date. +        return False + + +def get_header_files(options): +    """Returns a list of paths to C++ header files for the LLDB API. + +    These are the files that define the C++ API that will be wrapped by Python. + +    @param options the dictionary of options parsed from the command line. + +    @return a list of full paths to the include files used to define the public +    LLDB C++ API. +    """ + +    header_file_paths = [] +    header_base_dir = os.path.join(options.src_root, "include", "lldb") + +    # Specify the include files in include/lldb that are not easy to +    # grab programatically. +    for header in [ +            "lldb-defines.h", +            "lldb-enumerations.h", +            "lldb-forward.h", +            "lldb-types.h"]: +        header_file_paths.append(os.path.normcase( +            os.path.join(header_base_dir, header))) + +    # Include the main LLDB.h file. +    api_dir = os.path.join(header_base_dir, "API") +    header_file_paths.append(os.path.normcase( +        os.path.join(api_dir, "LLDB.h"))) + +    filename_regex = re.compile(r"^SB.+\.h$") + +    # Include all the SB*.h files in the API dir. +    for filename in os.listdir(api_dir): +        if filename_regex.match(filename): +            header_file_paths.append( +                os.path.normcase(os.path.join(api_dir, filename))) + +    logging.debug("found public API header file paths: %s", header_file_paths) +    return header_file_paths + + +def get_interface_files(options): +    """Returns a list of interface files used as input to swig. + +    @param options the options dictionary parsed from the command line args. + +    @return a list of full paths to the interface (.i) files used to describe +    the public API language binding. +    """ +    interface_file_paths = [] +    interface_dir = os.path.join(options.src_root, "scripts", "interface") + +    for filepath in [f for f in os.listdir(interface_dir) +                     if os.path.splitext(f)[1] == ".i"]: +        interface_file_paths.append( +            os.path.normcase(os.path.join(interface_dir, filepath))) + +    logging.debug("found swig interface files: %s", interface_file_paths) +    return interface_file_paths + + +def remove_ignore_enoent(filename): +    """Removes given file, ignoring error if it doesn't exist. + +    @param filename the path of the file to remove. +    """ +    try: +        os.remove(filename) +    except OSError as error: +        import errno +        if error.errno != errno.ENOENT: +            raise + + +def do_swig_rebuild(options, dependency_file, config_build_dir, settings): +    """Generates Python bindings file from swig. + +    This method will do a sys.exit() if something fails.  If it returns to +    the caller, it succeeded. + +    @param options the parsed command line options structure. +    @param dependency_file path to the bindings dependency file +    to be generated; otherwise, None if a dependency file is not +    to be generated. +    @param config_build_dir used as the output directory used by swig +    @param settings the SwigSettings that specify a number of aspects used +    to configure building the Python binding with swig (mostly paths) +    """ +    if options.generate_dependency_file: +        temp_dep_file_path = dependency_file + ".tmp" + +    # Build the SWIG args list +    command = [ +        options.swig_executable, +        "-c++", +        "-shadow", +        "-python", +        "-threads", +        "-I\"%s\"" % os.path.normcase( +            os.path.join(options.src_root, "include")), +        "-I\"%s\"" % os.path.normcase("./."), +        "-D__STDC_LIMIT_MACROS", +        "-D__STDC_CONSTANT_MACROS"] +    if options.generate_dependency_file: +        command.append("-MMD -MF \"%s\"" % temp_dep_file_path) +    command.extend([ +        "-outdir", "\"%s\"" % config_build_dir, +        "-o", "\"%s\"" % settings.output_file, +        "\"%s\"" % settings.input_file +        ]) +    logging.info("running swig with: %s", command) + +    # Execute swig +    process = subprocess.Popen( +        ' '.join(command), +        stdout=subprocess.PIPE, +        stderr=subprocess.PIPE, +        shell=True) +    # Wait for SWIG process to terminate +    swig_stdout, swig_stderr = process.communicate() +    return_code = process.returncode +    if return_code != 0: +        logging.error( +            "swig failed with error code %d: stdout=%s, stderr=%s", +            return_code, +            swig_stdout, +            swig_stderr) +        logging.error( +            "command line:\n%s", ' '.join(command)) +        sys.exit(return_code) + +    logging.info("swig generation succeeded") +    if swig_stdout is not None and len(swig_stdout) > 0: +        logging.info("swig output: %s", swig_stdout) + +    # Move the depedency file we just generated to the proper location. +    if options.generate_dependency_file: +        if os.path.exists(temp_dep_file_path): +            shutil.move(temp_dep_file_path, dependency_file) +        else: +            logging.error( +                "failed to generate Python binding depedency file '%s'", +                temp_dep_file_path) +            if os.path.exists(dependency_file): +                # Delete the old one. +                os.remove(dependency_file) +            sys.exit(-10) + + +def run_python_script(script_and_args): +    """Runs a python script, logging appropriately. + +    If the command returns anything non-zero, it is registered as +    an error and exits the program. + +    @param script_and_args the python script to execute, along with +    the command line arguments to pass to it. +    """ +    command_line = "%s %s" % (sys.executable, script_and_args) +    process = subprocess.Popen(command_line, shell=True) +    script_stdout, script_stderr = process.communicate() +    return_code = process.returncode +    if return_code != 0: +        logging.error("failed to run '%s': %s", command_line, script_stderr) +        sys.exit(return_code) +    else: +        logging.info("ran script '%s'", command_line) +        if script_stdout is not None: +            logging.info("output: %s", script_stdout) + + +def do_modify_python_lldb(options, config_build_dir): +    """Executes the modify-python-lldb.py script. + +    @param options the parsed command line arguments +    @param config_build_dir the directory where the Python output was created. +    """ +    script_path = os.path.normcase( +        os.path.join( +            options.src_root, +            "scripts", +            "Python", +            "modify-python-lldb.py")) + +    if not os.path.exists(script_path): +        logging.error("failed to find python script: '%s'", script_path) +        sys.exit(-11) + +    script_invocation = "%s %s" % (script_path, config_build_dir) +    run_python_script(script_invocation) + + +def get_python_module_path(options): +    """Returns the location where the lldb Python module should be placed. + +    @param options dictionary of options parsed from the command line. + +    @return the directory where the lldb module should be placed. +    """ +    if options.framework: +        # Caller wants to use the OS X framework packaging. + +        # We are packaging in an OS X-style framework bundle. The +        # module dir will be within the +        # LLDB.framework/Resources/Python subdirectory. +        return os.path.join( +            options.target_dir, +            "LLDB.framework", +            "Resources", +            "Python", +            "lldb") +    else: +        from distutils.sysconfig import get_python_lib + +        if options.prefix is not None: +            module_path = get_python_lib(True, False, options.prefix) +        else: +            module_path = get_python_lib(True, False) +        return os.path.normcase( +            os.path.join(module_path, "lldb")) + + +def main(options): +    """Pepares the Python language binding to LLDB. + +    @param options the parsed command line argument dictionary +    """ +    # Setup generated dependency file options. +    if options.generate_dependency_file: +        dependency_file = os.path.normcase(os.path.join( +            options.target_dir, "LLDBWrapPython.cpp.d")) +    else: +        dependency_file = None + +    # Keep track of all the swig-related settings. +    settings = SwigSettings() + +    # Determine the final binding file path. +    settings.output_file = os.path.normcase( +        os.path.join(options.target_dir, "LLDBWrapPython.cpp")) + +    # Touch the output file (but don't really generate it) if python +    # is disabled. +    disable_python = os.getenv("LLDB_DISABLE_PYTHON", None) +    if disable_python is not None and disable_python == "1": +        remove_ignore_enoent(settings.output_file) +        # Touch the file. +        open(settings.output_file, 'w').close() +        logging.info( +            "Created empty python binding file due to LLDB_DISABLE_PYTHON " +            "being set") +        return + +    # We also check the GCC_PREPROCESSOR_DEFINITIONS to see if it +    # contains LLDB_DISABLE_PYTHON.  If so, we skip generating +    # the binding. +    gcc_preprocessor_defs = os.getenv("GCC_PREPROCESSOR_DEFINITIONS", None) +    if gcc_preprocessor_defs is not None: +        if re.search(r"LLDB_DISABLE_PYTHON", gcc_preprocessor_defs): +            remove_ignore_enoent(settings.output_file) +            # Touch the file +            open(settings.output_file, 'w').close() +            logging.info( +                "Created empty python binding file due to " +                "finding LLDB_DISABLE_PYTHON in GCC_PREPROCESSOR_DEFINITIONS") +            return + +    # Setup paths used during swig invocation. +    settings.input_file = os.path.normcase( +        os.path.join(options.src_root, "scripts", "lldb.swig")) +    scripts_python_dir = os.path.dirname(os.path.realpath(__file__)) +    settings.extensions_file = os.path.normcase( +        os.path.join(scripts_python_dir, "python-extensions.swig")) +    settings.wrapper_file = os.path.normcase( +        os.path.join(scripts_python_dir, "python-wrapper.swig")) +    settings.typemaps_file = os.path.normcase( +        os.path.join(scripts_python_dir, "python-typemaps.swig")) +    settings.safecast_file = os.path.normcase( +        os.path.join(scripts_python_dir, "python-swigsafecast.swig")) + +    settings.header_files = get_header_files(options) +    settings.interface_files = get_interface_files(options) + +    generate_output = settings.output_out_of_date() + +    # Determine where to put the module. +    python_module_path = get_python_module_path(options) +    logging.info("python module path: %s", python_module_path) + +    # Handle the configuration build dir. +    if options.config_build_dir is not None: +        config_build_dir = options.config_build_dir +    else: +        config_build_dir = python_module_path + +    # Allow missing/non-link _lldb.so to force regeneration. +    if not generate_output: +        # Ensure the _lldb.so file exists. +        so_path = os.path.join(python_module_path, "_lldb.so") +        if not os.path.exists(so_path) or not os.path.islink(so_path): +            logging.info("_lldb.so doesn't exist or isn't a symlink") +            generate_output = True + +    # Allow missing __init__.py to force regeneration. +    if not generate_output: +        # Ensure the __init__.py for the lldb module can be found. +        init_path = os.path.join(python_module_path, "__init__.py") +        if not os.path.exists(init_path): +            logging.info("__init__.py doesn't exist") +            generate_output = True + +    if not generate_output: +        logging.info( +            "Skipping Python binding generation: everything is up to date") +        return + +    # Generate the Python binding with swig. +    logging.info("Python binding is out of date, regenerating") +    do_swig_rebuild(options, dependency_file, config_build_dir, settings) +    if options.generate_dependency_file: +        return + +    # Post process the swig-generated file. +    do_modify_python_lldb(options, config_build_dir) + + +# This script can be called by another Python script by calling the main() +# function directly +if __name__ == "__main__": +    print("Script cannot be called directly.") +    sys.exit(-1) diff --git a/scripts/Python/python-extensions.swig b/scripts/Python/python-extensions.swig new file mode 100644 index 000000000000..fae7f401bf13 --- /dev/null +++ b/scripts/Python/python-extensions.swig @@ -0,0 +1,1087 @@ + +%extend lldb::SBAddress { +        PyObject *lldb::SBAddress::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBBlock { +        PyObject *lldb::SBBlock::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBBreakpoint { +        PyObject *lldb::SBBreakpoint::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} + +} +%extend lldb::SBBreakpointLocation { +        PyObject *lldb::SBBreakpointLocation::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelFull); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} + +%extend lldb::SBBroadcaster { +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} + +%extend lldb::SBCommandReturnObject { +        PyObject *lldb::SBCommandReturnObject::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +        /* the write() and flush() calls are not part of the SB API proper, and are solely for Python usage +        they are meant to make an SBCommandReturnObject into a file-like object so that instructions of the sort +        print >>sb_command_return_object, "something" +        will work correctly */ + +        void lldb::SBCommandReturnObject::write (const char* str) +        { +            if (str) +                $self->Printf("%s",str); +        } +        void lldb::SBCommandReturnObject::flush () +        {} +} +%extend lldb::SBCompileUnit { +        PyObject *lldb::SBCompileUnit::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBData { +        PyObject *lldb::SBData::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBDebugger { +        PyObject *lldb::SBDebugger::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBDeclaration { +        PyObject *lldb::SBDeclaration::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} + +} +%extend lldb::SBError { +        PyObject *lldb::SBError::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBFileSpec { +        PyObject *lldb::SBFileSpec::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBFrame { +        PyObject *lldb::SBFrame::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBFunction { +        PyObject *lldb::SBFunction::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} + +} +%extend lldb::SBInstruction { +        PyObject *lldb::SBInstruction::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBInstructionList { +        PyObject *lldb::SBInstructionList::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBLineEntry { +        PyObject *lldb::SBLineEntry::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBModule { +        PyObject *lldb::SBModule::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} + +%extend lldb::SBModuleSpec { +        PyObject *lldb::SBModuleSpec::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} + +%extend lldb::SBModuleSpecList { +        PyObject *lldb::SBModuleSpecList::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} + +%extend lldb::SBProcess { +        PyObject *lldb::SBProcess::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBSection { +        PyObject *lldb::SBSection::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +         +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBStream { +        /* the write() and flush() calls are not part of the SB API proper, and are solely for Python usage +        they are meant to make an SBStream into a file-like object so that instructions of the sort +        print >>sb_stream, "something" +        will work correctly */ + +        void lldb::SBStream::write (const char* str) +        { +            if (str) +                $self->Printf("%s",str); +        } +        void lldb::SBStream::flush () +        {} +} +%extend lldb::SBSymbol { +        PyObject *lldb::SBSymbol::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{ +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBSymbolContext { +        PyObject *lldb::SBSymbolContext::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBSymbolContextList { +        PyObject *lldb::SBSymbolContextList::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} + +%extend lldb::SBTarget { +        PyObject *lldb::SBTarget::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } + +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} + +%extend lldb::SBType { +        PyObject *lldb::SBType::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeCategory { +        PyObject *lldb::SBTypeCategory::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeFilter { +        PyObject *lldb::SBTypeFilter::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBTypeFormat { +        PyObject *lldb::SBTypeFormat::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeMember { +        PyObject *lldb::SBTypeMember::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeMemberFunction { +        PyObject *lldb::SBTypeMemberFunction::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeEnumMember { +        PyObject *lldb::SBTypeEnumMember::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBTypeNameSpecifier { +        PyObject *lldb::SBTypeNameSpecifier::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBTypeSummary { +        PyObject *lldb::SBTypeSummary::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBTypeSynthetic { +        PyObject *lldb::SBTypeSynthetic::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelBrief); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBThread { +        PyObject *lldb::SBThread::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +    %pythoncode %{  +        def __eq__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return False  +             +            return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) +             +        def __ne__(self, rhs): +            if not isinstance(rhs, type(self)):  +                return True  +             +            return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) +    %} +} +%extend lldb::SBValue { +        PyObject *lldb::SBValue::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBValueList { +        PyObject *lldb::SBValueList::__str__ (){ +                lldb::SBStream description; +                const size_t n = $self->GetSize(); +                if (n) +                { +                    for (size_t i=0; i<n; ++i) +                        $self->GetValueAtIndex(i).GetDescription(description); +                } +                else +                { +                    description.Printf("<empty> lldb.SBValueList()"); +                } +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} +%extend lldb::SBWatchpoint { +        PyObject *lldb::SBWatchpoint::__str__ (){ +                lldb::SBStream description; +                $self->GetDescription (description, lldb::eDescriptionLevelVerbose); +                const char *desc = description.GetData(); +                size_t desc_len = description.GetSize(); +                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) +                    --desc_len; +                if (desc_len > 0) +                    return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); +                else +                    return lldb_private::PythonString("").release(); +        } +} + + +// %extend lldb::SBDebugger { +//         // FIXME: We can't get the callback and baton +//         PyObject *lldb::SBDebugger (){ +//             // Only call Py_XDECREF if we have a Python object (or NULL) +//             if (LLDBSwigPythonCallPythonLogOutputCallback == $self->GetLogOutPutCallback()) +//                 Py_XDECREF($self->GetCallbackBaton()); +//         } +// } + +%pythoncode %{ + +def command(*args, **kwargs): +    import lldb +    """A decorator function that registers an LLDB command line +        command that is bound to the function it is attached to.""" +    class obj(object): +        """The object that tracks adding the command to LLDB one time and handles +            calling the function on subsequent calls.""" +        def __init__(self, function, command_name, doc = None): +            if doc: +                function.__doc__ = doc +            command = "command script add -f %s.%s %s" % (function.__module__, function.__name__, command_name) +            lldb.debugger.HandleCommand(command) +            self.function = function +        def __call__(self, *args, **kwargs): +            self.function(*args, **kwargs) +    def callable(function): +        """Creates a callable object that gets used.""" +        return obj(function, *args, **kwargs) +    return callable + +class declaration(object): +    '''A class that represents a source declaration location with file, line and column.''' +    def __init__(self, file, line, col): +        self.file = file +        self.line = line +        self.col = col + +class value_iter(object): +    def __iter__(self): +        return self +     +    def next(self): +        if self.index >= self.length: +            raise StopIteration() +        child_sbvalue = self.sbvalue.GetChildAtIndex(self.index) +        self.index += 1 +        return value(child_sbvalue) +         +    def __init__(self,value): +        self.index = 0 +        self.sbvalue = value +        if type(self.sbvalue) is value: +            self.sbvalue = self.sbvalue.sbvalue +        self.length = self.sbvalue.GetNumChildren() + +class value(object): +    '''A class designed to wrap lldb.SBValue() objects so the resulting object +    can be used as a variable would be in code. So if you have a Point structure +    variable in your code in the current frame named "pt", you can initialize an instance +    of this class with it: +     +    pt = lldb.value(lldb.frame.FindVariable("pt")) +    print pt +    print pt.x +    print pt.y + +    pt = lldb.value(lldb.frame.FindVariable("rectangle_array")) +    print rectangle_array[12] +    print rectangle_array[5].origin.x''' +    def __init__(self, sbvalue): +        self.sbvalue = sbvalue + +    def __nonzero__(self): +        return self.sbvalue.__nonzero__() + +    def __str__(self): +        return self.sbvalue.__str__() + +    def __getitem__(self, key): +        # Allow array access if this value has children... +        if type(key) is value: +            key = int(key) +        if type(key) is int: +            child_sbvalue = (self.sbvalue.GetValueForExpressionPath("[%i]" % key)) +            if child_sbvalue and child_sbvalue.IsValid(): +                return value(child_sbvalue) +            raise IndexError("Index '%d' is out of range" % key) +        raise TypeError("No array item of type %s" % str(type(key))) + +    def __iter__(self): +        return value_iter(self.sbvalue) + +    def __getattr__(self, name): +        child_sbvalue = self.sbvalue.GetChildMemberWithName (name) +        if child_sbvalue and child_sbvalue.IsValid(): +            return value(child_sbvalue) +        raise AttributeError("Attribute '%s' is not defined" % name) + +    def __add__(self, other): +        return int(self) + int(other) +         +    def __sub__(self, other): +        return int(self) - int(other) +         +    def __mul__(self, other): +        return int(self) * int(other) +         +    def __floordiv__(self, other): +        return int(self) // int(other) +         +    def __mod__(self, other): +        return int(self) % int(other) +         +    def __divmod__(self, other): +        return int(self) % int(other) +         +    def __pow__(self, other): +        return int(self) ** int(other) +         +    def __lshift__(self, other): +        return int(self) << int(other) +         +    def __rshift__(self, other): +        return int(self) >> int(other) +         +    def __and__(self, other): +        return int(self) & int(other) +         +    def __xor__(self, other): +        return int(self) ^ int(other) +         +    def __or__(self, other): +        return int(self) | int(other) +         +    def __div__(self, other): +        return int(self) / int(other) +         +    def __truediv__(self, other): +        return int(self) / int(other) +         +    def __iadd__(self, other): +        result = self.__add__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __isub__(self, other): +        result = self.__sub__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __imul__(self, other): +        result = self.__mul__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __idiv__(self, other): +        result = self.__div__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __itruediv__(self, other): +        result = self.__truediv__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ifloordiv__(self, other): +        result =  self.__floordiv__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __imod__(self, other): +        result =  self.__and__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ipow__(self, other): +        result = self.__pow__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ipow__(self, other, modulo): +        result = self.__pow__(self, other, modulo) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ilshift__(self, other): +        result = self.__lshift__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __irshift__(self, other): +        result =  self.__rshift__(other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __iand__(self, other): +        result =  self.__and__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ixor__(self, other): +        result =  self.__xor__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __ior__(self, other): +        result =  self.__ior__(self, other) +        self.sbvalue.SetValueFromCString (str(result)) +        return result +         +    def __neg__(self): +        return -int(self) +         +    def __pos__(self): +        return +int(self) +         +    def __abs__(self): +        return abs(int(self)) +         +    def __invert__(self): +        return ~int(self) +         +    def __complex__(self): +        return complex (int(self)) +         +    def __int__(self): +        return self.sbvalue.GetValueAsSigned() +         +    def __long__(self): +        return self.sbvalue.GetValueAsSigned() +         +    def __float__(self): +        return float (self.sbvalue.GetValueAsSigned()) +         +    def __oct__(self): +        return '0%o' % self.sbvalue.GetValueAsUnsigned() +         +    def __hex__(self): +        return '0x%x' % self.sbvalue.GetValueAsUnsigned() + +    def __len__(self): +        return self.sbvalue.GetNumChildren() + +    def __eq__(self, other): +        if type(other) is int: +                return int(self) == other +        elif type(other) is str: +                return str(self) == other +        elif type(other) is value: +                self_err = SBError() +                other_err = SBError() +                self_val = self.sbvalue.GetValueAsUnsigned(self_err) +                if self_err.fail: +                        raise ValueError("unable to extract value of self") +                other_val = other.sbvalue.GetValueAsUnsigned(other_err) +                if other_err.fail: +                        raise ValueError("unable to extract value of other") +                return self_val == other_val +        raise TypeError("Unknown type %s, No equality operation defined." % str(type(other))) + +    def __ne__(self, other): +        return not self.__eq__(other) +%} + +%pythoncode %{ + +class SBSyntheticValueProvider(object): +    def __init__(self,valobj): +        pass + +    def num_children(self): +        return 0 + +    def get_child_index(self,name): +        return None + +    def get_child_at_index(self,idx): +        return None + +    def update(self): +        pass + +    def has_children(self): +        return False + + +%}
\ No newline at end of file diff --git a/scripts/Python/python-swigsafecast.swig b/scripts/Python/python-swigsafecast.swig new file mode 100644 index 000000000000..ea3f21f859ad --- /dev/null +++ b/scripts/Python/python-swigsafecast.swig @@ -0,0 +1,142 @@ +// leaving this undefined ensures we will get a linker error if we try to use SBTypeToSWIGWrapper() +// for a type for which we did not specialze this function +template <typename SBClass> +PyObject* +SBTypeToSWIGWrapper (SBClass* sb_object); + +template <typename SBClass> +PyObject* +SBTypeToSWIGWrapper (SBClass& sb_object) +{ +    return SBTypeToSWIGWrapper(&sb_object); +} + +template <typename SBClass> +PyObject* +SBTypeToSWIGWrapper (const SBClass& sb_object) +{ +    return SBTypeToSWIGWrapper(&sb_object); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (PyObject* py_object) +{ +    return py_object; +} + +template <> +PyObject* +SBTypeToSWIGWrapper (const char* c_str) +{ +    if (c_str) +        return PyString_FromString(c_str); +    return NULL; +} + +template <> +PyObject* +SBTypeToSWIGWrapper (unsigned int* c_int) +{ +    if (!c_int) +        return NULL; +    return PyInt_FromLong(*c_int); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBEvent* event_sb) +{ +    return SWIG_NewPointerObj((void *) event_sb, SWIGTYPE_p_lldb__SBEvent, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBProcess* process_sb) +{ +    return SWIG_NewPointerObj((void *) process_sb, SWIGTYPE_p_lldb__SBProcess, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBThread* thread_sb) +{ +    return SWIG_NewPointerObj((void *) thread_sb, SWIGTYPE_p_lldb__SBThread, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBThreadPlan* thread_plan_sb) +{ +    return SWIG_NewPointerObj((void *) thread_plan_sb, SWIGTYPE_p_lldb__SBThreadPlan, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBTarget* target_sb) +{ +    return SWIG_NewPointerObj((void *) target_sb, SWIGTYPE_p_lldb__SBTarget, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBFrame* frame_sb) +{ +    return SWIG_NewPointerObj((void *) frame_sb, SWIGTYPE_p_lldb__SBFrame, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBDebugger* debugger_sb) +{ +    return SWIG_NewPointerObj((void *) debugger_sb, SWIGTYPE_p_lldb__SBDebugger, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBBreakpoint* breakpoint_sb) +{ +    return SWIG_NewPointerObj((void *) breakpoint_sb, SWIGTYPE_p_lldb__SBBreakpoint, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBWatchpoint* watchpoint_sb) +{ +    return SWIG_NewPointerObj((void *) watchpoint_sb, SWIGTYPE_p_lldb__SBWatchpoint, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBBreakpointLocation* breakpoint_location_sb) +{ +    return SWIG_NewPointerObj((void *) breakpoint_location_sb, SWIGTYPE_p_lldb__SBBreakpointLocation, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBValue* value_sb) +{ +    return SWIG_NewPointerObj((void *) value_sb, SWIGTYPE_p_lldb__SBValue, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBCommandReturnObject* cmd_ret_obj_sb) +{ +    return SWIG_NewPointerObj((void *) cmd_ret_obj_sb, SWIGTYPE_p_lldb__SBCommandReturnObject, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBExecutionContext* ctx_sb) +{ +    return SWIG_NewPointerObj((void *) ctx_sb, SWIGTYPE_p_lldb__SBExecutionContext, 0); +} + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBTypeSummaryOptions* summary_options_sb) +{ +    return SWIG_NewPointerObj((void *) summary_options_sb, SWIGTYPE_p_lldb__SBTypeSummaryOptions, 0); +} diff --git a/scripts/Python/python-typemaps.swig b/scripts/Python/python-typemaps.swig new file mode 100644 index 000000000000..ec9302a15cd7 --- /dev/null +++ b/scripts/Python/python-typemaps.swig @@ -0,0 +1,601 @@ +/* Typemap definitions, to allow SWIG to properly handle 'char**' data types. */ + +%typemap(in) char ** { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $1 = (char **) malloc((size+1) * sizeof(char*)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyString_Check(o)) +        $1[i] = PyString_AsString(o); +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain strings"); +        free($1); +        return NULL; +      } +    } +    $1[i] = 0; +  } else if ($input == Py_None) { +    $1 =  NULL; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(in) lldb::tid_t { +    if (PyInt_Check($input)) +        $1 = PyInt_AsLong($input); +    else if (PyLong_Check($input)) +        $1 = PyLong_AsLongLong($input); +    else +    { +        PyErr_SetString(PyExc_ValueError, "Expecting an integer"); +        return NULL; +    } +} + +%typemap(typecheck) char ** { +  /* Check if is a list  */ +  $1 = 1; +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (!PyString_Check(o)) { $1 = 0; } +    } +  } +  else +  { +    $1 = ( ($input == Py_None) ? 1 : 0); +  } +} + +%typemap(freearg) char** { +  free((char *) $1); +} + +%typemap(out) char** { +  int len; +  int i; +  len = 0; +  while ($1[len]) len++; +  using namespace lldb_private; +  PythonList list(len); +  for (i = 0; i < len; i++) +    list.SetItemAtIndex(i, PythonString($1[i])); +  $result = list.release(); +} + +%typemap(in) char const ** { +  /* Check if is a list  */ +  using namespace lldb_private; +  if (PythonList::Check($input)) { +    PythonList py_list(PyRefType::Borrowed, $input); +    int size = py_list.GetSize(); + +    $1 = (char**)malloc((size+1)*sizeof(char*)); +    for (int i = 0; i < size; i++) { +      PythonObject o = py_list.GetItemAtIndex(i); +      if (!PythonString::Check(o.get())) { +        PyErr_SetString(PyExc_TypeError,"list must contain strings"); +        free($1); +        return nullptr; +      } +      auto py_str = o.AsType<PythonString>(); +      $1[i] = const_cast<char*>(py_str.GetString().data()); +    } + +    $1[size] = 0; +  } else if ($input == Py_None) { +    $1 = nullptr; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return nullptr; +  } +} + +%typemap(typecheck) char const ** { +  /* Check if is a list  */ +  $1 = 1; +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (!PyString_Check(o)) { $1 = 0; } +    } +  } +  else +  { +    $1 = ( ($input == Py_None) ? 1 : 0); +  } +} + +%typemap(freearg) char const ** { +  free((char *) $1); +} + +%typemap(out) char const ** { +  int len; +  int i; +  len = 0; +  while ($1[len]) len++; +  $result = PyList_New(len); +  for (i = 0; i < len; i++) { +    PyList_SetItem($result, i, PyString_FromString($1[i])); +  } +} + +/* Typemap definitions to allow SWIG to properly handle char buffer. */ + +// typemap for a char buffer +// See also SBThread::GetStopDescription. +%typemap(in) (char *dst, size_t dst_len) { +   if (!PyInt_Check($input)) { +       PyErr_SetString(PyExc_ValueError, "Expecting an integer"); +       return NULL; +   } +   $2 = PyInt_AsLong($input); +   if ($2 <= 0) { +       PyErr_SetString(PyExc_ValueError, "Positive integer expected"); +       return NULL; +   } +   $1 = (char *) malloc($2); +} + +// Return the char buffer.  Discarding any previous return result +// See also SBThread::GetStopDescription. +%typemap(argout) (char *dst, size_t dst_len) { +   Py_XDECREF($result);   /* Blow away any previous result */ +   if (result == 0) { +      $result = Py_None; +      Py_INCREF($result); +   } else { +      llvm::StringRef ref(static_cast<const char*>($1), result); +      lldb_private::PythonString string(ref); +      $result = string.release(); +   } +   free($1); +} + + +// typemap for an outgoing buffer +// See also SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len). +%typemap(in) (const char *cstr, uint32_t cstr_len) { +   if (PyString_Check($input)) { +      $1 = (char *) PyString_AsString($input); +      $2 = PyString_Size($input); +   } +   else if(PyByteArray_Check($input)) { +      $1 = (char *) PyByteArray_AsString($input); +      $2 = PyByteArray_Size($input); +   } +   else { +      PyErr_SetString(PyExc_ValueError, "Expecting a string"); +      return NULL; +   } +} +// Ditto for SBProcess::PutSTDIN(const char *src, size_t src_len). +%typemap(in) (const char *src, size_t src_len) { +   if (PyString_Check($input)) { +      $1 = (char *) PyString_AsString($input); +      $2 = PyString_Size($input); +   } +   else if(PyByteArray_Check($input)) { +      $1 = (char *) PyByteArray_AsString($input); +      $2 = PyByteArray_Size($input); +   } +   else { +      PyErr_SetString(PyExc_ValueError, "Expecting a string"); +      return NULL; +   } +} +// And SBProcess::WriteMemory. +%typemap(in) (const void *buf, size_t size) { +   if (PyString_Check($input)) { +      $1 = (void *) PyString_AsString($input); +      $2 = PyString_Size($input); +   } +   else if(PyByteArray_Check($input)) { +      $1 = (void *) PyByteArray_AsString($input); +      $2 = PyByteArray_Size($input); +   } +   else { +      PyErr_SetString(PyExc_ValueError, "Expecting a string"); +      return NULL; +   } +} + +// For SBDebugger::DispatchInput +%typemap(in) (const void *data, size_t data_len) { +   if (PyString_Check($input)) { +      $1 = static_cast<void *>(PyString_AsString($input)); +      $2 = PyString_Size($input); +   } +   else if(PyByteArray_Check($input)) { +      $1 = static_cast<void *>(PyByteArray_AsString($input)); +      $2 = PyByteArray_Size($input); +   } +   else { +      PyErr_SetString(PyExc_ValueError, "Expecting a string or byte array"); +      return NULL; +   } +} + +// typemap for an incoming buffer +// See also SBProcess::ReadMemory. +%typemap(in) (void *buf, size_t size) { +   if (PyInt_Check($input)) { +      $2 = PyInt_AsLong($input); +   } else if (PyLong_Check($input)) { +      $2 = PyLong_AsLong($input); +   } else { +      PyErr_SetString(PyExc_ValueError, "Expecting an integer or long object"); +      return NULL; +   } +   if ($2 <= 0) { +       PyErr_SetString(PyExc_ValueError, "Positive integer expected"); +       return NULL; +   } +   $1 = (void *) malloc($2); +} + +// Return the buffer.  Discarding any previous return result +// See also SBProcess::ReadMemory. +%typemap(argout) (void *buf, size_t size) { +   Py_XDECREF($result);   /* Blow away any previous result */ +   if (result == 0) { +      $result = Py_None; +      Py_INCREF($result); +   } else { +      llvm::StringRef ref(static_cast<const char*>($1), result); +      lldb_private::PythonString string(ref); +      $result = string.release(); +   } +   free($1); +} + +// these typemaps allow Python users to pass list objects +// and have them turn into C++ arrays (this is useful, for instance +// when creating SBData objects from lists of numbers) +%typemap(in) (uint64_t* array, size_t array_len) { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $2 = size; +    $1 = (uint64_t*) malloc(size * sizeof(uint64_t)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyInt_Check(o)) { +        $1[i] = PyInt_AsLong(o); +      } +      else if (PyLong_Check(o)) { +        $1[i] = PyLong_AsUnsignedLongLong(o); +      } +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain numbers"); +        free($1); +        return NULL; +      } + +      if (PyErr_Occurred()) { +        free($1); +        return NULL; +      } +    } +  } else if ($input == Py_None) { +    $1 =  NULL; +    $2 = 0; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(freearg) (uint64_t* array, size_t array_len) { +  free($1); +} + +%typemap(in) (uint32_t* array, size_t array_len) { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $2 = size; +    $1 = (uint32_t*) malloc(size * sizeof(uint32_t)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyInt_Check(o)) { +        $1[i] = PyInt_AsLong(o); +      } +      else if (PyLong_Check(o)) { +        $1[i] = PyLong_AsUnsignedLong(o); +      } +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain numbers"); +        free($1); +        return NULL; +      } + +      if (PyErr_Occurred()) { +        free($1); +        return NULL; +      } +    } +  } else if ($input == Py_None) { +    $1 =  NULL; +    $2 = 0; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(freearg) (uint32_t* array, size_t array_len) { +  free($1); +} + +%typemap(in) (int64_t* array, size_t array_len) { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $2 = size; +    $1 = (int64_t*) malloc(size * sizeof(int64_t)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyInt_Check(o)) { +        $1[i] = PyInt_AsLong(o); +      } +      else if (PyLong_Check(o)) { +        $1[i] = PyLong_AsLongLong(o); +      } +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain numbers"); +        free($1); +        return NULL; +      } + +      if (PyErr_Occurred()) { +        free($1); +        return NULL; +      } +    } +  } else if ($input == Py_None) { +    $1 =  NULL; +    $2 = 0; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(freearg) (int64_t* array, size_t array_len) { +  free($1); +} + +%typemap(in) (int32_t* array, size_t array_len) { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $2 = size; +    $1 = (int32_t*) malloc(size * sizeof(int32_t)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyInt_Check(o)) { +        $1[i] = PyInt_AsLong(o); +      } +      else if (PyLong_Check(o)) { +        $1[i] = PyLong_AsLong(o); +      } +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain numbers"); +        free($1); +        return NULL; +      } + +      if (PyErr_Occurred()) { +        free($1); +        return NULL; +      } +    } +  } else if ($input == Py_None) { +    $1 =  NULL; +    $2 = 0; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(freearg) (int32_t* array, size_t array_len) { +  free($1); +} + +%typemap(in) (double* array, size_t array_len) { +  /* Check if is a list  */ +  if (PyList_Check($input)) { +    int size = PyList_Size($input); +    int i = 0; +    $2 = size; +    $1 = (double*) malloc(size * sizeof(double)); +    for (i = 0; i < size; i++) { +      PyObject *o = PyList_GetItem($input,i); +      if (PyFloat_Check(o)) { +        $1[i] = PyFloat_AsDouble(o); +      } +      else { +        PyErr_SetString(PyExc_TypeError,"list must contain floating-point numbers"); +        free($1); +        return NULL; +      } +    } +  } else if ($input == Py_None) { +    $1 =  NULL; +    $2 = 0; +  } else { +    PyErr_SetString(PyExc_TypeError,"not a list"); +    return NULL; +  } +} + +%typemap(freearg) (double* array, size_t array_len) { +  free($1); +} + +// these typemaps wrap SBModule::GetVersion() from requiring a memory buffer +// to the more Pythonic style where a list is returned and no previous allocation +// is necessary - this will break if more than 50 versions are ever returned +%typemap(typecheck) (uint32_t *versions, uint32_t num_versions) { +    $1 = ($input == Py_None ? 1 : 0); +} + +%typemap(in, numinputs=0) (uint32_t *versions) { +    $1 = (uint32_t*)malloc(sizeof(uint32_t) * 50); +} + +%typemap(in, numinputs=0) (uint32_t num_versions) { +    $1 = 50; +} + +%typemap(argout) (uint32_t *versions, uint32_t num_versions) { +    uint32_t count = result; +    if (count >= $2) +        count = $2; +    PyObject* list = PyList_New(count); +    for (uint32_t j = 0; j < count; j++) +    { +        if ($1[j] < UINT32_MAX) +        { +            PyObject* item = PyInt_FromLong($1[j]); +            int ok = PyList_SetItem(list,j,item); +            if (ok != 0) +            { +                $result = Py_None; +                break; +            } +        } +        else +            break; +    } +    $result = list; +} + +%typemap(freearg) (uint32_t *versions) { +    free($1); +} + + +// For Log::LogOutputCallback +%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) { +  if (!($input == Py_None || PyCallable_Check(reinterpret_cast<PyObject*>($input)))) { +    PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); +    return NULL; +  } + +  // FIXME (filcab): We can't currently check if our callback is already +  // LLDBSwigPythonCallPythonLogOutputCallback (to DECREF the previous +  // baton) nor can we just remove all traces of a callback, if we want to +  // revert to a file logging mechanism. + +  // Don't lose the callback reference +  Py_INCREF($input); +  $1 = LLDBSwigPythonCallPythonLogOutputCallback; +  $2 = $input; +} + +%typemap(typecheck) (lldb::LogOutputCallback log_callback, void *baton) { +  $1 = $input == Py_None; +  $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject*>($input)); +} + +%typemap(in) FILE * { +   using namespace lldb_private; +   if ($input == Py_None) +      $1 = nullptr; +   else if (!lldb_private::PythonFile::Check($input)) { +      int fd = PyObject_AsFileDescriptor($input); +      PythonObject py_input(PyRefType::Borrowed, $input); +      PythonString py_mode = py_input.GetAttributeValue("mode").AsType<PythonString>(); + +      if (-1 != fd && py_mode.IsValid()) { +         FILE *f; +         if ((f = fdopen(fd, py_mode.GetString().str().c_str()))) +            $1 = f; +         else +            PyErr_SetString(PyExc_TypeError, strerror(errno)); +      } else { +         PyErr_SetString(PyExc_TypeError,"not a file-like object"); +         return nullptr; +      } +   } +   else +   { +      PythonFile py_file(PyRefType::Borrowed, $input); +      File file; +      if (!py_file.GetUnderlyingFile(file)) +         return nullptr; + +      $1 = file.GetStream(); +   } +} + +%typemap(out) FILE * { +   char mode[4] = {0}; +#ifdef __MACOSX__ +   int i = 0; +   short flags = $1->_flags; + +   if (flags & __SRD) +      mode[i++] = 'r'; +   else if (flags & __SWR) +      mode[i++] = 'w'; +   else // if (flags & __SRW) +      mode[i++] = 'a'; +#endif +   using namespace lldb_private; +   File file($1, false); +   PythonFile py_file(file, mode); +   $result = py_file.release(); +   if (!$result) +   { +       $result = Py_None; +       Py_INCREF(Py_None); +   } +} + +%typemap(in) (const char* string, int len) { +    using namespace lldb_private; +    if ($input == Py_None) +    { +        $1 = NULL; +        $2 = 0; +    } +    else if (PythonString::Check($input)) +    { +        PythonString py_str(PyRefType::Borrowed, $input); +        llvm::StringRef str = py_str.GetString(); +        $1 = const_cast<char*>(str.data()); +        $2 = str.size(); +        // In Python 2, if $input is a PyUnicode object then this +        // will trigger a Unicode -> String conversion, in which +        // case the `PythonString` will now own the PyString.  Thus +        // if it goes out of scope, the data will be deleted.  The +        // only way to avoid this is to leak the Python object in +        // that case.  Note that if there was no conversion, then +        // releasing the string will not leak anything, since we +        // created this as a borrowed reference. +        py_str.release(); +    } +    else +    { +        PyErr_SetString(PyExc_TypeError,"not a string-like object"); +        return NULL; +    } +} diff --git a/scripts/Python/python-wrapper.swig b/scripts/Python/python-wrapper.swig new file mode 100644 index 000000000000..5d7bfaa89439 --- /dev/null +++ b/scripts/Python/python-wrapper.swig @@ -0,0 +1,936 @@ +%header %{ + +template <typename T> +PyObject * +SBTypeToSWIGWrapper (T* item); + +class PyErr_Cleaner +{ +public: +    PyErr_Cleaner(bool print=false) : +    m_print(print) +    { +    } + +    ~PyErr_Cleaner() +    { +        if (PyErr_Occurred()) +        { +            if(m_print && !PyErr_ExceptionMatches(PyExc_SystemExit)) +                PyErr_Print(); +            PyErr_Clear(); +        } +    } + +private: +    bool m_print; +}; + +%} + +%wrapper %{ + +// resolve a dotted Python name in the form +// foo.bar.baz.Foobar to an actual Python object +// if pmodule is NULL, the __main__ module will be used +// as the starting point for the search + + +// This function is called by lldb_private::ScriptInterpreterPython::BreakpointCallbackFunction(...) +// and is used when a script command is attached to a breakpoint for execution. + +SWIGEXPORT bool +LLDBSwigPythonBreakpointCallbackFunction +( +    const char *python_function_name, +    const char *session_dictionary_name, +    const lldb::StackFrameSP& frame_sp, +    const lldb::BreakpointLocationSP& bp_loc_sp +) +{ +    using namespace lldb_private; +    lldb::SBFrame sb_frame (frame_sp); +    lldb::SBBreakpointLocation sb_bp_loc(bp_loc_sp); + +    bool stop_at_breakpoint = true; + +    PyErr_Cleaner py_err_cleaner(true); +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return stop_at_breakpoint; + +    PythonObject frame_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_frame)); +    PythonObject bp_loc_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_bp_loc)); +    PythonObject result = pfunc(frame_arg, bp_loc_arg, dict); + +    if (result.get() == Py_False) +        stop_at_breakpoint = false; + +    return stop_at_breakpoint; +} + +// This function is called by lldb_private::ScriptInterpreterPython::WatchpointCallbackFunction(...) +// and is used when a script command is attached to a watchpoint for execution. + +SWIGEXPORT bool +LLDBSwigPythonWatchpointCallbackFunction +( +    const char *python_function_name, +    const char *session_dictionary_name, +    const lldb::StackFrameSP& frame_sp, +    const lldb::WatchpointSP& wp_sp +) +{ +    using namespace lldb_private; +    lldb::SBFrame sb_frame (frame_sp); +    lldb::SBWatchpoint sb_wp(wp_sp); + +    bool stop_at_watchpoint = true; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return stop_at_watchpoint; + +    PythonObject frame_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_frame)); +    PythonObject wp_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_wp)); +    PythonObject result = pfunc(frame_arg, wp_arg, dict); + +    if (result.get() == Py_False) +        stop_at_watchpoint = false; + +    return stop_at_watchpoint; +} + +SWIGEXPORT bool +LLDBSwigPythonCallTypeScript +( +    const char *python_function_name, +    const void *session_dictionary, +    const lldb::ValueObjectSP& valobj_sp, +    void** pyfunct_wrapper, +    const lldb::TypeSummaryOptionsSP& options_sp, +    std::string& retval +) +{ +    using namespace lldb_private; +    lldb::SBValue sb_value (valobj_sp); +    lldb::SBTypeSummaryOptions sb_options(options_sp.get()); + +    retval.clear(); + +    if (!python_function_name || !session_dictionary) +        return false; + +    PyObject *pfunc_impl = nullptr; + +    if (pyfunct_wrapper && *pyfunct_wrapper && PyFunction_Check (*pyfunct_wrapper)) +    { +        pfunc_impl = (PyObject*)(*pyfunct_wrapper); +        if (pfunc_impl->ob_refcnt == 1) +        { +            Py_XDECREF(pfunc_impl); +            pfunc_impl = NULL; +        } +    } + +    PyObject *py_dict = (PyObject*)session_dictionary; +    if (!PythonDictionary::Check(py_dict)) +        return true; + +    PythonDictionary dict(PyRefType::Borrowed, py_dict); + +    PyErr_Cleaner pyerr_cleanup(true);  // show Python errors + +    PythonCallable pfunc(PyRefType::Borrowed, pfunc_impl); + +    if (!pfunc.IsAllocated()) +    { +        pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); +        if (!pfunc.IsAllocated()) +            return false; + +        if (pyfunct_wrapper) +        { +            *pyfunct_wrapper = pfunc.get(); +            Py_XINCREF(pfunc.get()); +        } +    } + +    PythonObject result; +    auto argc = pfunc.GetNumArguments(); +    // if the third argument is supported, or varargs are allowed +    PythonObject value_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_value)); +    PythonObject options_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_options)); +    if (argc.count == 3 || argc.has_varargs) +        result = pfunc(value_arg,dict,options_arg); +    else +        result = pfunc(value_arg,dict); + +    retval = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT void* +LLDBSwigPythonCreateSyntheticProvider +( +    const char *python_class_name, +    const char *session_dictionary_name, +    const lldb::ValueObjectSP& valobj_sp +) +{ +    using namespace lldb_private; + +    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) +        Py_RETURN_NONE; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name,dict); + +    if (!pfunc.IsAllocated()) +        Py_RETURN_NONE; + +    // I do not want the SBValue to be deallocated when going out of scope because python +    // has ownership of it and will manage memory for this object by itself +    lldb::SBValue *sb_value = new lldb::SBValue(valobj_sp); +    sb_value->SetPreferSyntheticValue(false); + +    PythonObject val_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_value)); +    if (!val_arg.IsAllocated()) +        Py_RETURN_NONE; + +    PythonObject result = pfunc(val_arg, dict); + +    if (result.IsAllocated()) +        return result.release(); + +    Py_RETURN_NONE; +} + +SWIGEXPORT void* +LLDBSwigPythonCreateCommandObject +( +    const char *python_class_name, +    const char *session_dictionary_name, +    const lldb::DebuggerSP debugger_sp +) +{ +    using namespace lldb_private; + +    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) +        Py_RETURN_NONE; + +    PyErr_Cleaner py_err_cleaner(true); +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict); + +    if (!pfunc.IsAllocated()) +        return nullptr; + +    lldb::SBDebugger debugger_sb(debugger_sp); +    PythonObject debugger_arg(PyRefType::Owned, SBTypeToSWIGWrapper(debugger_sb)); +    PythonObject result = pfunc(debugger_arg, dict); + +    if (result.IsAllocated()) +        return result.release(); + +    Py_RETURN_NONE; +} + +SWIGEXPORT void* +LLDBSwigPythonCreateScriptedThreadPlan +( +    const char *python_class_name, +    const char *session_dictionary_name, +    const lldb::ThreadPlanSP& thread_plan_sp +) +{ +    using namespace lldb_private; + +    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) +        Py_RETURN_NONE; + +    // I do not want the SBThreadPlan to be deallocated when going out of scope because python +    // has ownership of it and will manage memory for this object by itself +    lldb::SBThreadPlan *tp_value = new lldb::SBThreadPlan(thread_plan_sp); + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict); + +    if (!pfunc.IsAllocated()) +        return nullptr; + +    PythonObject tp_arg(PyRefType::Owned, SBTypeToSWIGWrapper(tp_value)); + +    if (!tp_arg.IsAllocated()) +        Py_RETURN_NONE; + +    PythonObject result = pfunc(tp_arg, dict); +    // FIXME: At this point we should check that the class we found supports all the methods +    // that we need. + +    if (result.IsAllocated()) +        return result.release(); +    Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSWIGPythonCallThreadPlan +( +    void *implementor, +    const char *method_name, +    lldb_private::Event *event, +    bool &got_error +) +{ +    using namespace lldb_private; + +    got_error = false; + +    PyErr_Cleaner py_err_cleaner(false); +    PythonObject self(PyRefType::Borrowed, static_cast<PyObject*>(implementor)); +    auto pfunc = self.ResolveName<PythonCallable>(method_name); + +    if (!pfunc.IsAllocated()) +        return false; + +    PythonObject result; +    if (event != nullptr) +    { +        lldb::SBEvent sb_event(event); +        PythonObject event_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_event)); +        result = pfunc(event_arg); +    } +    else +        result = pfunc(); + +    if (PyErr_Occurred()) +    { +        got_error = true; +        printf ("Return value was neither false nor true for call to %s.\n", method_name); +        PyErr_Print(); +        return false; +    } + +    if (result.get() == Py_True) +        return true; +    else if (result.get() == Py_False) +        return false; + +    // Somebody returned the wrong thing... +    got_error = true; +    printf ("Wrong return value type for call to %s.\n", method_name); +    return false; +} + +// wrapper that calls an optional instance member of an object taking no arguments +static PyObject* +LLDBSwigPython_CallOptionalMember +( +    PyObject* implementor, +    char* callee_name, +    PyObject* ret_if_not_found = Py_None, +    bool* was_found = NULL +) +{ +    using namespace lldb_private; + +    PyErr_Cleaner py_err_cleaner(false); + +    PythonObject self(PyRefType::Borrowed, static_cast<PyObject*>(implementor)); +    auto pfunc = self.ResolveName<PythonCallable>(callee_name); + +    if (!pfunc.IsAllocated()) +    { +        if (was_found) +            *was_found = false; +        Py_XINCREF(ret_if_not_found); +        return ret_if_not_found; +    } + +    if (was_found) +        *was_found = true; + +    PythonObject result = pfunc(); +    return result.release(); +} + +SWIGEXPORT size_t +LLDBSwigPython_CalculateNumChildren +( +    PyObject *implementor, +    uint32_t max +) +{ +    using namespace lldb_private; + +    PythonObject self(PyRefType::Borrowed, implementor); +    auto pfunc = self.ResolveName<PythonCallable>("num_children"); + +    if (!pfunc.IsAllocated()) +        return 0; + +    PythonObject result; +    auto argc = pfunc.GetNumArguments(); +    if (argc.count == 1) +        result = pfunc(); +    else if (argc.count == 2) +        result = pfunc(PythonInteger(max)); + +    if (!result.IsAllocated()) +        return 0; + +    PythonInteger int_result = result.AsType<PythonInteger>(); +    if (!int_result.IsAllocated()) +        return 0; + +    size_t ret_val = int_result.GetInteger(); + +    if (PyErr_Occurred()) +    { +        PyErr_Print(); +        PyErr_Clear(); +    } + +    if (argc.count == 1) +        ret_val = std::min(ret_val, static_cast<size_t>(max)); + +    return ret_val; +} + +SWIGEXPORT PyObject* +LLDBSwigPython_GetChildAtIndex +( +    PyObject *implementor, +    uint32_t idx +) +{ +    using namespace lldb_private; +    PyErr_Cleaner py_err_cleaner(true); + +    PythonObject self(PyRefType::Borrowed, implementor); +    auto pfunc = self.ResolveName<PythonCallable>("get_child_at_index"); + +    if (!pfunc.IsAllocated()) +        return nullptr; + +    PythonObject result = pfunc(PythonInteger(idx)); + +    if (!result.IsAllocated()) +        return nullptr; + +    lldb::SBValue* sbvalue_ptr = nullptr; +    if (SWIG_ConvertPtr(result.get(), (void**)&sbvalue_ptr, SWIGTYPE_p_lldb__SBValue, 0) == -1) +        return nullptr; + +    if (sbvalue_ptr == nullptr) +        return nullptr; + +    return result.release(); +} + +SWIGEXPORT int +LLDBSwigPython_GetIndexOfChildWithName +( +    PyObject *implementor, +    const char* child_name +) +{ +    using namespace lldb_private; +    PyErr_Cleaner py_err_cleaner(true); + +    PythonObject self(PyRefType::Borrowed, implementor); +    auto pfunc = self.ResolveName<PythonCallable>("get_child_index"); + +    if (!pfunc.IsAllocated()) +        return UINT32_MAX; + +    PythonObject result = pfunc(PythonString(child_name)); + +    if (!result.IsAllocated()) +        return UINT32_MAX; + +    PythonInteger int_result = result.AsType<PythonInteger>(); +    if (!int_result.IsAllocated()) +        return UINT32_MAX; + +    int64_t retval = int_result.GetInteger(); +    if (retval >= 0) +        return (uint32_t)retval; + +    return UINT32_MAX; +} + +SWIGEXPORT bool +LLDBSwigPython_UpdateSynthProviderInstance +( +    PyObject *implementor +) +{ +    bool ret_val = false; + +    static char callee_name[] = "update"; + +    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name); + +    if (py_return == Py_True) +        ret_val = true; + +    Py_XDECREF(py_return); + +    return ret_val; +} + +SWIGEXPORT bool +LLDBSwigPython_MightHaveChildrenSynthProviderInstance +( +    PyObject *implementor +) +{ +    bool ret_val = false; + +    static char callee_name[] = "has_children"; + +    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, Py_True); + +    if (py_return == Py_True) +        ret_val = true; + +    Py_XDECREF(py_return); + +    return ret_val; +} + +SWIGEXPORT PyObject* +LLDBSwigPython_GetValueSynthProviderInstance +( +    PyObject *implementor +) +{ +    PyObject* ret_val = nullptr; + +    static char callee_name[] = "get_value"; + +    PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, Py_None); + +    if (py_return == Py_None || py_return == nullptr) +        ret_val = nullptr; + +    lldb::SBValue* sbvalue_ptr = NULL; + +    if (SWIG_ConvertPtr(py_return, (void**)&sbvalue_ptr, SWIGTYPE_p_lldb__SBValue, 0) == -1) +        ret_val = nullptr; +    else if (sbvalue_ptr == NULL) +        ret_val = nullptr; +    else +        ret_val = py_return; + +    Py_XDECREF(py_return); +    return ret_val; +} + +SWIGEXPORT void* +LLDBSWIGPython_CastPyObjectToSBValue +( +    PyObject* data +) +{ +    lldb::SBValue* sb_ptr = NULL; + +    int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBValue, 0); + +    if (valid_cast == -1) +        return NULL; + +    return sb_ptr; +} + +// Currently, SBCommandReturnObjectReleaser wraps a unique pointer to an +// lldb_private::CommandReturnObject. This means that the destructor for the +// SB object will deallocate its contained CommandReturnObject. Because that +// object is used as the real return object for Python-based commands, we want +// it to stay around. Thus, we release the unique pointer before returning from +// LLDBSwigPythonCallCommand, and to guarantee that the release will occur no +// matter how we exit from the function, we have a releaser object whose +// destructor does the right thing for us +class SBCommandReturnObjectReleaser +{ +public: +    SBCommandReturnObjectReleaser (lldb::SBCommandReturnObject &obj) : +        m_command_return_object_ref (obj) +    { +    } + +    ~SBCommandReturnObjectReleaser () +    { +        m_command_return_object_ref.Release(); +    } +private: +    lldb::SBCommandReturnObject &m_command_return_object_ref; +}; + +SWIGEXPORT bool +LLDBSwigPythonCallCommand +( +    const char *python_function_name, +    const char *session_dictionary_name, +    lldb::DebuggerSP& debugger, +    const char* args, +    lldb_private::CommandReturnObject& cmd_retobj, +    lldb::ExecutionContextRefSP exe_ctx_ref_sp +) +{ +    using namespace lldb_private; +    lldb::SBCommandReturnObject cmd_retobj_sb(&cmd_retobj); +    SBCommandReturnObjectReleaser cmd_retobj_sb_releaser(cmd_retobj_sb); +    lldb::SBDebugger debugger_sb(debugger); +    lldb::SBExecutionContext exe_ctx_sb(exe_ctx_ref_sp); + +    PyErr_Cleaner py_err_cleaner(true); +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    // pass the pointer-to cmd_retobj_sb or watch the underlying object disappear from under you +    // see comment above for SBCommandReturnObjectReleaser for further details +    auto argc = pfunc.GetNumArguments(); +    PythonObject debugger_arg(PyRefType::Owned, SBTypeToSWIGWrapper(debugger_sb)); +    PythonObject exe_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(exe_ctx_sb)); +    PythonObject cmd_retobj_arg(PyRefType::Owned, SBTypeToSWIGWrapper(&cmd_retobj_sb)); + +    if (argc.count == 5 || argc.has_varargs) +        pfunc(debugger_arg, PythonString(args), exe_ctx_arg, cmd_retobj_arg, dict); +    else +        pfunc(debugger_arg, PythonString(args), cmd_retobj_arg, dict); + +    return true; +} + +SWIGEXPORT bool +LLDBSwigPythonCallCommandObject +( +    PyObject *implementor, +    lldb::DebuggerSP& debugger, +    const char* args, +    lldb_private::CommandReturnObject& cmd_retobj, +    lldb::ExecutionContextRefSP exe_ctx_ref_sp +) +{ +    using namespace lldb_private; +    lldb::SBCommandReturnObject cmd_retobj_sb(&cmd_retobj); +    SBCommandReturnObjectReleaser cmd_retobj_sb_releaser(cmd_retobj_sb); +    lldb::SBDebugger debugger_sb(debugger); +    lldb::SBExecutionContext exe_ctx_sb(exe_ctx_ref_sp); + +    PyErr_Cleaner py_err_cleaner(true); + +    PythonObject self(PyRefType::Borrowed, implementor); +    auto pfunc = self.ResolveName<PythonCallable>("__call__"); + +    if (!pfunc.IsAllocated()) +        return false; + +    // pass the pointer-to cmd_retobj_sb or watch the underlying object disappear from under you +    // see comment above for SBCommandReturnObjectReleaser for further details +    PythonObject debugger_arg(PyRefType::Owned, SBTypeToSWIGWrapper(debugger_sb)); +    PythonObject exe_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(exe_ctx_sb)); +    PythonObject cmd_retobj_arg(PyRefType::Owned, SBTypeToSWIGWrapper(&cmd_retobj_sb)); + +    pfunc(debugger_arg, PythonString(args), exe_ctx_arg, cmd_retobj_arg); + +    return true; +} + +SWIGEXPORT void* +LLDBSWIGPythonCreateOSPlugin +( +    const char *python_class_name, +    const char *session_dictionary_name, +    const lldb::ProcessSP& process_sp +) +{ +    using namespace lldb_private; + +    if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) +        Py_RETURN_NONE; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_class_name, dict); + +    if (!pfunc.IsAllocated()) +        Py_RETURN_NONE; + +    // I do not want the SBProcess to be deallocated when going out of scope because python +    // has ownership of it and will manage memory for this object by itself +    lldb::SBProcess *process_sb = new lldb::SBProcess(process_sp); +    PythonObject process_arg(PyRefType::Owned, SBTypeToSWIGWrapper(process_sb)); +    if (!process_arg.IsAllocated()) +        Py_RETURN_NONE; + +    auto result = pfunc(process_arg); + +    if (result.IsAllocated()) +        return result.release(); + +    Py_RETURN_NONE; +} + +SWIGEXPORT void* +LLDBSWIGPython_GetDynamicSetting (void* module, const char* setting, const lldb::TargetSP& target_sp) +{ +    using namespace lldb_private; + +    if (!module || !setting) +        Py_RETURN_NONE; + +    PyErr_Cleaner py_err_cleaner(true); +    PythonObject py_module(PyRefType::Borrowed, (PyObject *)module); +    auto pfunc = py_module.ResolveName<PythonCallable>("get_dynamic_setting"); + +    if (!pfunc.IsAllocated()) +        Py_RETURN_NONE; + +    lldb::SBTarget target_sb(target_sp); +    PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_sb)); +    auto result = pfunc(target_arg, PythonString(setting)); + +    return result.release(); +} + +SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordProcess +(const char* python_function_name, +const char* session_dictionary_name, +lldb::ProcessSP& process, +std::string& output) + +{ +    using namespace lldb_private; + +    if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) +        return false; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    lldb::SBProcess process_sb(process); +    PythonObject process_arg(PyRefType::Owned, SBTypeToSWIGWrapper(process_sb)); +    auto result = pfunc(process_arg, dict); + +    output = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordThread +(const char* python_function_name, +const char* session_dictionary_name, +lldb::ThreadSP& thread, +std::string& output) + +{ +    using namespace lldb_private; + +    if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) +        return false; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    lldb::SBThread thread_sb(thread); +    PythonObject thread_arg(PyRefType::Owned, SBTypeToSWIGWrapper(thread_sb)); +    auto result = pfunc(thread_arg, dict); + +    output = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordTarget +(const char* python_function_name, +const char* session_dictionary_name, +lldb::TargetSP& target, +std::string& output) + +{ +    using namespace lldb_private; + +    if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) +        return false; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name,dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    lldb::SBTarget target_sb(target); +    PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_sb)); +    auto result = pfunc(target_arg, dict); + +    output = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordFrame +(const char* python_function_name, +const char* session_dictionary_name, +lldb::StackFrameSP& frame, +std::string& output) + +{ +    using namespace lldb_private; + +    if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) +        return false; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name,dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    lldb::SBFrame frame_sb(frame); +    PythonObject frame_arg(PyRefType::Owned, SBTypeToSWIGWrapper(frame_sb)); +    auto result = pfunc(frame_arg, dict); + +    output = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT bool +LLDBSWIGPythonRunScriptKeywordValue +(const char* python_function_name, +const char* session_dictionary_name, +lldb::ValueObjectSP& value, +std::string& output) + +{ +    using namespace lldb_private; + +    if (python_function_name == NULL || python_function_name[0] == '\0' || !session_dictionary_name) +        return false; + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    if (!pfunc.IsAllocated()) +        return false; + +    lldb::SBValue value_sb(value); +    PythonObject value_arg(PyRefType::Owned, SBTypeToSWIGWrapper(value_sb)); +    auto result = pfunc(value_arg, dict); + +    output = result.Str().GetString().str(); + +    return true; +} + +SWIGEXPORT bool +LLDBSwigPythonCallModuleInit +( +    const char *python_module_name, +    const char *session_dictionary_name, +    lldb::DebuggerSP& debugger +) +{ +    using namespace lldb_private; + +    std::string python_function_name_string = python_module_name; +    python_function_name_string += ".__lldb_init_module"; +    const char* python_function_name = python_function_name_string.c_str(); + +    PyErr_Cleaner py_err_cleaner(true); + +    auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>(session_dictionary_name); +    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(python_function_name, dict); + +    // This method is optional and need not exist.  So if we don't find it, +    // it's actually a success, not a failure. +    if (!pfunc.IsAllocated()) +        return true; + +    lldb::SBDebugger debugger_sb(debugger); +    PythonObject debugger_arg(PyRefType::Owned, SBTypeToSWIGWrapper(debugger_sb)); +    pfunc(debugger_arg, dict); + +    return true; +} +%} + + +%runtime %{ +// Forward declaration to be inserted at the start of LLDBWrapPython.h +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBValue.h" + +SWIGEXPORT lldb::ValueObjectSP +LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data) +{ +    lldb::ValueObjectSP valobj_sp; +    if (data) +    { +        lldb::SBValue* sb_ptr = (lldb::SBValue *)data; +        valobj_sp = sb_ptr->GetSP(); +    } +    return valobj_sp; +} + +#ifdef __cplusplus +extern "C" { +#endif + +void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton); + +#ifdef __cplusplus +} +#endif +%} + +%wrapper %{ + + +// For the LogOutputCallback functions +void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton) { +    if (baton != Py_None) { +      SWIG_PYTHON_THREAD_BEGIN_BLOCK; +      PyObject_CallFunction(reinterpret_cast<PyObject*>(baton), const_cast<char*>("s"), str); +      SWIG_PYTHON_THREAD_END_BLOCK; +    } +} +%} diff --git a/scripts/Python/remote-build.py b/scripts/Python/remote-build.py new file mode 100755 index 000000000000..72986a0bf8fe --- /dev/null +++ b/scripts/Python/remote-build.py @@ -0,0 +1,300 @@ +#!/usr/bin/python + +from __future__ import print_function + +import argparse +import getpass +import os +import os.path +import re +import select +import sys +import subprocess + +_COMMON_SYNC_OPTS = "-avzh --delete" +_COMMON_EXCLUDE_OPTS = "--exclude=DerivedData --exclude=.svn --exclude=.git --exclude=llvm-build/Release+Asserts" + +def normalize_configuration(config_text): +    if not config_text: +        return "debug" + +    config_lower = config_text.lower() +    if config_lower in ["debug", "release"]: +        return config_lower +    else: +        raise Exception("unknown configuration specified: %s" % config_text) + +def parse_args(): +    DEFAULT_REMOTE_ROOT_DIR = "/mnt/ssd/work/macosx.sync" +    DEFAULT_REMOTE_HOSTNAME = "tfiala2.mtv.corp.google.com" +    OPTIONS_FILENAME = ".remote-build.conf" +    DEFAULT_SSH_PORT = "22" + +    parser = argparse.ArgumentParser(fromfile_prefix_chars='@') + +    parser.add_argument( +        "--configuration", "-c", +        help="specify configuration (Debug, Release)", +        default=normalize_configuration(os.environ.get('CONFIGURATION', 'Debug'))) +    parser.add_argument( +        "--debug", "-d", +        action="store_true", +        help="help debug the remote-build script by adding extra logging") +    parser.add_argument( +        "--local-lldb-dir", "-l", metavar="DIR", +        help="specify local lldb directory (Xcode layout assumed for llvm/clang)", +        default=os.getcwd()) +    parser.add_argument( +        "--port", "-p", +        help="specify the port ssh should use to connect to the remote side", +        default=DEFAULT_SSH_PORT) +    parser.add_argument( +        "--remote-address", "-r", metavar="REMOTE-ADDR", +        help="specify the dns name or ip address of the remote linux system", +        default=DEFAULT_REMOTE_HOSTNAME) +    parser.add_argument( +        "--remote-dir", metavar="DIR", +        help="specify the root of the linux source/build dir", +        default=DEFAULT_REMOTE_ROOT_DIR) +    parser.add_argument( +        "--user", "-u", help="specify the user name for the remote system", +        default=getpass.getuser()) +    parser.add_argument( +        "--xcode-action", "-x", help="$(ACTION) from Xcode", nargs='?', default=None) + +    command_line_args = sys.argv[1:] +    if os.path.exists(OPTIONS_FILENAME): +        # Prepend the file so that command line args override the file contents. +        command_line_args.insert(0, "@%s" % OPTIONS_FILENAME) + +    return parser.parse_args(command_line_args) + + +def maybe_create_remote_root_dir(args): +    commandline = [ +        "ssh", +        "-p", args.port, +        "%s@%s" % (args.user, args.remote_address), +        "mkdir", +        "-p", +        args.remote_dir] +    print("create remote root dir command:\n{}".format(commandline)) +    return subprocess.call(commandline) + + +def init_with_args(args): +    # Expand any user directory specs in local-side source dir (on MacOSX). +    args.local_lldb_dir = os.path.expanduser(args.local_lldb_dir) + +    # Append the configuration type to the remote build dir. +    args.configuration = normalize_configuration(args.configuration) +    args.remote_build_dir = os.path.join( +        args.remote_dir, +        "build-%s" % args.configuration) + +    # We assume the local lldb directory is really named 'lldb'. +    # This is because on the remote end, the local lldb root dir +    # is copied over underneath llvm/tools and will be named there +    # whatever it is named locally.  The remote build will assume +    # is is called lldb. +    if os.path.basename(args.local_lldb_dir) != 'lldb': +        raise Exception( +            "local lldb root needs to be called 'lldb' but was {} instead" +            .format(os.path.basename(args.local_lldb_dir))) + +    args.lldb_dir_relative_regex = re.compile("%s/llvm/tools/lldb/" % args.remote_dir) +    args.llvm_dir_relative_regex = re.compile("%s/" % args.remote_dir) + +    print("Xcode action:", args.xcode_action) + +    # Ensure the remote directory exists. +    result = maybe_create_remote_root_dir(args) +    if result == 0: +        print("using remote root dir: %s" % args.remote_dir) +    else: +        print("remote root dir doesn't exist and could not be created, " +              + "error code:", result) +        return False + +    return True + +def sync_llvm(args): +    commandline = ["rsync"] +    commandline.extend(_COMMON_SYNC_OPTS.split()) +    commandline.extend(_COMMON_EXCLUDE_OPTS.split()) +    commandline.append("--exclude=/llvm/tools/lldb") +    commandline.extend(["-e", "ssh -p {}".format(args.port)]) +    commandline.extend([ +        "%s/llvm" % args.local_lldb_dir, +        "%s@%s:%s" % (args.user, args.remote_address, args.remote_dir)]) +    if args.debug: +        print("going to execute llvm sync: {}".format(commandline)) +    return subprocess.call(commandline) + + +def sync_lldb(args): +    commandline = ["rsync"] +    commandline.extend(_COMMON_SYNC_OPTS.split()) +    commandline.extend(_COMMON_EXCLUDE_OPTS.split()) +    commandline.append("--exclude=/lldb/llvm") +    commandline.extend(["-e", "ssh -p {}".format(args.port)]) +    commandline.extend([ +        args.local_lldb_dir, +        "%s@%s:%s/llvm/tools" % (args.user, args.remote_address, args.remote_dir)]) +    if args.debug: +        print("going to execute lldb sync: {}".format(commandline)) +    return subprocess.call(commandline) + + +def build_cmake_command(args): +    # args.remote_build_dir +    # args.configuration in ('release', 'debug') + +    if args.configuration == 'debug-optimized': +        build_type_name = "RelWithDebInfo" +    elif args.configuration == 'release': +        build_type_name = "Release" +    else: +        build_type_name = "Debug" + +    ld_flags = "\"-lstdc++ -lm\"" + +    install_dir = os.path.join( +        args.remote_build_dir, "..", "install-{}".format(args.configuration)) + +    command_line = [ +        "cmake", +        "-GNinja", +        "-DCMAKE_CXX_COMPILER=clang", +        "-DCMAKE_C_COMPILER=clang", +        # "-DCMAKE_CXX_FLAGS=%s" % cxx_flags, +        "-DCMAKE_SHARED_LINKER_FLAGS=%s" % ld_flags, +        "-DCMAKE_EXE_LINKER_FLAGS=%s" % ld_flags, +        "-DCMAKE_INSTALL_PREFIX:PATH=%s" % install_dir, +        "-DCMAKE_BUILD_TYPE=%s" % build_type_name, +        "-Wno-dev", +        os.path.join("..", "llvm") +        ] + +    return command_line + + +def maybe_configure(args): +    commandline = [ +        "ssh", +        "-p", args.port, +        "%s@%s" % (args.user, args.remote_address), +        "cd", args.remote_dir, "&&", +        "mkdir", "-p", args.remote_build_dir, "&&", +        "cd", args.remote_build_dir, "&&" +        ] +    commandline.extend(build_cmake_command(args)) + +    if args.debug: +        print("configure command: {}".format(commandline)) + +    return subprocess.call(commandline) + + +def filter_build_line(args, line): +    lldb_relative_line = args.lldb_dir_relative_regex.sub('', line) +    if len(lldb_relative_line) != len(line): +        # We substituted - return the modified line +        return lldb_relative_line + +    # No match on lldb path (longer on linux than llvm path).  Try +    # the llvm path match. +    return args.llvm_dir_relative_regex.sub('', line) + + +def run_remote_build_command(args, build_command_list): +    commandline = [ +        "ssh", +        "-p", args.port, +        "%s@%s" % (args.user, args.remote_address), +        "cd", args.remote_build_dir, "&&"] +    commandline.extend(build_command_list) + +    if args.debug: +        print("running remote build command: {}".format(commandline)) + +    proc = subprocess.Popen( +        commandline, +        stdout=subprocess.PIPE, +        stderr=subprocess.PIPE) + +    # Filter stdout/stderr output for file path mapping. +    # We do this to enable Xcode to see filenames relative to the +    # MacOSX-side directory structure. +    while True: +        reads = [proc.stdout.fileno(), proc.stderr.fileno()] +        select_result = select.select(reads, [], []) + +        for fd in select_result[0]: +            if fd == proc.stdout.fileno(): +                line = proc.stdout.readline() +                display_line = filter_build_line(args, line.rstrip()) +                if display_line and len(display_line) > 0: +                    print(display_line) +            elif fd == proc.stderr.fileno(): +                line = proc.stderr.readline() +                display_line = filter_build_line(args, line.rstrip()) +                if display_line and len(display_line) > 0: +                    print(display_line, file=sys.stderr) + +        proc_retval = proc.poll() +        if proc_retval != None: +            # Process stopped.  Drain output before finishing up. + +            # Drain stdout. +            while True: +                line = proc.stdout.readline() +                if line: +                    display_line = filter_build_line(args, line.rstrip()) +                    if display_line and len(display_line) > 0: +                        print(display_line) +                else: +                    break + +            # Drain stderr. +            while True: +                line = proc.stderr.readline() +                if line: +                    display_line = filter_build_line(args, line.rstrip()) +                    if display_line and len(display_line) > 0: +                        print(display_line, file=sys.stderr) +                else: +                    break + +            return proc_retval + + +def build(args): +    return run_remote_build_command(args, ["time", "ninja"]) + + +def clean(args): +    return run_remote_build_command(args, ["ninja", "clean"]) + + +if __name__ == "__main__": +    # Handle arg parsing. +    args = parse_args() + +    # Initialize the system. +    if not init_with_args(args): +        exit(1) + +    # Sync over llvm and clang source. +    sync_llvm(args) + +    # Sync over lldb source. +    sync_lldb(args) + +    # Configure the remote build if it's not already. +    maybe_configure(args) + +    if args.xcode_action == 'clean': +        exit(clean(args)) +    else: +        exit(build(args)) diff --git a/scripts/Python/use_lldb_suite.py b/scripts/Python/use_lldb_suite.py new file mode 100644 index 000000000000..63a098cea220 --- /dev/null +++ b/scripts/Python/use_lldb_suite.py @@ -0,0 +1,22 @@ +import inspect +import os +import sys + +def find_lldb_root(): +    lldb_root = os.path.dirname(inspect.getfile(inspect.currentframe())) +    while True: +        lldb_root = os.path.dirname(lldb_root) +        if lldb_root is None: +            return None + +        test_path = os.path.join(lldb_root, "use_lldb_suite_root.py") +        if os.path.isfile(test_path): +            return lldb_root +    return None + +lldb_root = find_lldb_root() +if lldb_root is not None: +    import imp +    module = imp.find_module("use_lldb_suite_root", [lldb_root]) +    if module is not None: +        imp.load_module("use_lldb_suite_root", *module)  | 
