aboutsummaryrefslogtreecommitdiff
path: root/scripts/Python
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/Python')
-rw-r--r--scripts/Python/Makefile15
-rw-r--r--scripts/Python/android/host_art_bt.py192
-rwxr-xr-xscripts/Python/finish-swig-Python-LLDB.sh310
-rw-r--r--scripts/Python/finishSwigPythonLLDB.py793
-rw-r--r--scripts/Python/modify-python-lldb.py486
-rw-r--r--scripts/Python/modules/CMakeLists.txt11
-rw-r--r--scripts/Python/modules/Makefile20
-rw-r--r--scripts/Python/modules/readline/CMakeLists.txt25
-rw-r--r--scripts/Python/modules/readline/Makefile100
-rw-r--r--scripts/Python/modules/readline/readline.cpp76
-rw-r--r--scripts/Python/prepare_binding_Python.py435
-rw-r--r--scripts/Python/python-extensions.swig1087
-rw-r--r--scripts/Python/python-swigsafecast.swig142
-rw-r--r--scripts/Python/python-typemaps.swig601
-rw-r--r--scripts/Python/python-wrapper.swig936
-rwxr-xr-xscripts/Python/remote-build.py300
-rw-r--r--scripts/Python/use_lldb_suite.py22
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)