diff options
Diffstat (limited to 'scripts')
104 files changed, 21191 insertions, 0 deletions
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt new file mode 100644 index 0000000000000..00bec0b2dae50 --- /dev/null +++ b/scripts/CMakeLists.txt @@ -0,0 +1,37 @@ +file(GLOB SWIG_INTERFACES interface/*.i) +file(GLOB_RECURSE SWIG_SOURCES *.swig) +set(SWIG_HEADERS + ${LLDB_SOURCE_DIR}/include/lldb/API/SBDefines.h + ${LLDB_SOURCE_DIR}/include/lldb/lldb-defines.h + ${LLDB_SOURCE_DIR}/include/lldb/lldb-enumerations.h + ${LLDB_SOURCE_DIR}/include/lldb/lldb-forward.h + ${LLDB_SOURCE_DIR}/include/lldb/lldb-types.h + ${LLDB_SOURCE_DIR}/include/lldb/lldb-versioning.h +) + +find_package(SWIG REQUIRED) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lldb.py + DEPENDS ${SWIG_SOURCES} + DEPENDS ${SWIG_INTERFACES} + DEPENDS ${SWIG_HEADERS} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Python/prepare_binding_Python.py + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Python/modify-python-lldb.py + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/prepare_bindings.py "--srcRoot=${LLDB_SOURCE_DIR}" "--targetDir=${CMAKE_CURRENT_BINARY_DIR}" "--cfgBldDir=${CMAKE_CURRENT_BINARY_DIR}" "--prefix=${CMAKE_BINARY_DIR}" "--swigExecutable=${SWIG_EXECUTABLE}" + COMMENT "Python script building LLDB Python wrapper") +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp PROPERTIES GENERATED 1) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lldb.py PROPERTIES GENERATED 1) + +add_custom_target(swig_wrapper ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp + ) + +# Install the LLDB python module on all operating systems (except Windows) +if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + install(DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} + DESTINATION lib${LLVM_LIBDIR_SUFFIX}) +endif() + +# build Python modules +add_subdirectory(Python/modules) diff --git a/scripts/Makefile b/scripts/Makefile new file mode 100644 index 0000000000000..807823f43e444 --- /dev/null +++ b/scripts/Makefile @@ -0,0 +1,17 @@ +##===- scripts/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 + +ifeq (,$(findstring -DLLDB_DISABLE_PYTHON,$(CXXFLAGS))) +DIRS := Python +endif + +include $(LLDB_LEVEL)/Makefile diff --git a/scripts/Python/Makefile b/scripts/Python/Makefile new file mode 100644 index 0000000000000..ad6c0af442b4d --- /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 0000000000000..0893662869f25 --- /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 0000000000000..92b99181c7cc0 --- /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 0000000000000..435cb88c20f04 --- /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 0000000000000..56323d6679a17 --- /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 0000000000000..396d447ff267a --- /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 0000000000000..b6989889858db --- /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 0000000000000..0a4376c1c324d --- /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 0000000000000..dc0d757bc1752 --- /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 0000000000000..d66ccf4b6b7dc --- /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 0000000000000..1996841baf18e --- /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 0000000000000..fae7f401bf134 --- /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 0000000000000..ea3f21f859ad2 --- /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 0000000000000..ec9302a15cd79 --- /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 0000000000000..5d7bfaa89439b --- /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 0000000000000..72986a0bf8fe6 --- /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 0000000000000..63a098cea220f --- /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) diff --git a/scripts/build-lldb-llvm-clang b/scripts/build-lldb-llvm-clang new file mode 100755 index 0000000000000..822e9944bf6a5 --- /dev/null +++ b/scripts/build-lldb-llvm-clang @@ -0,0 +1,74 @@ +#!/bin/sh -x + +# Usage: +# build-lldb-llvm-clang <revision> [Debug|Release|BuildAndIntegration] +# build-lldb-llvm-clang <llvm-revision> <clang-revision> [Debug|Release|BuildAndIntegration] + +LLVM_REVISION=$1 +CLANG_REVISION=$2 +LLVM_CONFIGURATION=$3 + +if [ "$LLVM_REVISION" = "" ]; then + echo "Usage:\n build-lldb-llvm-clang <llvm-revision> [<clang-revision> Debug|Release||BuildAndIntegration]" + exit 1 +fi + +if [ "$CLANG_REVISION" = "" ]; then + $CLANG_REVISION = $LLVM_REVISION +fi + +# Checkout LLVM +svn co -q -r $LLVM_REVISION http://llvm.org/svn/llvm-project/llvm/trunk llvm + +# change directory to "./llvm" +cd llvm + +# Checkout Clang +# change directory to "./llvm/tools" +cd tools +svn co -q -r $CLANG_REVISION http://llvm.org/svn/llvm-project/cfe/trunk clang + +# change directory to "./llvm" +cd .. +for patch_file in ../scripts/llvm.*.diff +do + echo "Applying patch from '$patch_file'" + patch -p0 < "$patch_file" +done + +# change directory to "./llvm/tools/clang" +cd tools/clang +for patch_file in ../../../scripts/clang.*.diff +do + echo "Applying patch from '$patch_file'" + patch -p0 < "$patch_file" +done + +# change directory to "./" +cd ../../.. +pwd + +if [ "$LLVM_CONFIGURATION" = "Debug" ]; then + # Configure "Debug+Asserts" build + mkdir llvm-debug + cd llvm-debug + ../llvm/configure --enable-targets=x86_64,arm + make -j8 clang-only VERBOSE=1 PROJECT_NAME='llvm' + make -j8 tools-only VERBOSE=1 PROJECT_NAME='llvm' EDIS_VERSION=1 +elif [ "$LLVM_CONFIGURATION" = "Release" ]; then + # Configure "Release" build + mkdir llvm-release + cd llvm-release + ../llvm/configure --enable-targets=x86_64,arm --enable-optimized --disable-assertions + make -j8 clang-only VERBOSE=1 PROJECT_NAME='llvm' + make -j8 tools-only VERBOSE=1 PROJECT_NAME='llvm' EDIS_VERSION=1 +elif [ "$LLVM_CONFIGURATION" = "BuildAndIntegration" ]; then + # Don't configure or build for "BuildAndIntegration", this configuration + # is a preparation step for a build submission + + # Remove all patches, and the llvm and clang "test" directories + rm -rf ./scripts/*.diff ./llvm/test ./llvm/tools/clang/test +else + echo "checked out llvm (revision $LLVM_REVISION) and clang (revision $CLANG_REVISION)." + exit 0 +fi diff --git a/scripts/build-llvm.pl b/scripts/build-llvm.pl new file mode 100644 index 0000000000000..f7a60d8d3d3e9 --- /dev/null +++ b/scripts/build-llvm.pl @@ -0,0 +1,407 @@ +#!/usr/bin/perl + +# This script will take a number ($ENV{SCRIPT_INPUT_FILE_COUNT}) of static archive files +# and pull them apart into object files. These object files will be placed in a directory +# named the same as the archive itself without the extension. Each object file will then +# get renamed to start with the archive name and a '-' character (for archive.a(object.o) +# the object file would becomde archive-object.o. Then all object files are re-made into +# a single static library. This can help avoid name collisions when different archive +# files might contain object files with the same name. + +use strict; +use Cwd 'abs_path'; +use File::Basename; +use File::Glob ':glob'; +use File::Slurp; +use List::Util qw[min max]; +use Digest::MD5 qw(md5_hex); + +our $llvm_srcroot = $ENV{SCRIPT_INPUT_FILE_0}; +our $llvm_dstroot = $ENV{SCRIPT_INPUT_FILE_1}; +our $archive_filelist_file = $ENV{SCRIPT_INPUT_FILE_2}; + +our $llvm_configuration = $ENV{LLVM_CONFIGURATION}; + +our $llvm_revision = "HEAD"; +our $clang_revision = "HEAD"; +our $compiler_rt_revision = "HEAD"; + +our $SRCROOT = "$ENV{SRCROOT}"; +our @archs = split (/\s+/, $ENV{ARCHS}); +my $os_release = 11; + +my $original_env_path = $ENV{PATH}; + +my $common_configure_options = "--disable-terminfo"; + +our %llvm_config_info = ( + 'Debug' => { configure_options => '--disable-optimized --disable-assertions --enable-cxx11 --enable-libcpp', make_options => 'DEBUG_SYMBOLS=1'}, + 'Debug+Asserts' => { configure_options => '--disable-optimized --enable-assertions --enable-cxx11 --enable-libcpp' , make_options => 'DEBUG_SYMBOLS=1'}, + 'Release' => { configure_options => '--enable-optimized --disable-assertions --enable-cxx11 --enable-libcpp' , make_options => ''}, + 'Release+Debug' => { configure_options => '--enable-optimized --disable-assertions --enable-cxx11 --enable-libcpp' , make_options => 'DEBUG_SYMBOLS=1'}, + 'Release+Asserts' => { configure_options => '--enable-optimized --enable-assertions --enable-cxx11 --enable-libcpp' , make_options => ''}, +); + +our $llvm_config_href = undef; +if (exists $llvm_config_info{"$llvm_configuration"}) +{ + $llvm_config_href = $llvm_config_info{$llvm_configuration}; +} +else +{ + die "Unsupported LLVM configuration: '$llvm_configuration'\n"; +} +our @llvm_repositories = ( + abs_path("$llvm_srcroot"), + abs_path("$llvm_srcroot/tools/clang"), +# abs_path("$llvm_srcroot/projects/compiler-rt") +); + +if (-e "$llvm_srcroot/lib") +{ + print "Using existing llvm sources in: '$llvm_srcroot'\n"; + print "Using standard LLVM build directory:\n SRC = '$llvm_srcroot'\n DST = '$llvm_dstroot'\n"; +} +else +{ + print "Checking out llvm sources from revision $llvm_revision...\n"; + do_command ("cd '$SRCROOT' && svn co --quiet --revision $llvm_revision http://llvm.org/svn/llvm-project/llvm/trunk llvm", "checking out llvm from repository", 1); + print "Checking out clang sources from revision $clang_revision...\n"; + do_command ("cd '$llvm_srcroot/tools' && svn co --quiet --revision $clang_revision http://llvm.org/svn/llvm-project/cfe/trunk clang", "checking out clang from repository", 1); +# print "Checking out compiler-rt sources from revision $compiler_rt_revision...\n"; +# do_command ("cd '$llvm_srcroot/projects' && svn co --quiet --revision $compiler_rt_revision http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt", "checking out compiler-rt from repository", 1); + print "Applying any local patches to LLVM/Clang..."; + + my @llvm_patches = bsd_glob("$ENV{SRCROOT}/scripts/llvm.*.diff"); + foreach my $patch (@llvm_patches) + { + do_command ("cd '$llvm_srcroot' && patch -p0 < $patch"); + } + + my @clang_patches = bsd_glob("$ENV{SRCROOT}/scripts/clang.*.diff"); + foreach my $patch (@clang_patches) + { + do_command ("cd '$llvm_srcroot/tools/clang' && patch -p0 < $patch"); + } + +# my @compiler_rt_patches = bsd_glob("$ENV{SRCROOT}/scripts/compiler-rt.*.diff"); +# foreach my $patch (@compiler_rt_patches) +# { +# do_command ("cd '$llvm_srcroot/projects/compiler-rt' && patch -p0 < $patch"); +# } +} + +# Get our options + +our $debug = 1; + +sub parallel_guess +{ + my $cpus = `sysctl -n hw.ncpu`; + chomp ($cpus); + my $memsize = `sysctl -n hw.memsize`; + chomp ($memsize); + my $max_cpus_by_memory = int($memsize / (750 * 1024 * 1024)); + return min($max_cpus_by_memory, $cpus); +} + +sub build_llvm +{ + #my $extra_svn_options = $debug ? "" : "--quiet"; + # Make the llvm build directory + my $arch_idx = 0; + + # Calculate if the current source digest so we can compare it to each architecture + # build folder + my @llvm_md5_strings; + foreach my $repo (@llvm_repositories) + { + if (-d "$repo/.svn") + { + push(@llvm_md5_strings, `cd '$repo'; svn info`); + push(@llvm_md5_strings, `cd '$repo'; svn diff`); + } + elsif (-d "$repo/.git") + { + push(@llvm_md5_strings, `cd '$repo'; git branch -v`); + push(@llvm_md5_strings, `cd '$repo'; git diff`); + } + } + + # open my $md5_data_file, '>', "/tmp/a.txt" or die "Can't open $! for writing...\n"; + # foreach my $md5_string (@llvm_md5_strings) + # { + # print $md5_data_file $md5_string; + # } + # close ($md5_data_file); + + #print "LLVM MD5 will be generated from:\n"; + #print @llvm_md5_strings; + my $llvm_hex_digest = md5_hex(@llvm_md5_strings); + my $did_make = 0; + + #print "llvm MD5: $llvm_hex_digest\n"; + + my @archive_dirs; + + foreach my $arch (@archs) + { + my $llvm_dstroot_arch = "${llvm_dstroot}/${arch}"; + + # if the arch destination root exists we have already built it + my $do_configure = 0; + my $do_make = 0; + my $is_arm = $arch =~ /^arm/; + my $save_arch_digest = 1; + my $arch_digest_file = "$llvm_dstroot_arch/md5"; + my $llvm_dstroot_arch_archive_dir = "$llvm_dstroot_arch/$llvm_configuration/lib"; + + push @archive_dirs, $llvm_dstroot_arch_archive_dir; + + print "LLVM architecture root for ${arch} exists at '$llvm_dstroot_arch'..."; + if (-e $llvm_dstroot_arch) + { + print "YES\n"; + $do_configure = !-e "$llvm_dstroot_arch/config.log"; + + my @archive_modtimes; + if ($do_make == 0) + { + if (-e $arch_digest_file) + { + my $arch_hex_digest = read_file($arch_digest_file); + if ($arch_hex_digest eq $llvm_hex_digest) + { + # No sources have been changed or updated + $save_arch_digest = 0; + } + else + { + # Sources have changed, or svn has been updated + print "Sources have changed, rebuilding...\n"; + $do_make = 1; + } + } + else + { + # No MD5 digest, we need to make + print "Missing MD5 digest file '$arch_digest_file', rebuilding...\n"; + $do_make = 1; + } + + if ($do_make == 0) + { + if (-e $archive_filelist_file) + { + # the final archive exists, check the modification times on all .a files that + # make the final archive to make sure we don't need to rebuild + my $archive_filelist_file_modtime = (stat($archive_filelist_file))[9]; + + our @archive_files = glob "$llvm_dstroot_arch_archive_dir/*.a"; + + for my $llvm_lib (@archive_files) + { + if (-e $llvm_lib) + { + if ($archive_filelist_file_modtime < (stat($llvm_lib))[9]) + { + print "'$llvm_dstroot_arch/$llvm_lib' is newer than '$archive_filelist_file', rebuilding...\n"; + $do_make = 1; + last; + } + } + } + } + else + { + $do_make = 1; + } + } + } + } + else + { + print "NO\n"; + do_command ("mkdir -p '$llvm_dstroot_arch'", "making llvm build directory '$llvm_dstroot_arch'", 1); + $do_configure = 1; + $do_make = 1; + + if ($is_arm) + { + my $llvm_dstroot_arch_bin = "${llvm_dstroot_arch}/bin"; + if (!-d $llvm_dstroot_arch_bin) + { + do_command ("mkdir -p '$llvm_dstroot_arch_bin'", "making llvm build arch bin directory '$llvm_dstroot_arch_bin'", 1); + my @tools = ("ar", "nm", "strip", "lipo", "ld", "as"); + my $script_mode = 0755; + my $prog; + for $prog (@tools) + { + chomp(my $actual_prog_path = `xcrun -sdk '$ENV{SDKROOT}' -find ${prog}`); + symlink($actual_prog_path, "$llvm_dstroot_arch_bin/${prog}"); + my $script_prog_path = "$llvm_dstroot_arch_bin/arm-apple-darwin${os_release}-${prog}"; + open (SCRIPT, ">$script_prog_path") or die "Can't open $! for writing...\n"; + print SCRIPT "#!/bin/sh\nexec '$actual_prog_path' \"\$\@\"\n"; + close (SCRIPT); + chmod($script_mode, $script_prog_path); + } + # Tools that must have the "-arch" and "-sysroot" specified + my @arch_sysroot_tools = ("clang", "clang++", "gcc", "g++"); + for $prog (@arch_sysroot_tools) + { + chomp(my $actual_prog_path = `xcrun -sdk '$ENV{SDKROOT}' -find ${prog}`); + symlink($actual_prog_path, "$llvm_dstroot_arch_bin/${prog}"); + my $script_prog_path = "$llvm_dstroot_arch_bin/arm-apple-darwin${os_release}-${prog}"; + open (SCRIPT, ">$script_prog_path") or die "Can't open $! for writing...\n"; + print SCRIPT "#!/bin/sh\nexec '$actual_prog_path' -arch ${arch} -isysroot '$ENV{SDKROOT}' \"\$\@\"\n"; + close (SCRIPT); + chmod($script_mode, $script_prog_path); + } + my $new_path = "$original_env_path:$llvm_dstroot_arch_bin"; + print "Setting new environment PATH = '$new_path'\n"; + $ENV{PATH} = $new_path; + } + } + } + + if ($save_arch_digest) + { + write_file($arch_digest_file, \$llvm_hex_digest); + } + + if ($do_configure) + { + # Build llvm and clang + print "Configuring clang ($arch) in '$llvm_dstroot_arch'...\n"; + my $lldb_configuration_options = "--enable-targets=x86_64,arm,arm64 $common_configure_options $llvm_config_href->{configure_options}"; + + # We're configuring llvm/clang with --enable-cxx11 and --enable-libcpp but llvm/configure doesn't + # pick up the right C++ standard library. If we have a MACOSX_DEPLOYMENT_TARGET of 10.7 or 10.8 + # (or are using actually building on those releases), we need to specify "-stdlib=libc++" at link + # time or llvm/configure will not see <atomic> as available and error out (v. llvm r199313). + $ENV{LDFLAGS} = $ENV{LDFLAGS} . " -stdlib=libc++"; + + if ($is_arm) + { + $lldb_configuration_options .= " --host=arm-apple-darwin${os_release} --target=arm-apple-darwin${os_release} --build=i686-apple-darwin${os_release} --program-prefix=\"\""; + } + else + { + $lldb_configuration_options .= " --build=$arch-apple-darwin${os_release}"; + } + if ($is_arm) + { + # Unset "SDKROOT" for ARM builds + do_command ("cd '$llvm_dstroot_arch' && unset SDKROOT && '$llvm_srcroot/configure' $lldb_configuration_options", + "configuring llvm build", 1); + } + else + { + do_command ("cd '$llvm_dstroot_arch' && '$llvm_srcroot/configure' $lldb_configuration_options", + "configuring llvm build", 1); + } + } + + if ($do_make) + { + $did_make = 1; + # Build llvm and clang + my $num_cpus = parallel_guess(); + print "Building clang using $num_cpus cpus ($arch)...\n"; + my $extra_make_flags = ''; + if ($is_arm) + { + $extra_make_flags = "UNIVERSAL=1 UNIVERSAL_ARCH=${arch} UNIVERSAL_SDK_PATH='$ENV{SDKROOT}' SDKROOT="; + } + do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus clang-only VERBOSE=1 $llvm_config_href->{make_options} PROJECT_NAME='llvm' $extra_make_flags", "making llvm and clang", 1); + do_command ("cd '$llvm_dstroot_arch' && make -j$num_cpus tools-only VERBOSE=1 $llvm_config_href->{make_options} PROJECT_NAME='llvm' $extra_make_flags EDIS_VERSION=1", "making libedis", 1); + + } + + ++$arch_idx; + } + + # If we did any makes update the archive filenames file with any .a files from + # each architectures "lib" folder... + if ($did_make) + { + open my $fh, '>', $archive_filelist_file or die "Can't open $! for writing...\n"; + foreach my $archive_dir (@archive_dirs) + { + append_all_archive_files ($archive_dir, $fh); + } + close($fh); + } +} + +#---------------------------------------------------------------------- +# quote the path if needed and realpath it if the -r option was +# specified +#---------------------------------------------------------------------- +sub finalize_path +{ + my $path = shift; + # Realpath all paths that don't start with "/" + $path =~ /^[^\/]/ and $path = abs_path($path); + + # Quote the path if asked to, or if there are special shell characters + # in the path name + my $has_double_quotes = $path =~ /["]/; + my $has_single_quotes = $path =~ /[']/; + my $needs_quotes = $path =~ /[ \$\&\*'"]/; + if ($needs_quotes) + { + # escape and double quotes in the path + $has_double_quotes and $path =~ s/"/\\"/g; + $path = "\"$path\""; + } + return $path; +} + +sub do_command +{ + my $cmd = shift; + my $description = @_ ? shift : "command"; + my $die_on_fail = @_ ? shift : undef; + $debug and print "% $cmd\n"; + system ($cmd); + if ($? == -1) + { + $debug and printf ("error: %s failed to execute: $!\n", $description); + $die_on_fail and $? and exit(1); + return $?; + } + elsif ($? & 127) + { + $debug and printf("error: %s child died with signal %d, %s coredump\n", + $description, + ($? & 127), + ($? & 128) ? 'with' : 'without'); + $die_on_fail and $? and exit(1); + return $?; + } + else + { + my $exit = $? >> 8; + if ($exit) + { + $debug and printf("error: %s child exited with value %d\n", $description, $exit); + $die_on_fail and exit(1); + } + return $exit; + } +} + +sub append_all_archive_files +{ + my $archive_dir = shift; + my $fh = shift; + + our @archive_files = glob "$archive_dir/*.a"; + for my $archive_fullpath (@archive_files) + { + print $fh "$archive_fullpath\n"; + } +} + +build_llvm(); diff --git a/scripts/buildbot.py b/scripts/buildbot.py new file mode 100755 index 0000000000000..0c04d9c4be822 --- /dev/null +++ b/scripts/buildbot.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +import argparse +import os +import os.path +import shutil +import subprocess +import sys + +class BuildError(Exception): + def __init__(self, + string=None, + path=None, + inferior_error=None): + self.m_string = string + self.m_path = path + self.m_inferior_error = inferior_error + def __str__(self): + if self.m_path and self.m_string: + return "Build error: %s (referring to %s)" % (self.m_string, self.m_path) + if self.m_path: + return "Build error (referring to %s)" % (self.m_path) + if self.m_string: + return "Build error: %s" % (self.m_string) + return "Build error" + +class LLDBBuildBot: + def __init__(self, + build_directory_path, + log_path, + lldb_repository_url="http://llvm.org/svn/llvm-project/lldb/trunk", + llvm_repository_url="http://llvm.org/svn/llvm-project/llvm/trunk", + clang_repository_url="http://llvm.org/svn/llvm-project/cfe/trunk", + revision=None): + self.m_build_directory_path = os.path.abspath(build_directory_path) + self.m_log_path = os.path.abspath(log_path) + self.m_lldb_repository_url = lldb_repository_url + self.m_llvm_repository_url = llvm_repository_url + self.m_clang_repository_url = clang_repository_url + self.m_revision = revision + self.m_log_stream = None + def Setup(self): + if os.path.exists(self.m_build_directory_path): + raise BuildError(string="Build directory exists", path=self.m_build_directory_path) + if os.path.exists(self.m_log_path): + raise BuildError(string="Log file exists", path=self.m_log_path) + self.m_log_stream = open(self.m_log_path, 'w') + os.mkdir(self.m_build_directory_path) + def Checkout(self): + os.chdir(self.m_build_directory_path) + + cmdline_prefix = [] + + if self.m_revision != None: + cmdline_prefix = ["svn", "-r %s" % (self.m_revision), "co"] + else: + cmdline_prefix = ["svn", "co"] + + returncode = subprocess.call(cmdline_prefix + [self.m_lldb_repository_url, "lldb"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + if returncode != 0: + raise BuildError(string="Couldn't checkout LLDB") + + os.chdir("lldb") + + returncode = subprocess.call(cmdline_prefix + [self.m_llvm_repository_url, "llvm.checkout"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + + if returncode != 0: + raise BuildError(string="Couldn't checkout LLVM") + + os.symlink("llvm.checkout", "llvm") + + os.chdir("llvm/tools") + + returncode = subprocess.call(cmdline_prefix + [self.m_clang_repository_url, "clang"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + + if returncode != 0: + raise BuildError(string="Couldn't checkout Clang") + def Build(self): + os.chdir(self.m_build_directory_path) + os.chdir("lldb/llvm") + + returncode = subprocess.call(["./configure", "--disable-optimized", "--enable-assertions", "--enable-targets=x86,x86_64,arm"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + + if returncode != 0: + raise BuildError(string="Couldn't configure LLVM/Clang") + + returncode = subprocess.call(["make"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + + if returncode != 0: + raise BuildError(string="Couldn't build LLVM/Clang") + + os.chdir(self.m_build_directory_path) + os.chdir("lldb") + + returncode = subprocess.call(["xcodebuild", + "-project", "lldb.xcodeproj", + "-target", "lldb-tool", + "-configuration", "Debug", + "-arch", "x86_64", + "LLVM_CONFIGURATION=Debug+Asserts", + "OBJROOT=build"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + + if returncode != 0: + raise BuildError(string="Couldn't build LLDB") + def Test(self): + os.chdir(self.m_build_directory_path) + os.chdir("lldb/test") + + returncode = subprocess.call(["./dotest.py", "-t"], + stdout=self.m_log_stream, + stderr=self.m_log_stream) + def Takedown(self): + os.chdir("/tmp") + self.m_log_stream.close() + shutil.rmtree(self.m_build_directory_path) + def Run(self): + self.Setup() + self.Checkout() + self.Build() + #self.Test() + self.Takedown() + +def GetArgParser(): + parser = argparse.ArgumentParser(description="Try to build LLDB/LLVM/Clang and run the full test suite.") + parser.add_argument("--build-path", "-b", required=True, help="A (nonexistent) path to put temporary build products into", metavar="path") + parser.add_argument("--log-file", "-l", required=True, help="The name of a (nonexistent) log file", metavar="file") + parser.add_argument("--revision", "-r", required=False, help="The LLVM revision to use", metavar="N") + return parser + +parser = GetArgParser() +arg_dict = vars(parser.parse_args()) + +build_bot = LLDBBuildBot(build_directory_path=arg_dict["build_path"], + log_path=arg_dict["log_file"], + revision=arg_dict["revision"]) + +try: + build_bot.Run() +except BuildError as err: + print err diff --git a/scripts/checkpoint-llvm.pl b/scripts/checkpoint-llvm.pl new file mode 100755 index 0000000000000..2372e7e509fac --- /dev/null +++ b/scripts/checkpoint-llvm.pl @@ -0,0 +1,126 @@ +#!/usr/bin/perl + +# This script should be pointed to a valid llvm.build folder that +# was created using the "build-llvm.pl" shell script. It will create +# a new llvm.zip file that can be checked into the repository +# at lldb/llvm.zip + +use strict; +use Cwd 'abs_path'; +use File::Basename; +use File::Temp qw/ tempfile tempdir /; +our $debug = 1; + + +sub do_command +{ + my $cmd = shift; + my $description = @_ ? shift : "command"; + my $die_on_fail = @_ ? shift : undef; + $debug and print "% $cmd\n"; + system ($cmd); + if ($? == -1) + { + $debug and printf ("error: %s failed to execute: $!\n", $description); + $die_on_fail and $? and exit(1); + return $?; + } + elsif ($? & 127) + { + $debug and printf("error: %s child died with signal %d, %s coredump\n", + $description, + ($? & 127), + ($? & 128) ? 'with' : 'without'); + $die_on_fail and $? and exit(1); + return $?; + } + else + { + my $exit = $? >> 8; + if ($exit) + { + $debug and printf("error: %s child exited with value %d\n", $description, $exit); + $die_on_fail and exit(1); + } + return $exit; + } +} + +sub do_rsync_paths +{ + while (@_) + { + my $rsync_src = shift @_; + my $rsync_dst = shift @_; + print "rsync_src = '$rsync_src'\n"; + print "rsync_dst = '$rsync_dst'\n"; + + if (!-d $rsync_dst) + { + mkdir $rsync_dst; + } + + if (-e $rsync_src) + { + my ($rsync_dst_file, $rsync_dst_dir) = fileparse ($rsync_dst); + print "rsync_dst_dir = '$rsync_dst_dir'\n"; + -e $rsync_dst_dir or do_command ("mkdir -p '$rsync_dst_dir'"); + do_command ("rsync -amvC --exclude='*.tmp' --exclude='*.txt' --exclude='*.TXT' --exclude='*.td' --exclude='\.dir' --exclude=Makefile '$rsync_src' '$rsync_dst'"); + } + else + { + die "$rsync_src does not exist!\n"; + } + } +} + +if (@ARGV > 4) +{ + my $llvm_source_dir = abs_path(shift @ARGV); # The llvm source that contains full llvm and clang sources + my $llvm_build_dir = abs_path(shift @ARGV); # The llvm build directory that contains headers and + my $lldb_build_dir = abs_path(shift @ARGV); # the build directory that contains the fat libEnhancedDisassembly.dylib + my $llvm_zip_file = abs_path(shift @ARGV); + + printf("LLVM sources : '%s'\n", $llvm_source_dir); + printf("LLVM build : '%s'\n", $llvm_build_dir); + printf("LLDB build : '%s'\n", $lldb_build_dir); + printf("LLVM zip file: '%s'\n", $llvm_zip_file); + + -e $llvm_build_dir or die "LLVM build directory doesn't exist: '$llvm_build_dir': $!\n"; + + my $temp_dir = tempdir( CLEANUP => 1 ); + print "temp dir = '$temp_dir'\n"; + my $llvm_checkpoint_dir = "$temp_dir/llvm"; + mkdir "$llvm_checkpoint_dir" or die "Couldn't make 'llvm' in '$temp_dir'\n"; + + my @generic_rsync_src_dst_paths = + ( + "$llvm_source_dir/include", "$llvm_checkpoint_dir", + "$llvm_source_dir/tools/clang/include", "$llvm_checkpoint_dir/tools/clang", + ); + + do_rsync_paths (@generic_rsync_src_dst_paths); + + for my $arch (@ARGV) + { + my @specific_rsync_src_dst_paths = + ( + "$llvm_build_dir/$arch/include", "$llvm_checkpoint_dir/$arch", + "$llvm_build_dir/$arch/tools/clang/include", "$llvm_checkpoint_dir/$arch/tools/clang", + ); + + do_rsync_paths (@specific_rsync_src_dst_paths); + + do_command ("cp '$llvm_build_dir/$arch/libllvmclang.a' '$llvm_checkpoint_dir/$arch/libllvmclang.a'", "Copying .a file", 1); + + } + + #do_command ("cp '$llvm_build_dir/libllvmclang.a' '$llvm_checkpoint_dir'", "Copying libllvmclang.a", 1); + do_command ("rm -rf '$llvm_zip_file'", "Removing old llvm checkpoint file '$llvm_zip_file'", 1); + do_command ("(cd '$temp_dir' ; zip -r '$llvm_zip_file' 'llvm')", "Zipping llvm checkpoint directory '$llvm_checkpoint_dir' to '$llvm_zip_file'", 1); +} +else +{ + print "USAGE\n\tcheckpoint-llvm.pl <llvm-sources> <llvm-build> <lldb-build> <llvm-zip> <arch1> [<arch2> ...]\n\n"; + print "EXAMPLE\n\tcd lldb\n\t./scripts/checkpoint-llvm.pl llvm build/llvm build/BuildAndIntegration llvm.zip x86_64 i386\n"; +} diff --git a/scripts/disasm-gdb-remote.pl b/scripts/disasm-gdb-remote.pl new file mode 100755 index 0000000000000..e4c7066ff21ff --- /dev/null +++ b/scripts/disasm-gdb-remote.pl @@ -0,0 +1,2283 @@ +#!/usr/bin/perl + +use strict; + +#---------------------------------------------------------------------- +# Globals +#---------------------------------------------------------------------- +our $unimplemented_str = "UNIMPLEMENTED"; +our $success_str = "OK"; +our $swap = 1; +our $addr_size = 4; +our $thread_suffix_supported = 0; +our $max_bytes_per_line = 32; +our $addr_format = sprintf("0x%%%u.%ux", $addr_size*2, $addr_size*2); +our $pid_format = "%04.4x"; +our $tid_format = "%04.4x"; +our $reg8_href = { extract => \&get8, format => "0x%2.2x" }; +our $reg16_href = { extract => \&get16, format => "0x%4.4x" }; +our $reg32_href = { extract => \&get32, format => "0x%8.8x" }; +our $reg64_href = { extract => \&get64, format => "0x%s" }; +our $reg80_href = { extract => \&get80, format => "0x%s" }; +our $reg128_href = { extract => \&get128, format => "0x%s" }; +our $reg256_href = { extract => \&get256, format => "0x%s" }; +our $float32_href = { extract => \&get32, format => "0x%8.8x" }; +our $float64_href = { extract => \&get64, format => "0x%s" }; +our $float96_href = { extract => \&get96, format => "0x%s" }; +our $curr_cmd = undef; +our $curr_full_cmd = undef; +our %packet_times; +our $curr_time = 0.0; +our $last_time = 0.0; +our $base_time = 0.0; +our $packet_start_time = 0.0; +our $reg_cmd_reg; +our %reg_map = ( + 'i386-gdb' => [ + { name => 'eax', info => $reg32_href }, + { name => 'ecx', info => $reg32_href }, + { name => 'edx', info => $reg32_href }, + { name => 'ebx', info => $reg32_href }, + { name => 'esp', info => $reg32_href }, + { name => 'ebp', info => $reg32_href }, + { name => 'esi', info => $reg32_href }, + { name => 'edi', info => $reg32_href }, + { name => 'eip', info => $reg32_href }, + { name => 'eflags', info => $reg32_href }, + { name => 'cs', info => $reg32_href }, + { name => 'ss', info => $reg32_href }, + { name => 'ds', info => $reg32_href }, + { name => 'es', info => $reg32_href }, + { name => 'fs', info => $reg32_href }, + { name => 'gs', info => $reg32_href }, + { name => 'st0', info => $reg80_href }, + { name => 'st1', info => $reg80_href }, + { name => 'st2', info => $reg80_href }, + { name => 'st3', info => $reg80_href }, + { name => 'st4', info => $reg80_href }, + { name => 'st5', info => $reg80_href }, + { name => 'st6', info => $reg80_href }, + { name => 'st7', info => $reg80_href }, + { name => 'fctrl', info => $reg32_href }, + { name => 'fstat', info => $reg32_href }, + { name => 'ftag', info => $reg32_href }, + { name => 'fiseg', info => $reg32_href }, + { name => 'fioff', info => $reg32_href }, + { name => 'foseg', info => $reg32_href }, + { name => 'fooff', info => $reg32_href }, + { name => 'fop', info => $reg32_href }, + { name => 'xmm0', info => $reg128_href }, + { name => 'xmm1', info => $reg128_href }, + { name => 'xmm2', info => $reg128_href }, + { name => 'xmm3', info => $reg128_href }, + { name => 'xmm4', info => $reg128_href }, + { name => 'xmm5', info => $reg128_href }, + { name => 'xmm6', info => $reg128_href }, + { name => 'xmm7', info => $reg128_href }, + { name => 'mxcsr', info => $reg32_href }, + { name => 'mm0', info => $reg64_href }, + { name => 'mm1', info => $reg64_href }, + { name => 'mm2', info => $reg64_href }, + { name => 'mm3', info => $reg64_href }, + { name => 'mm4', info => $reg64_href }, + { name => 'mm5', info => $reg64_href }, + { name => 'mm6', info => $reg64_href }, + { name => 'mm7', info => $reg64_href }, + ], + + 'i386-lldb' => [ + { name => 'eax', info => $reg32_href }, + { name => 'ebx', info => $reg32_href }, + { name => 'ecx', info => $reg32_href }, + { name => 'edx', info => $reg32_href }, + { name => 'edi', info => $reg32_href }, + { name => 'esi', info => $reg32_href }, + { name => 'ebp', info => $reg32_href }, + { name => 'esp', info => $reg32_href }, + { name => 'ss', info => $reg32_href }, + { name => 'eflags', info => $reg32_href }, + { name => 'eip', info => $reg32_href }, + { name => 'cs', info => $reg32_href }, + { name => 'ds', info => $reg32_href }, + { name => 'es', info => $reg32_href }, + { name => 'fs', info => $reg32_href }, + { name => 'gs', info => $reg32_href }, + { name => 'fctrl', info => $reg16_href }, + { name => 'fstat', info => $reg16_href }, + { name => 'ftag', info => $reg8_href }, + { name => 'fop', info => $reg16_href }, + { name => 'fioff', info => $reg32_href }, + { name => 'fiseg', info => $reg16_href }, + { name => 'fooff', info => $reg32_href }, + { name => 'foseg', info => $reg16_href }, + { name => 'mxcsr', info => $reg32_href }, + { name => 'mxcsrmask', info => $reg32_href }, + { name => 'stmm0', info => $reg80_href }, + { name => 'stmm1', info => $reg80_href }, + { name => 'stmm2', info => $reg80_href }, + { name => 'stmm3', info => $reg80_href }, + { name => 'stmm4', info => $reg80_href }, + { name => 'stmm5', info => $reg80_href }, + { name => 'stmm6', info => $reg80_href }, + { name => 'stmm7', info => $reg80_href }, + { name => 'xmm0', info => $reg128_href }, + { name => 'xmm1', info => $reg128_href }, + { name => 'xmm2', info => $reg128_href }, + { name => 'xmm3', info => $reg128_href }, + { name => 'xmm4', info => $reg128_href }, + { name => 'xmm5', info => $reg128_href }, + { name => 'xmm6', info => $reg128_href }, + { name => 'xmm7', info => $reg128_href }, + { name => 'trapno', info => $reg32_href }, + { name => 'err', info => $reg32_href }, + { name => 'faultvaddr', info => $reg32_href }, + ], + + 'arm-gdb' => [ + { name => 'r0' , info => $reg32_href }, + { name => 'r1' , info => $reg32_href }, + { name => 'r2' , info => $reg32_href }, + { name => 'r3' , info => $reg32_href }, + { name => 'r4' , info => $reg32_href }, + { name => 'r5' , info => $reg32_href }, + { name => 'r6' , info => $reg32_href }, + { name => 'r7' , info => $reg32_href }, + { name => 'r8' , info => $reg32_href }, + { name => 'r9' , info => $reg32_href }, + { name => 'r10' , info => $reg32_href }, + { name => 'r11' , info => $reg32_href }, + { name => 'r12' , info => $reg32_href }, + { name => 'sp' , info => $reg32_href }, + { name => 'lr' , info => $reg32_href }, + { name => 'pc' , info => $reg32_href }, + { name => 'f0' , info => $float96_href }, + { name => 'f1' , info => $float96_href }, + { name => 'f2' , info => $float96_href }, + { name => 'f3' , info => $float96_href }, + { name => 'f4' , info => $float96_href }, + { name => 'f5' , info => $float96_href }, + { name => 'f6' , info => $float96_href }, + { name => 'f7' , info => $float96_href }, + { name => 'fps' , info => $reg32_href }, + { name => 'cpsr' , info => $reg32_href }, + { name => 's0' , info => $float32_href }, + { name => 's1' , info => $float32_href }, + { name => 's2' , info => $float32_href }, + { name => 's3' , info => $float32_href }, + { name => 's4' , info => $float32_href }, + { name => 's5' , info => $float32_href }, + { name => 's6' , info => $float32_href }, + { name => 's7' , info => $float32_href }, + { name => 's8' , info => $float32_href }, + { name => 's9' , info => $float32_href }, + { name => 's10' , info => $float32_href }, + { name => 's11' , info => $float32_href }, + { name => 's12' , info => $float32_href }, + { name => 's13' , info => $float32_href }, + { name => 's14' , info => $float32_href }, + { name => 's15' , info => $float32_href }, + { name => 's16' , info => $float32_href }, + { name => 's17' , info => $float32_href }, + { name => 's18' , info => $float32_href }, + { name => 's19' , info => $float32_href }, + { name => 's20' , info => $float32_href }, + { name => 's21' , info => $float32_href }, + { name => 's22' , info => $float32_href }, + { name => 's23' , info => $float32_href }, + { name => 's24' , info => $float32_href }, + { name => 's25' , info => $float32_href }, + { name => 's26' , info => $float32_href }, + { name => 's27' , info => $float32_href }, + { name => 's28' , info => $float32_href }, + { name => 's29' , info => $float32_href }, + { name => 's30' , info => $float32_href }, + { name => 's31' , info => $float32_href }, + { name => 'fpscr' , info => $reg32_href }, + { name => 'd16' , info => $float64_href }, + { name => 'd17' , info => $float64_href }, + { name => 'd18' , info => $float64_href }, + { name => 'd19' , info => $float64_href }, + { name => 'd20' , info => $float64_href }, + { name => 'd21' , info => $float64_href }, + { name => 'd22' , info => $float64_href }, + { name => 'd23' , info => $float64_href }, + { name => 'd24' , info => $float64_href }, + { name => 'd25' , info => $float64_href }, + { name => 'd26' , info => $float64_href }, + { name => 'd27' , info => $float64_href }, + { name => 'd28' , info => $float64_href }, + { name => 'd29' , info => $float64_href }, + { name => 'd30' , info => $float64_href }, + { name => 'd31' , info => $float64_href }, + ], + + + 'arm-lldb' => [ + { name => 'r0' , info => $reg32_href }, + { name => 'r1' , info => $reg32_href }, + { name => 'r2' , info => $reg32_href }, + { name => 'r3' , info => $reg32_href }, + { name => 'r4' , info => $reg32_href }, + { name => 'r5' , info => $reg32_href }, + { name => 'r6' , info => $reg32_href }, + { name => 'r7' , info => $reg32_href }, + { name => 'r8' , info => $reg32_href }, + { name => 'r9' , info => $reg32_href }, + { name => 'r10' , info => $reg32_href }, + { name => 'r11' , info => $reg32_href }, + { name => 'r12' , info => $reg32_href }, + { name => 'sp' , info => $reg32_href }, + { name => 'lr' , info => $reg32_href }, + { name => 'pc' , info => $reg32_href }, + { name => 'cpsr' , info => $reg32_href }, + { name => 's0' , info => $float32_href }, + { name => 's1' , info => $float32_href }, + { name => 's2' , info => $float32_href }, + { name => 's3' , info => $float32_href }, + { name => 's4' , info => $float32_href }, + { name => 's5' , info => $float32_href }, + { name => 's6' , info => $float32_href }, + { name => 's7' , info => $float32_href }, + { name => 's8' , info => $float32_href }, + { name => 's9' , info => $float32_href }, + { name => 's10' , info => $float32_href }, + { name => 's11' , info => $float32_href }, + { name => 's12' , info => $float32_href }, + { name => 's13' , info => $float32_href }, + { name => 's14' , info => $float32_href }, + { name => 's15' , info => $float32_href }, + { name => 's16' , info => $float32_href }, + { name => 's17' , info => $float32_href }, + { name => 's18' , info => $float32_href }, + { name => 's19' , info => $float32_href }, + { name => 's20' , info => $float32_href }, + { name => 's21' , info => $float32_href }, + { name => 's22' , info => $float32_href }, + { name => 's23' , info => $float32_href }, + { name => 's24' , info => $float32_href }, + { name => 's25' , info => $float32_href }, + { name => 's26' , info => $float32_href }, + { name => 's27' , info => $float32_href }, + { name => 's28' , info => $float32_href }, + { name => 's29' , info => $float32_href }, + { name => 's30' , info => $float32_href }, + { name => 's31' , info => $float32_href }, + { name => 'd0' , info => $float64_href }, + { name => 'd1' , info => $float64_href }, + { name => 'd2' , info => $float64_href }, + { name => 'd3' , info => $float64_href }, + { name => 'd4' , info => $float64_href }, + { name => 'd5' , info => $float64_href }, + { name => 'd6' , info => $float64_href }, + { name => 'd7' , info => $float64_href }, + { name => 'd8' , info => $float64_href }, + { name => 'd9' , info => $float64_href }, + { name => 'd10' , info => $float64_href }, + { name => 'd11' , info => $float64_href }, + { name => 'd12' , info => $float64_href }, + { name => 'd13' , info => $float64_href }, + { name => 'd14' , info => $float64_href }, + { name => 'd15' , info => $float64_href }, + { name => 'd16' , info => $float64_href }, + { name => 'd17' , info => $float64_href }, + { name => 'd18' , info => $float64_href }, + { name => 'd19' , info => $float64_href }, + { name => 'd20' , info => $float64_href }, + { name => 'd21' , info => $float64_href }, + { name => 'd22' , info => $float64_href }, + { name => 'd23' , info => $float64_href }, + { name => 'd24' , info => $float64_href }, + { name => 'd25' , info => $float64_href }, + { name => 'd26' , info => $float64_href }, + { name => 'd27' , info => $float64_href }, + { name => 'd28' , info => $float64_href }, + { name => 'd29' , info => $float64_href }, + { name => 'd30' , info => $float64_href }, + { name => 'd31' , info => $float64_href }, + { name => 'fpscr' , info => $reg32_href }, + { name => 'exc' , info => $reg32_href }, + { name => 'fsr' , info => $reg32_href }, + { name => 'far' , info => $reg32_href }, + ], + + 'x86_64-gdb' => [ + { name => 'rax' , info => $reg64_href }, + { name => 'rbx' , info => $reg64_href }, + { name => 'rcx' , info => $reg64_href }, + { name => 'rdx' , info => $reg64_href }, + { name => 'rsi' , info => $reg64_href }, + { name => 'rdi' , info => $reg64_href }, + { name => 'rbp' , info => $reg64_href }, + { name => 'rsp' , info => $reg64_href }, + { name => 'r8' , info => $reg64_href }, + { name => 'r9' , info => $reg64_href }, + { name => 'r10' , info => $reg64_href }, + { name => 'r11' , info => $reg64_href }, + { name => 'r12' , info => $reg64_href }, + { name => 'r13' , info => $reg64_href }, + { name => 'r14' , info => $reg64_href }, + { name => 'r15' , info => $reg64_href }, + { name => 'rip' , info => $reg64_href }, + { name => 'eflags' , info => $reg32_href }, + { name => 'cs' , info => $reg32_href }, + { name => 'ss' , info => $reg32_href }, + { name => 'ds' , info => $reg32_href }, + { name => 'es' , info => $reg32_href }, + { name => 'fs' , info => $reg32_href }, + { name => 'gs' , info => $reg32_href }, + { name => 'stmm0' , info => $reg80_href }, + { name => 'stmm1' , info => $reg80_href }, + { name => 'stmm2' , info => $reg80_href }, + { name => 'stmm3' , info => $reg80_href }, + { name => 'stmm4' , info => $reg80_href }, + { name => 'stmm5' , info => $reg80_href }, + { name => 'stmm6' , info => $reg80_href }, + { name => 'stmm7' , info => $reg80_href }, + { name => 'fctrl' , info => $reg32_href }, + { name => 'fstat' , info => $reg32_href }, + { name => 'ftag' , info => $reg32_href }, + { name => 'fiseg' , info => $reg32_href }, + { name => 'fioff' , info => $reg32_href }, + { name => 'foseg' , info => $reg32_href }, + { name => 'fooff' , info => $reg32_href }, + { name => 'fop' , info => $reg32_href }, + { name => 'xmm0' , info => $reg128_href }, + { name => 'xmm1' , info => $reg128_href }, + { name => 'xmm2' , info => $reg128_href }, + { name => 'xmm3' , info => $reg128_href }, + { name => 'xmm4' , info => $reg128_href }, + { name => 'xmm5' , info => $reg128_href }, + { name => 'xmm6' , info => $reg128_href }, + { name => 'xmm7' , info => $reg128_href }, + { name => 'xmm8' , info => $reg128_href }, + { name => 'xmm9' , info => $reg128_href }, + { name => 'xmm10' , info => $reg128_href }, + { name => 'xmm11' , info => $reg128_href }, + { name => 'xmm12' , info => $reg128_href }, + { name => 'xmm13' , info => $reg128_href }, + { name => 'xmm14' , info => $reg128_href }, + { name => 'xmm15' , info => $reg128_href }, + { name => 'mxcsr' , info => $reg32_href }, + ], + + 'x86_64-lldb' => [ + { name => 'rax' , info => $reg64_href }, + { name => 'rbx' , info => $reg64_href }, + { name => 'rcx' , info => $reg64_href }, + { name => 'rdx' , info => $reg64_href }, + { name => 'rdi' , info => $reg64_href }, + { name => 'rsi' , info => $reg64_href }, + { name => 'rbp' , info => $reg64_href }, + { name => 'rsp' , info => $reg64_href }, + { name => 'r8 ' , info => $reg64_href }, + { name => 'r9 ' , info => $reg64_href }, + { name => 'r10' , info => $reg64_href }, + { name => 'r11' , info => $reg64_href }, + { name => 'r12' , info => $reg64_href }, + { name => 'r13' , info => $reg64_href }, + { name => 'r14' , info => $reg64_href }, + { name => 'r15' , info => $reg64_href }, + { name => 'rip' , info => $reg64_href }, + { name => 'rflags' , info => $reg64_href }, + { name => 'cs' , info => $reg64_href }, + { name => 'fs' , info => $reg64_href }, + { name => 'gs' , info => $reg64_href }, + { name => 'fctrl' , info => $reg16_href }, + { name => 'fstat' , info => $reg16_href }, + { name => 'ftag' , info => $reg8_href }, + { name => 'fop' , info => $reg16_href }, + { name => 'fioff' , info => $reg32_href }, + { name => 'fiseg' , info => $reg16_href }, + { name => 'fooff' , info => $reg32_href }, + { name => 'foseg' , info => $reg16_href }, + { name => 'mxcsr' , info => $reg32_href }, + { name => 'mxcsrmask' , info => $reg32_href }, + { name => 'stmm0' , info => $reg80_href }, + { name => 'stmm1' , info => $reg80_href }, + { name => 'stmm2' , info => $reg80_href }, + { name => 'stmm3' , info => $reg80_href }, + { name => 'stmm4' , info => $reg80_href }, + { name => 'stmm5' , info => $reg80_href }, + { name => 'stmm6' , info => $reg80_href }, + { name => 'stmm7' , info => $reg80_href }, + { name => 'xmm0' , info => $reg128_href }, + { name => 'xmm1' , info => $reg128_href }, + { name => 'xmm2' , info => $reg128_href }, + { name => 'xmm3' , info => $reg128_href }, + { name => 'xmm4' , info => $reg128_href }, + { name => 'xmm5' , info => $reg128_href }, + { name => 'xmm6' , info => $reg128_href }, + { name => 'xmm7' , info => $reg128_href }, + { name => 'xmm8' , info => $reg128_href }, + { name => 'xmm9' , info => $reg128_href }, + { name => 'xmm10' , info => $reg128_href }, + { name => 'xmm11' , info => $reg128_href }, + { name => 'xmm12' , info => $reg128_href }, + { name => 'xmm13' , info => $reg128_href }, + { name => 'xmm14' , info => $reg128_href }, + { name => 'xmm15' , info => $reg128_href }, + { name => 'trapno' , info => $reg32_href }, + { name => 'err' , info => $reg32_href }, + { name => 'faultvaddr' , info => $reg64_href }, + ] +); + +our $max_register_name_len = 0; +calculate_max_register_name_length(); +our @point_types = ( "software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp" ); +our $opt_v = 0; # verbose +our $opt_g = 0; # debug +our $opt_q = 0; # quiet +our $opt_r = undef; +use Getopt::Std; +getopts('gvqr:'); + +our $registers_aref = undef; + +if (length($opt_r)) +{ + if (exists $reg_map{$opt_r}) + { + $registers_aref = $reg_map{$opt_r}; + } + else + { + die "Can't get registers group for '$opt_r'\n"; + } +} + +sub extract_key_value_pairs +{ + my $kv_href = {}; + my $arrayref = shift; + my $str = join('',@$arrayref); + my @kv_strs = split(/;/, $str); + foreach my $kv_str (@kv_strs) + { + my ($key, $value) = split(/:/, $kv_str); + $kv_href->{$key} = $value; + } + return $kv_href; +} + +sub get_thread_from_thread_suffix +{ + if ($thread_suffix_supported) + { + my $arrayref = shift; + # Skip leading semi-colon if needed + $$arrayref[0] == ';' and shift @$arrayref; + my $thread_href = extract_key_value_pairs ($arrayref); + if (exists $thread_href->{thread}) + { + return $thread_href->{thread}; + } + } + return undef; +} + +sub calculate_max_register_name_length +{ + $max_register_name_len = 7; + foreach my $reg_href (@$registers_aref) + { + my $name_len = length($reg_href->{name}); + if ($max_register_name_len < $name_len) + { + $max_register_name_len = $name_len; + } + } +} +#---------------------------------------------------------------------- +# Hash that maps command characters to the appropriate functions using +# the command character as the key and the value being a reference to +# the dump function for dumping the command itself. +#---------------------------------------------------------------------- +our %cmd_callbacks = +( + '?' => \&dump_last_signal_cmd, + 'H' => \&dump_set_thread_cmd, + 'T' => \&dump_thread_is_alive_cmd, + 'q' => \&dump_general_query_cmd, + 'Q' => \&dump_general_set_cmd, + 'g' => \&dump_read_regs_cmd, + 'G' => \&dump_write_regs_cmd, + 'p' => \&dump_read_single_register_cmd, + 'P' => \&dump_write_single_register_cmd, + 'm' => \&dump_read_mem_cmd, + 'M' => \&dump_write_mem_cmd, + 'X' => \&dump_write_mem_binary_cmd, + 'Z' => \&dump_bp_wp_command, + 'z' => \&dump_bp_wp_command, + 'k' => \&dump_kill_cmd, + 'A' => \&dump_A_command, + 'c' => \&dump_continue_cmd, + 's' => \&dump_continue_cmd, + 'C' => \&dump_continue_with_signal_cmd, + 'S' => \&dump_continue_with_signal_cmd, + '_M' => \&dump_allocate_memory_cmd, + '_m' => \&dump_deallocate_memory_cmd, + # extended commands + 'v' => \&dump_extended_cmd +); + +#---------------------------------------------------------------------- +# Hash that maps command characters to the appropriate functions using +# the command character as the key and the value being a reference to +# the dump function for the response to the command. +#---------------------------------------------------------------------- +our %rsp_callbacks = +( + 'c' => \&dump_stop_reply_packet, + 's' => \&dump_stop_reply_packet, + 'C' => \&dump_stop_reply_packet, + '?' => \&dump_stop_reply_packet, + 'T' => \&dump_thread_is_alive_rsp, + 'H' => \&dump_set_thread_rsp, + 'q' => \&dump_general_query_rsp, + 'g' => \&dump_read_regs_rsp, + 'p' => \&dump_read_single_register_rsp, + 'm' => \&dump_read_mem_rsp, + '_M' => \&dump_allocate_memory_rsp, + + # extended commands + 'v' => \&dump_extended_rsp, +); + + +sub dump_register_value +{ + my $indent = shift; + my $arrayref = shift; + my $reg_num = shift; + + if ($reg_num >= @$registers_aref) + { + printf("\tinvalid register index %d\n", $reg_num); + return; + } + + my $reg_href = $$registers_aref[$reg_num]; + my $reg_name = $reg_href->{name}; + if ($$arrayref[0] eq '#') + { + printf("\t%*s: error: EOS reached when trying to read register %d\n", $max_register_name_len, $reg_name, $reg_num); + } + + my $reg_info = $reg_href->{info}; + my $reg_extract = $reg_info->{extract}; + my $reg_format = $reg_info->{format}; + my $reg_val = &$reg_extract($arrayref); + if ($indent) { + printf("\t%*s = $reg_format", $max_register_name_len, $reg_name, $reg_val); + } else { + printf("%s = $reg_format", $reg_name, $reg_val); + } +} + +#---------------------------------------------------------------------- +# Extract the command into an array of ASCII char strings for easy +# processing +#---------------------------------------------------------------------- +sub extract_command +{ + my $cmd_str = shift; + my @cmd_chars = split(/ */, $cmd_str); + if ($cmd_chars[0] ne '$') + { + # only set the current command if it isn't a reply + $curr_cmd = $cmd_chars[0]; + } + return @cmd_chars; +} + +#---------------------------------------------------------------------- +# Strip the 3 checksum array entries after we don't need them anymore +#---------------------------------------------------------------------- +sub strip_checksum +{ + my $arrayref = shift; + splice(@$arrayref, -3); +} + +#---------------------------------------------------------------------- +# Dump all strings in array by joining them together with no space +# between them +#---------------------------------------------------------------------- +sub dump_chars +{ + print join('',@_); +} + +#---------------------------------------------------------------------- +# Check if the response is an error 'EXX' +#---------------------------------------------------------------------- +sub is_error_response +{ + if ($_[0] eq 'E') + { + shift; + print "ERROR = " . join('',@_) . "\n"; + return 1; + } + return 0; +} + +#---------------------------------------------------------------------- +# 'H' command +#---------------------------------------------------------------------- +sub dump_set_thread_cmd +{ + my $cmd = shift; + my $mod = shift; + print "set_thread ( $mod, " . join('',@_) . " )\n"; +} + +#---------------------------------------------------------------------- +# 'T' command +#---------------------------------------------------------------------- +our $T_cmd_tid = -1; +sub dump_thread_is_alive_cmd +{ + my $cmd = shift; + $T_cmd_tid = get_hex(\@_); + printf("thread_is_alive ( $tid_format )\n", $T_cmd_tid); +} + +sub dump_thread_is_alive_rsp +{ + my $rsp = join('',@_); + + printf("thread_is_alive ( $tid_format ) =>", $T_cmd_tid); + if ($rsp eq 'OK') + { + print " alive.\n"; + } + else + { + print " dead.\n"; + } +} + +#---------------------------------------------------------------------- +# 'H' response +#---------------------------------------------------------------------- +sub dump_set_thread_rsp +{ + if (!is_error_response(@_)) + { + print join('',@_) . "\n"; + } +} + +#---------------------------------------------------------------------- +# 'q' command +#---------------------------------------------------------------------- +our $gen_query_cmd; +our $qRegisterInfo_reg_num = -1; +sub dump_general_query_cmd +{ + $gen_query_cmd = join('',@_); + if ($gen_query_cmd eq 'qC') + { + print 'get_current_pid ()'; + } + elsif ($gen_query_cmd eq 'qfThreadInfo') + { + print 'get_first_active_threads ()'; + } + elsif ($gen_query_cmd eq 'qsThreadInfo') + { + print 'get_subsequent_active_threads ()'; + } + elsif (index($gen_query_cmd, 'qThreadExtraInfo') == 0) + { + # qThreadExtraInfo,id + print 'get_thread_extra_info ()'; + } + elsif (index($gen_query_cmd, 'qThreadStopInfo') == 0) + { + # qThreadStopInfoXXXX + @_ = splice(@_, length('qThreadStopInfo')); + my $tid = get_addr(\@_); + printf('get_thread_stop_info ( thread = 0x%4.4x )', $tid); + } + elsif (index($gen_query_cmd, 'qSymbol:') == 0) + { + # qCRC:addr,length + print 'gdb_ready_to_serve_symbol_lookups ()'; + } + elsif (index($gen_query_cmd, 'qCRC:') == 0) + { + # qCRC:addr,length + @_ = splice(@_, length('qCRC:')); + my $address = get_addr(\@_); + shift @_; + my $length = join('', @_); + printf("compute_crc (addr = $addr_format, length = $length)", $address); + } + elsif (index($gen_query_cmd, 'qGetTLSAddr:') == 0) + { + # qGetTLSAddr:thread-id,offset,lm + @_ = splice(@_, length('qGetTLSAddr:')); + my ($tid, $offset, $lm) = split (/,/, join('', @_)); + print "get_thread_local_storage_addr (thread-id = $tid, offset = $offset, lm = $lm)"; + } + elsif ($gen_query_cmd eq 'qOffsets') + { + print 'get_section_offsets ()'; + } + elsif (index($gen_query_cmd, 'qRegisterInfo') == 0) + { + @_ = splice(@_, length('qRegisterInfo')); + $qRegisterInfo_reg_num = get_hex(\@_); + + printf "get_dynamic_register_info ($qRegisterInfo_reg_num)"; + } + else + { + print $gen_query_cmd; + } + print "\n"; +} + +#---------------------------------------------------------------------- +# 'q' response +#---------------------------------------------------------------------- +sub dump_general_query_rsp +{ + my $gen_query_rsp = join('',@_); + my $gen_query_rsp_len = length ($gen_query_rsp); + if ($gen_query_cmd eq 'qC' and index($gen_query_rsp, 'QC') == 0) + { + shift @_; shift @_; + my $pid = get_hex(\@_); + printf("pid = $pid_format\n", $pid); + return; + } + elsif (index($gen_query_cmd, 'qRegisterInfo') == 0) + { + if ($gen_query_rsp_len == 0) + { + print "$unimplemented_str\n"; + } + else + { + if (index($gen_query_rsp, 'name') == 0) + { + $qRegisterInfo_reg_num == 0 and $registers_aref = []; + + my @name_and_values = split (/;/, $gen_query_rsp); + + my $reg_name = undef; + my $byte_size = 0; + my $pseudo = 0; + foreach (@name_and_values) + { + my ($name, $value) = split /:/; + if ($name eq "name") { $reg_name = $value; } + elsif ($name eq "bitsize") { $byte_size = $value / 8; } + elsif ($name eq "container-regs") { $pseudo = 1; } + } + if (defined $reg_name and $byte_size > 0) + { + if ($byte_size == 4) {push @$registers_aref, { name => $reg_name, info => $reg32_href , pseudo => $pseudo };} + elsif ($byte_size == 8) {push @$registers_aref, { name => $reg_name, info => $reg64_href , pseudo => $pseudo };} + elsif ($byte_size == 1) {push @$registers_aref, { name => $reg_name, info => $reg8_href , pseudo => $pseudo };} + elsif ($byte_size == 2) {push @$registers_aref, { name => $reg_name, info => $reg16_href , pseudo => $pseudo };} + elsif ($byte_size == 10) {push @$registers_aref, { name => $reg_name, info => $reg80_href , pseudo => $pseudo };} + elsif ($byte_size == 12) {push @$registers_aref, { name => $reg_name, info => $float96_href , pseudo => $pseudo };} + elsif ($byte_size == 16) {push @$registers_aref, { name => $reg_name, info => $reg128_href , pseudo => $pseudo };} + elsif ($byte_size == 32) {push @$registers_aref, { name => $reg_name, info => $reg256_href , pseudo => $pseudo };} + } + } + elsif ($gen_query_rsp_len == 3 and index($gen_query_rsp, 'E') == 0) + { + calculate_max_register_name_length(); + } + } + } + elsif ($gen_query_cmd =~ 'qThreadStopInfo') + { + dump_stop_reply_packet (@_); + } + if (dump_standard_response(\@_)) + { + # Do nothing... + } + else + { + print join('',@_) . "\n"; + } +} + +#---------------------------------------------------------------------- +# 'Q' command +#---------------------------------------------------------------------- +our $gen_set_cmd; +sub dump_general_set_cmd +{ + $gen_query_cmd = join('',@_); + if ($gen_query_cmd eq 'QStartNoAckMode') + { + print "StartNoAckMode ()" + } + elsif ($gen_query_cmd eq 'QThreadSuffixSupported') + { + $thread_suffix_supported = 1; + print "ThreadSuffixSupported ()" + } + elsif (index($gen_query_cmd, 'QSetMaxPayloadSize:') == 0) + { + @_ = splice(@_, length('QSetMaxPayloadSize:')); + my $max_payload_size = get_hex(\@_); + # QSetMaxPayloadSize:XXXX where XXXX is a hex length of the max + # packet payload size supported by gdb + printf("SetMaxPayloadSize ( 0x%x (%u))", $max_payload_size, $max_payload_size); + } + elsif (index ($gen_query_cmd, 'QSetSTDIN:') == 0) + { + @_ = splice(@_, length('QSetSTDIN:')); + printf ("SetSTDIN (path ='%s')\n", get_hex_string (\@_)); + } + elsif (index ($gen_query_cmd, 'QSetSTDOUT:') == 0) + { + @_ = splice(@_, length('QSetSTDOUT:')); + printf ("SetSTDOUT (path ='%s')\n", get_hex_string (\@_)); + } + elsif (index ($gen_query_cmd, 'QSetSTDERR:') == 0) + { + @_ = splice(@_, length('QSetSTDERR:')); + printf ("SetSTDERR (path ='%s')\n", get_hex_string (\@_)); + } + else + { + print $gen_query_cmd; + } + print "\n"; +} + +#---------------------------------------------------------------------- +# 'k' command +#---------------------------------------------------------------------- +sub dump_kill_cmd +{ + my $cmd = shift; + print "kill (" . join('',@_) . ")\n"; +} + +#---------------------------------------------------------------------- +# 'g' command +#---------------------------------------------------------------------- +sub dump_read_regs_cmd +{ + my $cmd = shift; + print "read_registers ()\n"; +} + +#---------------------------------------------------------------------- +# 'G' command +#---------------------------------------------------------------------- +sub dump_write_regs_cmd +{ + print "write_registers:\n"; + my $cmd = shift; + foreach my $reg_href (@$registers_aref) + { + last if ($_[0] eq '#'); + if ($reg_href->{pseudo} == 0) + { + my $reg_info_href = $reg_href->{info}; + my $reg_name = $reg_href->{name}; + my $reg_extract = $reg_info_href->{extract}; + my $reg_format = $reg_info_href->{format}; + my $reg_val = &$reg_extract(\@_); + printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val); + } + } +} + +sub dump_read_regs_rsp +{ + print "read_registers () =>\n"; + if (!is_error_response(@_)) + { + # print join('',@_) . "\n"; + foreach my $reg_href (@$registers_aref) + { + last if ($_[0] eq '#'); + if ($reg_href->{pseudo} == 0) + { + my $reg_info_href = $reg_href->{info}; + my $reg_name = $reg_href->{name}; + my $reg_extract = $reg_info_href->{extract}; + my $reg_format = $reg_info_href->{format}; + my $reg_val = &$reg_extract(\@_); + printf("\t%*s = $reg_format\n", $max_register_name_len, $reg_name, $reg_val); + } + } + } +} + +sub dump_read_single_register_rsp +{ + dump_register_value(0, \@_, $reg_cmd_reg); + print "\n"; +} + +#---------------------------------------------------------------------- +# '_M' - allocate memory command (LLDB extension) +# +# Command: '_M' +# Arg1: Hex byte size as big endian hex string +# Separator: ',' +# Arg2: permissions as string that must be a string that contains any +# combination of 'r' (readable) 'w' (writable) or 'x' (executable) +# +# Returns: The address that was allocated as a big endian hex string +# on success, else an error "EXX" where XX are hex bytes +# that indicate an error code. +# +# Examples: +# _M10,rw # allocate 16 bytes with read + write permissions +# _M100,rx # allocate 256 bytes with read + execute permissions +#---------------------------------------------------------------------- +sub dump_allocate_memory_cmd +{ + shift; shift; # shift off the '_' and the 'M' + my $byte_size = get_addr(\@_); + shift; # Skip ',' + printf("allocate_memory ( byte_size = %u (0x%x), permissions = %s)\n", $byte_size, $byte_size, join('',@_)); +} + +sub dump_allocate_memory_rsp +{ + if (@_ == 3 and $_[0] == 'E') + { + printf("allocated memory addr = ERROR (%s))\n", join('',@_)); + } + else + { + printf("allocated memory addr = 0x%s\n", join('',@_)); + } +} + +#---------------------------------------------------------------------- +# '_m' - deallocate memory command (LLDB extension) +# +# Command: '_m' +# Arg1: Hex address as big endian hex string +# +# Returns: "OK" on success "EXX" on error +# +# Examples: +# _m201000 # Free previously allocated memory at address 0x201000 +#---------------------------------------------------------------------- +sub dump_deallocate_memory_cmd +{ + shift; shift; # shift off the '_' and the 'm' + printf("deallocate_memory ( addr = 0x%s)\n", join('',@_)); +} + + +#---------------------------------------------------------------------- +# 'p' command +#---------------------------------------------------------------------- +sub dump_read_single_register_cmd +{ + my $cmd = shift; + $reg_cmd_reg = get_hex(\@_); + my $thread = get_thread_from_thread_suffix (\@_); + my $reg_href = $$registers_aref[$reg_cmd_reg]; + + if (defined $thread) + { + print "read_register ( reg = \"$reg_href->{name}\", thread = $thread )\n"; + } + else + { + print "read_register ( reg = \"$reg_href->{name}\" )\n"; + } +} + + +#---------------------------------------------------------------------- +# 'P' command +#---------------------------------------------------------------------- +sub dump_write_single_register_cmd +{ + my $cmd = shift; + my $reg_num = get_hex(\@_); + shift (@_); # Discard the '=' + + print "write_register ( "; + dump_register_value(0, \@_, $reg_num); + my $thread = get_thread_from_thread_suffix (\@_); + if (defined $thread) + { + print ", thread = $thread"; + } + print " )\n"; +} + +#---------------------------------------------------------------------- +# 'm' command +#---------------------------------------------------------------------- +our $read_mem_address = 0; +sub dump_read_mem_cmd +{ + my $cmd = shift; + $read_mem_address = get_addr(\@_); + shift; # Skip ',' + printf("read_mem ( $addr_format, %s )\n", $read_mem_address, join('',@_)); +} + +#---------------------------------------------------------------------- +# 'm' response +#---------------------------------------------------------------------- +sub dump_read_mem_rsp +{ + # If the memory read was 2 or 4 bytes, print it out in native format + # instead of just as bytes. + my $num_nibbles = @_; + if ($num_nibbles == 2) + { + printf(" 0x%2.2x", get8(\@_)); + } + elsif ($num_nibbles == 4) + { + printf(" 0x%4.4x", get16(\@_)); + } + elsif ($num_nibbles == 8) + { + printf(" 0x%8.8x", get32(\@_)); + } + elsif ($num_nibbles == 16) + { + printf(" 0x%s", get64(\@_)); + } + else + { + my $curr_address = $read_mem_address; + my $nibble; + my $nibble_offset = 0; + my $max_nibbles_per_line = 2 * $max_bytes_per_line; + foreach $nibble (@_) + { + if (($nibble_offset % $max_nibbles_per_line) == 0) + { + ($nibble_offset > 0) and print "\n "; + printf("$addr_format: ", $curr_address + $nibble_offset/2); + } + (($nibble_offset % 2) == 0) and print ' '; + print $nibble; + $nibble_offset++; + } + } + print "\n"; +} + +#---------------------------------------------------------------------- +# 'c' or 's' command +#---------------------------------------------------------------------- +sub dump_continue_cmd +{ + my $cmd = shift; + my $cmd_str; + $cmd eq 'c' and $cmd_str = 'continue'; + $cmd eq 's' and $cmd_str = 'step'; + my $address = -1; + if (@_) + { + my $address = get_addr(\@_); + printf("%s ($addr_format)\n", $cmd_str, $address); + } + else + { + printf("%s ()\n", $cmd_str); + } +} + +#---------------------------------------------------------------------- +# 'Css' continue (C) with signal (ss where 'ss' is two hex digits) +# 'Sss' step (S) with signal (ss where 'ss' is two hex digits) +#---------------------------------------------------------------------- +sub dump_continue_with_signal_cmd +{ + my $cmd = shift; + my $address = -1; + my $cmd_str; + $cmd eq 'c' and $cmd_str = 'continue'; + $cmd eq 's' and $cmd_str = 'step'; + my $signal = get_hex(\@_); + if (@_) + { + my $address = 0; + if (@_ && $_[0] == ';') + { + shift; + $address = get_addr(\@_); + } + } + + if ($address != -1) + { + printf("%s_with_signal (signal = 0x%2.2x, address = $addr_format)\n", $cmd_str, $signal, $address); + } + else + { + printf("%s_with_signal (signal = 0x%2.2x)\n", $cmd_str, $signal); + } +} + +#---------------------------------------------------------------------- +# 'A' command +#---------------------------------------------------------------------- +sub dump_A_command +{ + my $cmd = get_expected_char(\@_, 'A') or print "error: incorrect command letter for argument packet, expected 'A'\n"; + printf("set_program_arguments (\n"); + do + { + my $arg_len = get_uint(\@_); + get_expected_char(\@_, ',') or die "error: missing comma after argument length...?\n"; + my $arg_idx = get_uint(\@_); + get_expected_char(\@_, ',') or die "error: missing comma after argument number...?\n"; + + my $arg = ''; + my $num_hex8_bytes = $arg_len/2; + for (1 .. $num_hex8_bytes) + { + $arg .= sprintf("%c", get8(\@_)) + } + printf(" <%3u> argv[%u] = '%s'\n", $arg_len, $arg_idx, $arg); + if (@_ > 0) + { + get_expected_char(\@_, ',') or die "error: missing comma after argument argument ASCII hex bytes...?\n"; + } + } while (@_ > 0); + printf(" )\n"); +} + + +#---------------------------------------------------------------------- +# 'z' and 'Z' command +#---------------------------------------------------------------------- +sub dump_bp_wp_command +{ + my $cmd = shift; + my $type = shift; + shift; # Skip ',' + my $address = get_addr(\@_); + shift; # Skip ',' + my $length = join('',@_); + if ($cmd eq 'z') + { + printf("remove $point_types[$type]($addr_format, %d)\n", $address, $length); + } + else + { + printf("insert $point_types[$type]($addr_format, %d)\n", $address, $length); + } +} + + +#---------------------------------------------------------------------- +# 'X' command +#---------------------------------------------------------------------- +sub dump_write_mem_binary_cmd +{ + my $cmd = shift; + my $address = get_addr(\@_); + shift; # Skip ',' + + my ($length, $binary) = split(/:/, join('',@_)); + printf("write_mem_binary ( $addr_format, %d, %s)\n", $address, $length, $binary); + +} + +#---------------------------------------------------------------------- +# 'M' command +#---------------------------------------------------------------------- +sub dump_write_mem_cmd +{ + my $cmd = shift; + my $address = get_addr(\@_); + shift; # Skip ',' + my ($length, $hex_bytes) = split(/:/, join('',@_)); +# printf("write_mem ( $addr_format, %d, %s)\n", $address, $length, $hex_bytes); + printf("write_mem ( addr = $addr_format, len = %d (0x%x), bytes = ", $address, $length, $length); + splice(@_, 0, length($length)+1); + + my $curr_address = $address; + my $nibble; + my $nibble_count = 0; + my $max_nibbles_per_line = 2 * $max_bytes_per_line; + foreach $nibble (@_) + { + (($nibble_count % 2) == 0) and print ' '; + print $nibble; + $nibble_count++; + } + + # If the memory to write is 2 or 4 bytes, print it out in native format + # instead of just as bytes. + if (@_ == 4) + { + printf(" ( 0x%4.4x )", get16(\@_)); + } + elsif (@_ == 8) + { + printf(" ( 0x%8.8x )", get32(\@_)); + } + print " )\n"; + +} + +#---------------------------------------------------------------------- +# 'v' command +#---------------------------------------------------------------------- +our $extended_rsp_callback = 0; +sub dump_extended_cmd +{ + $extended_rsp_callback = 0; + if (join('', @_[0..4]) eq "vCont") + { + dump_extended_continue_cmd(splice(@_,5)); + } + elsif (join('', @_[0..7]) eq 'vAttach;') + { + dump_attach_command (splice(@_,8)); + } + elsif (join('', @_[0..11]) eq 'vAttachWait;') + { + dump_attach_wait_command (splice(@_,12)); + } +} + +#---------------------------------------------------------------------- +# 'v' response +#---------------------------------------------------------------------- +sub dump_extended_rsp +{ + if ($extended_rsp_callback) + { + &$extended_rsp_callback(@_); + } + $extended_rsp_callback = 0; +} + +#---------------------------------------------------------------------- +# 'vAttachWait' command +#---------------------------------------------------------------------- +sub dump_attach_wait_command +{ + print "attach_wait ( "; + while (@_) + { + printf("%c", get8(\@_)) + } + printf " )\n"; + +} + +#---------------------------------------------------------------------- +# 'vAttach' command +#---------------------------------------------------------------------- +sub dump_attach_command +{ + printf("attach ( pid = %i )", get_hex(\@_)); + $extended_rsp_callback = \&dump_stop_reply_packet; +} + +#---------------------------------------------------------------------- +# 'vCont' command +#---------------------------------------------------------------------- +sub dump_extended_continue_cmd +{ + print "extended_continue ( "; + my $cmd = shift; + if ($cmd eq '?') + { + print "list supported modes )\n"; + $extended_rsp_callback = \&dump_extended_continue_rsp; + } + elsif ($cmd eq ';') + { + $extended_rsp_callback = \&dump_stop_reply_packet; + my $i = 0; + while ($#_ >= 0) + { + if ($i > 0) + { + print ", "; + } + my $continue_cmd = shift; + my $tmp; + if ($continue_cmd eq 'c') + { + print "continue"; + } + elsif ($continue_cmd eq 'C') + { + print "continue with signal "; + print shift; + print shift; + } + elsif ($continue_cmd eq 's') + { + print "step"; + } + elsif ($continue_cmd eq 'S') + { + print "step with signal "; + print shift; + print shift; + } + + if ($_[0] eq ':') + { + shift; # Skip ':' + print " for thread "; + while ($#_ >= 0) + { + $tmp = shift; + if (length($tmp) > 0 && $tmp ne ';') { + print $tmp; + } else { + last; + } + } + } + $i++; + } + + printf " )\n"; + } +} + +#---------------------------------------------------------------------- +# 'vCont' response +#---------------------------------------------------------------------- +sub dump_extended_continue_rsp +{ + if (scalar(@_) == 0) + { + print "$unimplemented_str\n"; + } + else + { + print "extended_continue supports " . join('',@_) . "\n"; + } +} + +#---------------------------------------------------------------------- +# Dump the command ascii for any unknown commands +#---------------------------------------------------------------------- +sub dump_other_cmd +{ + print "other = " . join('',@_) . "\n"; +} + +#---------------------------------------------------------------------- +# Check to see if the response was unsupported with appropriate checksum +#---------------------------------------------------------------------- +sub rsp_is_unsupported +{ + return join('',@_) eq "#00"; +} + +#---------------------------------------------------------------------- +# Check to see if the response was "OK" with appropriate checksum +#---------------------------------------------------------------------- +sub rsp_is_OK +{ + return join('',@_) eq "OK#9a"; +} + +#---------------------------------------------------------------------- +# Dump a response for an unknown command +#---------------------------------------------------------------------- +sub dump_other_rsp +{ + print "other = " . join('',@_) . "\n"; +} + +#---------------------------------------------------------------------- +# Get a byte from the ascii string assuming that the 2 nibble ascii +# characters are in hex. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get8 +{ + my $arrayref = shift; + my $val = hex(shift(@$arrayref) . shift(@$arrayref)); + return $val; +} + +#---------------------------------------------------------------------- +# Get a 16 bit integer and swap if $swap global is set to a non-zero +# value. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get16 +{ + my $arrayref = shift; + my $val = 0; + if ($swap) + { + $val = get8($arrayref) | + get8($arrayref) << 8; + } + else + { + $val = get8($arrayref) << 8 | + get8($arrayref) ; + } + return $val; +} + +#---------------------------------------------------------------------- +# Get a 32 bit integer and swap if $swap global is set to a non-zero +# value. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get32 +{ + my $arrayref = shift; + my $val = 0; + if ($swap) + { + $val = get8($arrayref) | + get8($arrayref) << 8 | + get8($arrayref) << 16 | + get8($arrayref) << 24 ; + } + else + { + $val = get8($arrayref) << 24 | + get8($arrayref) << 16 | + get8($arrayref) << 8 | + get8($arrayref) ; + } + return $val; +} + +#---------------------------------------------------------------------- +# Get a 64 bit hex value as a string +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get64 +{ + my $arrayref = shift; + my $val = ''; + my @nibbles; + if ($swap) + { + push @nibbles, splice(@$arrayref, 14, 2); + push @nibbles, splice(@$arrayref, 12, 2); + push @nibbles, splice(@$arrayref, 10, 2); + push @nibbles, splice(@$arrayref, 8, 2); + push @nibbles, splice(@$arrayref, 6, 2); + push @nibbles, splice(@$arrayref, 4, 2); + push @nibbles, splice(@$arrayref, 2, 2); + push @nibbles, splice(@$arrayref, 0, 2); + } + else + { + (@nibbles) = splice(@$arrayref, 0, ((64/8) * 2)); + } + $val = join('', @nibbles); + return $val; +} + +#---------------------------------------------------------------------- +# Get a 80 bit hex value as a string +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get80 +{ + my $arrayref = shift; + my $val = ''; + my @nibbles; + if ($swap) + { + push @nibbles, splice(@$arrayref, 18, 2); + push @nibbles, splice(@$arrayref, 16, 2); + push @nibbles, splice(@$arrayref, 14, 2); + push @nibbles, splice(@$arrayref, 12, 2); + push @nibbles, splice(@$arrayref, 10, 2); + push @nibbles, splice(@$arrayref, 8, 2); + push @nibbles, splice(@$arrayref, 6, 2); + push @nibbles, splice(@$arrayref, 4, 2); + push @nibbles, splice(@$arrayref, 2, 2); + push @nibbles, splice(@$arrayref, 0, 2); + } + else + { + (@nibbles) = splice(@$arrayref, 0, ((80/8) * 2)); + } + $val = join('', @nibbles); + return $val; +} + +#---------------------------------------------------------------------- +# Get a 96 bit hex value as a string +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get96 +{ + my $arrayref = shift; + my $val = ''; + my @nibbles; + if ($swap) + { + push @nibbles, splice(@$arrayref, 22, 2); + push @nibbles, splice(@$arrayref, 20, 2); + push @nibbles, splice(@$arrayref, 18, 2); + push @nibbles, splice(@$arrayref, 16, 2); + push @nibbles, splice(@$arrayref, 14, 2); + push @nibbles, splice(@$arrayref, 12, 2); + push @nibbles, splice(@$arrayref, 10, 2); + push @nibbles, splice(@$arrayref, 8, 2); + push @nibbles, splice(@$arrayref, 6, 2); + push @nibbles, splice(@$arrayref, 4, 2); + push @nibbles, splice(@$arrayref, 2, 2); + push @nibbles, splice(@$arrayref, 0, 2); + } + else + { + (@nibbles) = splice(@$arrayref, 0, ((96/8) * 2)); + } + $val = join('', @nibbles); + return $val; +} + +#---------------------------------------------------------------------- +# Get a 128 bit hex value as a string +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get128 +{ + my $arrayref = shift; + my $val = ''; + my @nibbles; + if ($swap) + { + push @nibbles, splice(@$arrayref, 30, 2); + push @nibbles, splice(@$arrayref, 28, 2); + push @nibbles, splice(@$arrayref, 26, 2); + push @nibbles, splice(@$arrayref, 24, 2); + push @nibbles, splice(@$arrayref, 22, 2); + push @nibbles, splice(@$arrayref, 20, 2); + push @nibbles, splice(@$arrayref, 18, 2); + push @nibbles, splice(@$arrayref, 16, 2); + push @nibbles, splice(@$arrayref, 14, 2); + push @nibbles, splice(@$arrayref, 12, 2); + push @nibbles, splice(@$arrayref, 10, 2); + push @nibbles, splice(@$arrayref, 8, 2); + push @nibbles, splice(@$arrayref, 6, 2); + push @nibbles, splice(@$arrayref, 4, 2); + push @nibbles, splice(@$arrayref, 2, 2); + push @nibbles, splice(@$arrayref, 0, 2); + } + else + { + (@nibbles) = splice(@$arrayref, 0, ((128/8) * 2)); + } + $val = join('', @nibbles); + return $val; +} + +#---------------------------------------------------------------------- +# Get a 256 bit hex value as a string +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get256 +{ + my $arrayref = shift; + my $val = ''; + my @nibbles; + if ($swap) + { + push @nibbles, splice(@$arrayref, 62, 2); + push @nibbles, splice(@$arrayref, 60, 2); + push @nibbles, splice(@$arrayref, 58, 2); + push @nibbles, splice(@$arrayref, 56, 2); + push @nibbles, splice(@$arrayref, 54, 2); + push @nibbles, splice(@$arrayref, 52, 2); + push @nibbles, splice(@$arrayref, 50, 2); + push @nibbles, splice(@$arrayref, 48, 2); + push @nibbles, splice(@$arrayref, 46, 2); + push @nibbles, splice(@$arrayref, 44, 2); + push @nibbles, splice(@$arrayref, 42, 2); + push @nibbles, splice(@$arrayref, 40, 2); + push @nibbles, splice(@$arrayref, 38, 2); + push @nibbles, splice(@$arrayref, 36, 2); + push @nibbles, splice(@$arrayref, 34, 2); + push @nibbles, splice(@$arrayref, 32, 2); + push @nibbles, splice(@$arrayref, 30, 2); + push @nibbles, splice(@$arrayref, 28, 2); + push @nibbles, splice(@$arrayref, 26, 2); + push @nibbles, splice(@$arrayref, 24, 2); + push @nibbles, splice(@$arrayref, 22, 2); + push @nibbles, splice(@$arrayref, 20, 2); + push @nibbles, splice(@$arrayref, 18, 2); + push @nibbles, splice(@$arrayref, 16, 2); + push @nibbles, splice(@$arrayref, 14, 2); + push @nibbles, splice(@$arrayref, 12, 2); + push @nibbles, splice(@$arrayref, 10, 2); + push @nibbles, splice(@$arrayref, 8, 2); + push @nibbles, splice(@$arrayref, 6, 2); + push @nibbles, splice(@$arrayref, 4, 2); + push @nibbles, splice(@$arrayref, 2, 2); + push @nibbles, splice(@$arrayref, 0, 2); + } + else + { + (@nibbles) = splice(@$arrayref, 0, ((256/8) * 2)); + } + $val = join('', @nibbles); + return $val; +} + +#---------------------------------------------------------------------- +# Get an unsigned integer value by grabbing items off the front of +# the array stopping when a non-digit char string is encountered. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it +#---------------------------------------------------------------------- +sub get_uint +{ + my $arrayref = shift; + @$arrayref == 0 and return 0; + my $val = 0; + while ($$arrayref[0] =~ /[0-9]/) + { + $val = $val * 10 + int(shift(@$arrayref)); + } + return $val; +} + +#---------------------------------------------------------------------- +# Check the first character in the array and if it matches the expected +# character, return that character, else return undef; +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it. If the expected +# character doesn't match, it won't touch the array. If the first +# character does match, it will shift it off and return it. +#---------------------------------------------------------------------- +sub get_expected_char +{ + my $arrayref = shift; + my $expected_char = shift; + if ($expected_char eq $$arrayref[0]) + { + return shift(@$arrayref); + } + return undef; +} +#---------------------------------------------------------------------- +# Get a hex value by grabbing items off the front of the array and +# stopping when a non-hex char string is encountered. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get_hex +{ + my $arrayref = shift; + my $my_swap = @_ ? shift : 0; + my $shift = 0; + my $val = 0; + while ($$arrayref[0] =~ /[0-9a-fA-F]/) + { + if ($my_swap) + { + my $byte = hex(shift(@$arrayref)) << 4 | hex(shift(@$arrayref)); + $val |= $byte << $shift; + $shift += 8; + } + else + { + $val <<= 4; + $val |= hex(shift(@$arrayref)); + } + } + return $val; +} + +#---------------------------------------------------------------------- +# Get an address value by grabbing items off the front of the array. +# +# The argument for this function needs to be a reference to an array +# that contains single character strings and the array will get +# updated by shifting characters off the front of it (no leading # "0x") +#---------------------------------------------------------------------- +sub get_addr +{ + get_hex(shift); +} + +sub get_hex_string +{ + my $arrayref = shift; + my $str = ''; + while ($$arrayref[0] =~ /[0-9a-fA-F]/ and $$arrayref[1] =~ /[0-9a-fA-F]/) + { + my $hi_nibble = hex(shift(@$arrayref)); + my $lo_nibble = hex(shift(@$arrayref)); + my $byte = ($hi_nibble << 4) | $lo_nibble; + $str .= chr($byte); + } + return $str; +} + +sub dump_stop_reply_data +{ + while ($#_ >= 0) + { + last unless ($_[0] ne '#'); + + + my $key = ''; + my $value = ''; + my $comment = ''; + if ($_[0] =~ /[0-9a-fA-F]/ && $_[1] =~ /[0-9a-fA-F]/) + { + my $reg_num = get8(\@_); + shift(@_); # Skip ':' + if (defined ($registers_aref) && $reg_num < @$registers_aref) + { + dump_register_value(1, \@_, $reg_num); + print "\n"; + shift(@_); # Skip ';' + next; + } + $key = sprintf("reg %u", $reg_num); + } + my $char; + + if (length($key) == 0) + { + while (1) + { + $char = shift(@_); + if (length($char) == 0 or $char eq ':' or $char eq '#') { last; } + $key .= $char; + } + } + + while (1) + { + $char = shift(@_); + if (length($char) == 0 or $char eq ';' or $char eq '#') { last; } + $value .= $char; + } + if ($key eq 'metype') + { + our %metype_to_name = ( + '1' => ' (EXC_BAD_ACCESS)', + '2' => ' (EXC_BAD_INSTRUCTION)', + '3' => ' (EXC_ARITHMETIC)', + '4' => ' (EXC_EMULATION)', + '5' => ' (EXC_SOFTWARE)', + '6' => ' (EXC_BREAKPOINT)', + '7' => ' (EXC_SYSCALL)', + '8' => ' (EXC_MACH_SYSCALL)', + '9' => ' (EXC_RPC_ALERT)', + '10' => ' (EXC_CRASH)' + ); + if (exists $metype_to_name{$value}) + { + $comment = $metype_to_name{$value}; + } + } + printf("\t%*s = %s$comment\n", $max_register_name_len, $key, $value); + } +} + +#---------------------------------------------------------------------- +# Dumps a Stop Reply Packet which happens in response to a step, +# continue, last signal, and probably a few other commands. +#---------------------------------------------------------------------- +sub dump_stop_reply_packet +{ + my $what = shift(@_); + if ($what eq 'S' or $what eq 'T') + { + my $signo = get8(\@_); + + our %signo_to_name = ( + '1' => ' SIGHUP', + '2' => ' SIGINT', + '3' => ' SIGQUIT', + '4' => ' SIGILL', + '5' => ' SIGTRAP', + '6' => ' SIGABRT', + '7' => ' SIGPOLL/SIGEMT', + '8' => ' SIGFPE', + '9' => ' SIGKILL', + '10' => ' SIGBUS', + '11' => ' SIGSEGV', + '12' => ' SIGSYS', + '13' => ' SIGPIPE', + '14' => ' SIGALRM', + '15' => ' SIGTERM', + '16' => ' SIGURG', + '17' => ' SIGSTOP', + '18' => ' SIGTSTP', + '19' => ' SIGCONT', + '20' => ' SIGCHLD', + '21' => ' SIGTTIN', + '22' => ' SIGTTOU', + '23' => ' SIGIO', + '24' => ' SIGXCPU', + '25' => ' SIGXFSZ', + '26' => ' SIGVTALRM', + '27' => ' SIGPROF', + '28' => ' SIGWINCH', + '29' => ' SIGINFO', + '30' => ' SIGUSR1', + '31' => ' SIGUSR2', + '145' => ' TARGET_EXC_BAD_ACCESS', # 0x91 + '146' => ' TARGET_EXC_BAD_INSTRUCTION', # 0x92 + '147' => ' TARGET_EXC_ARITHMETIC', # 0x93 + '148' => ' TARGET_EXC_EMULATION', # 0x94 + '149' => ' TARGET_EXC_SOFTWARE', # 0x95 + '150' => ' TARGET_EXC_BREAKPOINT' # 0x96 + ); + my $signo_str = sprintf("%i", $signo); + my $signo_name = ''; + if (exists $signo_to_name{$signo_str}) + { + $signo_name = $signo_to_name{$signo_str}; + } + printf ("signal (signo=%u$signo_name)\n", $signo); + dump_stop_reply_data (@_); + } + elsif ($what eq 'W') + { + print 'process_exited( ' . shift(@_) . shift(@_) . " )\n"; + } + elsif ($what eq 'X') + { + print 'process_terminated( ' . shift(@_) . shift(@_) . " )\n"; + } + elsif ($what eq 'O') + { + my $console_output = ''; + my $num_hex8_bytes = @_/2; + for (1 .. $num_hex8_bytes) + { + $console_output .= sprintf("%c", get8(\@_)) + } + + print "program_console_output('$console_output')\n"; + } +} + +#---------------------------------------------------------------------- +# '?' command +#---------------------------------------------------------------------- +sub dump_last_signal_cmd +{ + my $cmd = shift; + print 'last_signal (' . join('',@_) . ")\n"; +} + +sub dump_raw_command +{ + my $cmd_aref = shift; + my $callback_ref; + $curr_cmd = $$cmd_aref[0]; + + if ($curr_cmd eq 'q' or $curr_cmd eq 'Q' or $curr_cmd eq '_') + { + $curr_full_cmd = ''; + foreach my $ch (@$cmd_aref) + { + $ch !~ /[A-Za-z_]/ and last; + $curr_full_cmd .= $ch; + } + } + else + { + $curr_full_cmd = $curr_cmd; + } + + $curr_cmd eq '_' and $curr_cmd .= $$cmd_aref[1]; + $callback_ref = $cmd_callbacks{$curr_cmd}; + if ($callback_ref) + { + &$callback_ref(@$cmd_aref); + } + else + { + # Strip the command byte for responses since we injected that above + dump_other_cmd(@$cmd_aref); + } +} + +sub dump_standard_response +{ + my $cmd_aref = shift; + + my $cmd_len = scalar(@$cmd_aref); + if ($cmd_len == 0) + { + print "$unimplemented_str\n"; + return 1; + } + + my $response = join('', @$cmd_aref); + if ($response eq 'OK') + { + print "$success_str\n"; + return 1; + } + + if ($cmd_len == 3 and index($response, 'E') == 0) + { + print "ERROR: " . substr($response, 1) . "\n"; + return 1; + } + + return 0; +} +sub dump_raw_response +{ + my $cmd_aref = shift; + my $callback_ref; + + if ($packet_start_time != 0.0) + { + if (length($curr_full_cmd) > 0) + { + $packet_times{$curr_full_cmd} += $curr_time - $packet_start_time; + } + else + { + $packet_times{$curr_cmd} += $curr_time - $packet_start_time; + } + $packet_start_time = 0.0; + } + + $callback_ref = $rsp_callbacks{$curr_cmd}; + + if ($callback_ref) + { + &$callback_ref(@$cmd_aref); + } + else + { + dump_standard_response($cmd_aref) or dump_other_rsp(@$cmd_aref); + } + +} +#---------------------------------------------------------------------- +# Dumps any command and handles simple error checking on the responses +# for commands that are unsupported or OK. +#---------------------------------------------------------------------- +sub dump_command +{ + my $cmd_str = shift; + + # Dump the original command string if verbose is on + if ($opt_v) + { + print "dump_command($cmd_str)\n "; + } + + my @cmd_chars = extract_command($cmd_str); + my $is_cmd = 1; + + my $cmd = $cmd_chars[0]; + if ($cmd eq '$') + { + $is_cmd = 0; # Note that this is a reply + $cmd = $curr_cmd; # set the command byte appropriately + shift @cmd_chars; # remove the '$' from the cmd bytes + } + + # Check for common responses across all commands and handle them + # if we can + if ( $is_cmd == 0 ) + { + if (rsp_is_unsupported(@cmd_chars)) + { + print "$unimplemented_str\n"; + return; + } + elsif (rsp_is_OK(@cmd_chars)) + { + print "$success_str\n"; + return; + } + # Strip the checksum information for responses + strip_checksum(\@cmd_chars); + } + + my $callback_ref; + if ($is_cmd) { + $callback_ref = $cmd_callbacks{$cmd}; + } else { + $callback_ref = $rsp_callbacks{$cmd}; + } + + if ($callback_ref) + { + &$callback_ref(@cmd_chars); + } + else + { + # Strip the command byte for responses since we injected that above + if ($is_cmd) { + dump_other_cmd(@cmd_chars); + } else { + dump_other_rsp(@cmd_chars); + } + + } +} + + +#---------------------------------------------------------------------- +# Process a gdbserver log line by looking for getpkt and putkpt and +# tossing any other lines. + +#---------------------------------------------------------------------- +sub process_log_line +{ + my $line = shift; + #($opt_v and $opt_g) and print "# $line"; + + my $extract_cmd = 0; + my $delta_time = 0.0; + if ($line =~ /^(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$/) + { + my $leading_space = $1; + $curr_time = $2; + $line = $3; + if ($base_time == 0.0) + { + $base_time = $curr_time; + } + else + { + $delta_time = $curr_time - $last_time; + } + printf ("(%.6f, %+.6f): ", $curr_time - $base_time, $delta_time); + $last_time = $curr_time; + } + else + { + $curr_time = 0.0 + } + + if ($line =~ /getpkt /) + { + $extract_cmd = 1; + print "\n--> "; + $packet_start_time = $curr_time; + } + elsif ($line =~ /putpkt /) + { + $extract_cmd = 1; + print "<-- "; + } + elsif ($line =~ /.*Sent: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/) + { + $opt_g and print "maintenance dump-packets command: $1\n"; + my @raw_cmd_bytes = split(/ */, $1); + $packet_start_time = $curr_time; + print "\n--> "; + dump_raw_command(\@raw_cmd_bytes); + process_log_line($2); + } + elsif ($line =~ /.*Recvd: \[[0-9]+\.[0-9]+[:0-9]*\] (.*)/) + { + $opt_g and print "maintenance dump-packets reply: $1\n"; + my @raw_rsp_bytes = split(/ */, $1); + print "<-- "; + dump_raw_response(\@raw_rsp_bytes); + print "\n"; + } + elsif ($line =~ /getpkt: (.*)/) + { + if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) + { + $opt_g and print "command: $1\n"; + my @raw_cmd_bytes = split(/ */, $1); + print "--> "; + $packet_start_time = $curr_time; + dump_raw_command(\@raw_cmd_bytes); + } + elsif ($1 =~ /\+/) + { + #print "--> ACK\n"; + } + elsif ($1 =~ /-/) + { + #print "--> NACK\n"; + } + } + elsif ($line =~ /putpkt: (.*)/) + { + if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) + { + $opt_g and print "response: $1\n"; + my @raw_rsp_bytes = split(/ */, $1); + print "<-- "; + dump_raw_response(\@raw_rsp_bytes); + print "\n"; + } + elsif ($1 =~ /\+/) + { + #print "<-- ACK\n"; + } + elsif ($1 =~ /-/) + { + #print "<-- NACK\n"; + } + } + elsif ($line =~ /send packet: (.*)/) + { + if ($1 =~ /\$([^#]+)#[0-9a-fA-F]{2}/) + { + $opt_g and print "command: $1\n"; + my @raw_cmd_bytes = split(/ */, $1); + print "--> "; + $packet_start_time = $curr_time; + dump_raw_command(\@raw_cmd_bytes); + } + elsif ($1 =~ /\+/) + { + #print "--> ACK\n"; + } + elsif ($1 =~ /-/) + { + #print "--> NACK\n"; + } + } + elsif ($line =~ /read packet: (.*)/) + { + if ($1 =~ /\$([^#]*)#[0-9a-fA-F]{2}/) + { + $opt_g and print "response: $1\n"; + my @raw_rsp_bytes = split(/ */, $1); + print "<-- "; + dump_raw_response(\@raw_rsp_bytes); + print "\n"; + } + elsif ($1 =~ /\+/) + { + #print "<-- ACK\n"; + } + elsif ($1 =~ /-/) + { + #print "<-- NACK\n"; + } + } + elsif ($line =~ /Sending packet: \$([^#]+)#[0-9a-fA-F]{2}\.\.\.(.*)/) + { + $opt_g and print "command: $1\n"; + my @raw_cmd_bytes = split(/ */, $1); + print "\n--> "; + $packet_start_time = $curr_time; + dump_raw_command(\@raw_cmd_bytes); + process_log_line($2); + } + elsif ($line =~ /Packet received: (.*)/) + { + $opt_g and print "response: $1\n"; + my @raw_rsp_bytes = split(/ */, $1); + print "<-- "; + dump_raw_response(\@raw_rsp_bytes); + print "\n"; + } + + if ($extract_cmd) + { + my $beg = index($line, '("') + 2; + my $end = rindex($line, '");'); + $packet_start_time = $curr_time; + dump_command(substr($line, $beg, $end - $beg)); + } +} + + +our $line_num = 0; +while(<>) +{ + $line_num++; + $opt_q or printf("# %5d: $_", $line_num); + process_log_line($_); +} + +if (%packet_times) +{ + print "----------------------------------------------------------------------\n"; + print "Packet timing summary:\n"; + print "----------------------------------------------------------------------\n"; + print "Packet Time %\n"; + print "---------------------- -------- ------\n"; + my @packet_names = keys %packet_times; + my $total_packet_times = 0.0; + foreach my $key (@packet_names) + { + $total_packet_times += $packet_times{$key}; + } + + foreach my $value (sort {$packet_times{$b} cmp $packet_times{$a}} @packet_names) + { + my $percent = ($packet_times{$value} / $total_packet_times) * 100.0; + if ($percent < 10.0) + { + printf("%22s %1.6f %2.2f\n", $value, $packet_times{$value}, $percent); + + } + else + { + printf("%22s %1.6f %2.2f\n", $value, $packet_times{$value}, $percent); + } + } + print "---------------------- -------- ------\n"; + printf (" Total %1.6f 100.00\n", $total_packet_times); +} + + + + + + + diff --git a/scripts/finish-swig-wrapper-classes.sh b/scripts/finish-swig-wrapper-classes.sh new file mode 100755 index 0000000000000..806f2862af699 --- /dev/null +++ b/scripts/finish-swig-wrapper-classes.sh @@ -0,0 +1,101 @@ +#! /bin/sh + +# finish-swig-wrapper-classes.sh +# +# For each scripting language liblldb supports, we need to create the +# appropriate Script Bridge wrapper classes for that language so that +# users can call Script Bridge functions from within the script interpreter. +# +# We use SWIG to create a C++ file containing the appropriate wrapper classes +# and funcitons for each scripting language, before liblldb is built (thus +# the C++ file can be compiled into liblldb. In some cases, additional work +# may need to be done after liblldb has been compiled, to make the scripting +# language stuff fully functional. Any such post-processing is handled through +# the shell scripts called here. + +# 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 generated from running SWIG. +# PREFIX is the root directory used to determine where third-party modules +# for scripting languages should be installed. +# debug_flag (optional) determines whether or not this script outputs +# additional information when running. + +SRC_ROOT=$1 +TARGET_DIR=$2 +CONFIG_BUILD_DIR=$3 +PREFIX=$4 + +shift 4 + +if [ -n "$1" -a "$1" = "-debug" ] +then + debug_flag=$1 + Debug=1 + shift +else + debug_flag="" + Debug=0 +fi + +if [ -n "$1" -a "$1" = "-m" ] +then + makefile_flag="$1" + shift +else + makefile_flag="" +fi + +# +# For each scripting language, see if a post-processing script for that +# language exists, and if so, call it. +# +# For now the only language we support is Python, but we expect this to +# change. + +languages="Python" +cwd=${SRC_ROOT}/scripts + +for curlang in $languages +do + if [ $Debug -eq 1 ] + then + echo "Current language is $curlang" + fi + + if [ ! -d "$cwd/$curlang" ] + then + echo "error: unable to find $curlang script sub-dirctory" >&2 + continue + else + + if [ $Debug -eq 1 ] + then + echo "Found $curlang sub-directory" + fi + + cd $cwd/$curlang + + filename="./finish-swig-${curlang}-LLDB.sh" + + if [ -f $filename ] + then + if [ $Debug -eq 1 ] + then + echo "Found $curlang post-processing script for LLDB" + echo "Executing $curlang post-processing script..." + fi + + + ./finish-swig-${curlang}-LLDB.sh $SRC_ROOT $TARGET_DIR $CONFIG_BUILD_DIR "${PREFIX}" "${debug_flag}" "${makefile_flag}" + retval=$? + if [ $retval -ne 0 ]; then + echo "$(pwd)/finish-swig-${curlang}-LLDB.sh failed with exit code $retval" + exit $retval + fi + fi + fi +done + +exit 0 diff --git a/scripts/finishSwigWrapperClasses.py b/scripts/finishSwigWrapperClasses.py new file mode 100644 index 0000000000000..8d7d19ef1bdfc --- /dev/null +++ b/scripts/finishSwigWrapperClasses.py @@ -0,0 +1,368 @@ +""" Post process SWIG Bridge wrapper code Python script for Windows/LINUX/OSX platform + + -------------------------------------------------------------------------- + File: finishSwigWrapperClasses.py + + Overview: Python script(s) to finish off the SWIG Python C++ Script + Bridge wrapper code on the Windows/LINUX/OSX platform. + The Python scripts are equivalent to the shell script (.sh) + files. + We use SWIG to create a C++ file containing the appropriate + wrapper classes and functions for each scripting language, + before liblldb is built (thus the C++ file can be compiled + into liblldb. In some cases, additional work may need to be + done after liblldb has been compiled, to make the scripting + language stuff fully functional. Any such post-processing + is handled through the Python scripts called here. + + Gotchas: None. + + Copyright: None. + -------------------------------------------------------------------------- + +""" + +# Python modules: +import sys # Provide argument parsing +import os # Provide directory and file handling + +# Third party modules: + +# In-house modules: +import utilsArgsParse # Parse and validate this script's input arguments +import utilsOsType # Determine the OS type this script is running on +import utilsDebug # Debug Python scripts + +# Instantiations: +gbDbgVerbose = False # True = Turn on script function tracing, False = off. +gbDbgFlag = False # Global debug mode flag, set by input parameter + # --dbgFlag. True = operate in debug mode. +gbMakeFileFlag = False # True = yes called from makefile system, False = not. + +# User facing text: +strMsgErrorNoMain = "Program called by another Python script not allowed" +strExitMsgSuccess = "Program successful" +strExitMsgError = "Program error: " +strParameter = "Parameter: " +strMsgErrorOsTypeUnknown = "Unable to determine OS type" +strScriptDirNotFound = "Unable to locate the script directory \'/script\'" +strScriptLangsFound = "Found the following script languages:" +strPostProcessError = "Executing \'%s\' post process script failed: " +strScriptNotFound = "Unable to locate the post process script file \'%s\' in \'%s\'" +strScriptLangFound = "Found \'%s\' build script." +strScriptLangsFound = "Found the following script languages:" +strExecuteMsg = "Executing \'%s\' build script..." +strExecuteError = "Executing \'%s\' build script failed: " +strHelpInfo = "\ +Python script(s) to finish off the SWIG Python C++ Script \n\ +Bridge wrapper code on the Windows/LINUX/OSX platform. The Python \n\ +scripts are equivalent to the shell script (.sh) files \n\ +run on others platforms.\n\ +Args: -h (optional) Print help information on this program.\n\ + -d (optional) Determines whether or not this script\n\ + outputs additional information when running.\n\ + -m (optional) Specify called from Makefile system.\n\ + --srcRoot= The root of the lldb source tree.\n\ + --targetDir= Where the lldb framework/shared library gets put.\n\ + --cfgBldDir= (optional) Where the build-swig-Python-LLDB.py program \n\ + will put the lldb.py file it generated from running\n\ + SWIG.\n\ + --prefix= (optional) Is the root directory used to determine where\n\ + third-party modules for scripting languages should\n\ + be installed. Where non-Darwin systems want to put\n\ + the .py and .so files so that Python can find them\n\ + automatically. Python install directory.\n\ + --cmakeBuildConfiguration= (optional) Is the build configuration(Debug, Release, RelWithDebugInfo)\n\ + used to determine where the bin and lib directories are \n\ + created for a Windows build.\n\ + --argsFile= The args are read from a file instead of the\n\ + command line. Other command line args are ignored.\n\ +\n\ +Usage:\n\ + finishSwigWrapperClasses.py --srcRoot=ADirPath --targetDir=ADirPath\n\ + --cfgBldDir=ADirPath --prefix=ADirPath -m -d\n\ +\n\ +" #TAG_PROGRAM_HELP_INFO + +#++--------------------------------------------------------------------------- +# Details: Exit the program on success. Called on program successfully done +# its work. Returns a status result to the caller. +# Args: vnResult - (R) 0 or greater indicating success. +# vMsg - (R) Success message if any to show success to user. +# Returns: None. +# Throws: None. +#-- +def program_exit_success(vnResult, vMsg): + strMsg = "" + + if vMsg.__len__() != 0: + strMsg = "%s: %s (%d)" % (strExitMsgSuccess, vMsg, vnResult) + print(strMsg) + + sys.exit(vnResult) + +#++--------------------------------------------------------------------------- +# Details: Exit the program with error. Called on exit program failed its +# task. Returns a status result to the caller. +# Args: vnResult - (R) A negative number indicating error condition. +# vMsg - (R) Error message to show to user. +# Returns: None. +# Throws: None. +#-- +def program_exit_on_failure(vnResult, vMsg): + print(("%s%s (%d)" % (strExitMsgError, vMsg, vnResult))) + sys.exit(vnResult) + +#++--------------------------------------------------------------------------- +# Details: Exit the program return a exit result number and print a message. +# Positive numbers and zero are returned for success other error +# occurred. +# Args: vnResult - (R) A -ve (an error), 0 or +ve number (ok or status). +# vMsg - (R) Error message to show to user. +# Returns: None. +# Throws: None. +#-- +def program_exit(vnResult, vMsg): + if vnResult >= 0: + program_exit_success(vnResult, vMsg) + else: + program_exit_on_failure(vnResult, vMsg) + +#++--------------------------------------------------------------------------- +# Details: Dump input parameters. +# Args: vDictArgs - (R) Map of input args to value. +# Returns: None. +# Throws: None. +#-- +def print_out_input_parameters(vDictArgs): + for arg, val in list(vDictArgs.items()): + strEqs = "" + strQ = "" + if val.__len__() != 0: + strEqs = " =" + strQ = "\"" + print(("%s%s%s %s%s%s\n" % (strParameter, arg, strEqs, strQ, val, strQ))) + +#++--------------------------------------------------------------------------- +# Details: Validate the arguments passed to the program. This function exits +# the program should error with the arguments be found. +# Args: vArgv - (R) List of arguments and values. +# Returns: Int - 0 = success, -ve = some failure. +# Dict - Map of arguments names to argument values +# Throws: None. +#-- +def validate_arguments(vArgv): + dbg = utilsDebug.CDebugFnVerbose("validate_arguments()") + strMsg = "" + dictArgs = {} + nResult = 0 + strListArgs = "hdm" # Format "hiox:" = -h -i -o -x <arg> + listLongArgs = ["srcRoot=", "targetDir=", "cfgBldDir=", "prefix=", "cmakeBuildConfiguration=", + "argsFile"] + dictArgReq = { "-h": "o", # o = optional, m = mandatory + "-d": "o", + "-m": "o", + "--srcRoot": "m", + "--targetDir": "m", + "--cfgBldDir": "o", + "--prefix": "o", + "--cmakeBuildConfiguration": "o", + "--argsFile": "o" } + + # Check for mandatory parameters + nResult, dictArgs, strMsg = utilsArgsParse.parse(vArgv, strListArgs, + listLongArgs, + dictArgReq, + strHelpInfo) + if nResult < 0: + program_exit_on_failure(nResult, strMsg) + + # User input -h for help + if nResult == 1: + program_exit_success(0, strMsg) + + return (nResult, dictArgs) + +#++--------------------------------------------------------------------------- +# Details: Locate post process script language directory and the script within +# and execute. +# Args: vStrScriptLang - (R) Name of the script language to build. +# vstrFinishFileName - (R) Prefix file name to build full name. +# vDictArgs - (R) Program input parameters. +# Returns: Int - 0 = Success, < 0 some error condition. +# Str - Error message. +# Throws: None. +#-- +def run_post_process(vStrScriptLang, vstrFinishFileName, vDictArgs): + dbg = utilsDebug.CDebugFnVerbose("run_post_process()") + nResult = 0 + strStatusMsg = "" + strScriptFile = vstrFinishFileName % vStrScriptLang + strScriptFileDir = os.path.normpath(os.path.join(vDictArgs["--srcRoot"], "scripts", vStrScriptLang)) + strScriptFilePath = os.path.join(strScriptFileDir, strScriptFile) + + # Check for the existence of the script file + strPath = os.path.normcase(strScriptFilePath) + bOk = os.path.exists(strPath) + if bOk == False: + strDir = os.path.normcase(strScriptFileDir) + strStatusMsg = strScriptNotFound % (strScriptFile, strDir) + return (-9, strStatusMsg) + + if gbDbgFlag: + print((strScriptLangFound % vStrScriptLang)) + print((strExecuteMsg % vStrScriptLang)) + + # Change where Python looks for our modules + strDir = os.path.normcase(strScriptFileDir) + sys.path.append(strDir) + + # Execute the specific language script + dictArgs = vDictArgs # Remove any args not required before passing on + strModuleName = strScriptFile[: strScriptFile.__len__() - 3] + module = __import__(strModuleName) + nResult, strStatusMsg = module.main(dictArgs) + + # Revert sys path + sys.path.remove(strDir) + + return (nResult, strStatusMsg) + +#++--------------------------------------------------------------------------- +# Details: Step through each script language sub directory supported +# and execute post processing script for each scripting language, +# make sure the build script for that language exists. +# For now the only language we support is Python, but we expect this +# to change. +# Args: vDictArgs - (R) Program input parameters. +# Returns: Int - 0 = Success, < 0 some error condition. +# Str - Error message. +# Throws: None. +#-- +def run_post_process_for_each_script_supported(vDictArgs): + dbg = utilsDebug.CDebugFnVerbose("run_post_process_for_each_script_supported()") + nResult = 0 + strStatusMsg = "" + strScriptDir = os.path.normpath(os.path.join(vDictArgs["--srcRoot"], "scripts")) + strFinishFileName = "finishSwig%sLLDB.py" + + # Check for the existence of the scripts folder + strScriptsDir = os.path.normcase(strScriptDir) + bOk = os.path.exists(strScriptsDir) + if bOk == False: + return (-8, strScriptDirNotFound) + + # Look for any script language directories to build for + listDirs = ["Python"] + + # Iterate script directory find any script language directories + for scriptLang in listDirs: + # __pycache__ is a magic directory in Python 3 that holds .pyc files + if scriptLang != "__pycache__" and scriptLang != "swig_bot_lib": + dbg.dump_text("Executing language script for \'%s\'" % scriptLang) + nResult, strStatusMsg = run_post_process(scriptLang, strFinishFileName, + vDictArgs) + if nResult < 0: + break + + if nResult < 0: + strTmp = strPostProcessError % scriptLang + strTmp += strStatusMsg + strStatusMsg = strTmp + + return (nResult, strStatusMsg) + +#++--------------------------------------------------------------------------- +# Details: Program's main() with arguments passed in from the command line. +# Program either exits normally or with error from this function - +# top most level function. +# Args: vArgv - (R) List of arguments and values. +# Returns: None +# Throws: None. +#-- +def main(vArgv): + dbg = utilsDebug.CDebugFnVerbose("main()") + bOk = False + dictArgs = {} + nResult = 0 + strMsg = "" + + # The validate arguments fn will exit the program if tests fail + nResult, dictArgs = validate_arguments(vArgv) + + eOSType = utilsOsType.determine_os_type() + if eOSType == utilsOsType.EnumOsType.Unknown: + program_exit(-4, strMsgErrorOsTypeUnknown) + + global gbDbgFlag + gbDbgFlag = "-d" in dictArgs + if gbDbgFlag: + print_out_input_parameters(dictArgs) + + # Check to see if we were called from the Makefile system. If we were, check + # if the caller wants SWIG to generate a dependency file. + # Not used in this program, but passed through to the language script file + # called by this program + global gbMakeFileFlag + gbMakeFileFlag = "-m" in dictArgs + + nResult, strMsg = run_post_process_for_each_script_supported(dictArgs) + + program_exit(nResult, strMsg) + +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- + +#TAG_PROGRAM_HELP_INFO +""" Details: Program main entry point. + + -------------------------------------------------------------------------- + Args: -h (optional) Print help information on this program. + -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. + --cmakeBuildConfiguration= (optional) Is the build configuration(Debug, Release, RelWithDebugInfo)\n\ + used to determine where the bin and lib directories are \n\ + created for a Windows build.\n\ + --argsFile= The args are read from a file instead of the + command line. Other command line args are ignored. + Usage: + finishSwigWrapperClasses.py --srcRoot=ADirPath --targetDir=ADirPath + --cfgBldDir=ADirPath --prefix=ADirPath -m -d + + Results: 0 Success + -1 Error - invalid parameters passed. + -2 Error - incorrect number of mandatory parameters passed. + + -4 Error - unable to determine OS type. + -5 Error - program not run with name of "__main__". + -8 Error - unable to locate the scripts folder. + -9 Error - unable to locate the post process language script + file. + + -100+ - Error messages from the child language script file. + + -------------------------------------------------------------------------- + +""" + +# Called using "__main__" when not imported i.e. from the command line +if __name__ == "__main__": + utilsDebug.CDebugFnVerbose.bVerboseOn = gbDbgVerbose + dbg = utilsDebug.CDebugFnVerbose("__main__") + main(sys.argv[1:]) +else: + program_exit(-5, strMsgErrorNoMain) diff --git a/scripts/generate-vers.pl b/scripts/generate-vers.pl new file mode 100755 index 0000000000000..63374981e01e0 --- /dev/null +++ b/scripts/generate-vers.pl @@ -0,0 +1,56 @@ +#!/usr/bin/perl + +sub usage() +{ + print "Usage: generate-vers.pl /path/toproject.pbxproj program_name"; + exit(0); +} + +(scalar @ARGV == 2) or usage(); + +open $pbxproj, $ARGV[0] or die "Couldn't open ".$ARGV[0]; + +$lldb_version = None; +$lldb_train = None; +$lldb_revision = None; +$lldb_version_string = None; + +$product_name = "lldb"; + +while ($line = <$pbxproj>) +{ + chomp ($line); + + if ($lldb_version == None && + $line =~ /CURRENT_PROJECT_VERSION = ([0-9]+).([0-9]+).([0-9]+)(.[0-9])?/) + { + $lldb_version = $1; + $lldb_train = $2; + $lldb_revision = $3; + $lldb_patchlevel = $4; + + if ($lldb_patchlevel != None) + { + $lldb_version_string = $lldb_version.".".$lldb_train.".".$lldb_revision.".".$lldb_patchlevel; + } + else + { + $lldb_version_string = $lldb_version.".".$lldb_train.".".$lldb_revision; + } + } +} + +if (!$product_name || !$lldb_version_string) +{ + print "Couldn't get needed information from the .pbxproj"; + exit(-1); +} + +$uppercase_name = uc $product_name; +$lowercase_name = lc $product_name; + +close $pbxproj; + +$file_string = " const unsigned char ".$ARGV[1]."VersionString[] __attribute__ ((used)) = \"@(#)PROGRAM:".$uppercase_name." PROJECT:".$lowercase_name."-".$lldb_version_string."\" \"\\n\"; const double ".$ARGV[1]."VersionNumber __attribute__ ((used)) = (double)".$lldb_version.".".$lldb_train.";\n"; + +print $file_string; diff --git a/scripts/get_relative_lib_dir.py b/scripts/get_relative_lib_dir.py new file mode 100644 index 0000000000000..f7020d653fddc --- /dev/null +++ b/scripts/get_relative_lib_dir.py @@ -0,0 +1,44 @@ +import distutils.sysconfig +import os +import platform +import re +import sys + + +def get_python_relative_libdir(): + """Returns the appropropriate python libdir relative to the build directory. + + @param exe_path the path to the lldb executable + + @return the python path that needs to be added to sys.path (PYTHONPATH) + in order to find the lldb python module. + """ + if platform.system() != 'Linux': + return None + + # We currently have a bug in lldb -P that does not account for + # architecture variants in python paths for + # architecture-specific modules. Handle the lookup here. + # When that bug is fixed, we should just ask lldb for the + # right answer always. + arch_specific_libdir = distutils.sysconfig.get_python_lib(True, False) + split_libdir = arch_specific_libdir.split(os.sep) + lib_re = re.compile(r"^lib.+$") + + for i in range(len(split_libdir)): + match = lib_re.match(split_libdir[i]) + if match is not None: + # We'll call this the relative root of the lib dir. + # Things like RHEL will have an arch-specific python + # lib dir, which isn't 'lib' on x86_64. + return os.sep.join(split_libdir[i:]) + # Didn't resolve it. + return None + +if __name__ == '__main__': + lib_dir = get_python_relative_libdir() + if lib_dir is not None: + sys.stdout.write(lib_dir) + sys.exit(0) + else: + sys.exit(1) diff --git a/scripts/install-lldb.sh b/scripts/install-lldb.sh new file mode 100755 index 0000000000000..0ba4e7c5ee2b0 --- /dev/null +++ b/scripts/install-lldb.sh @@ -0,0 +1,59 @@ +#!/bin/sh + + +# This script will install the files from a "Debug" or "Release" build +# directory into the developer folder specified. + +NUM_EXPECTED_ARGS=2 + +PROGRAM=`basename $0` + +if [ $# -ne $NUM_EXPECTED_ARGS ]; then + echo This script will install the files from a 'Debug' or 'Release' build directory into the developer folder specified. + echo "usage: $PROGRAM <BUILD_DIR> <DEVELOPER_DIR>"; + echo "example: $PROGRAM ./Debug /Developer" + echo "example: $PROGRAM /build/Release /Xcode4" + exit 1; +fi + +BUILD_DIR=$1 +DEVELOPER_DIR=$2 + +if [ -d $BUILD_DIR ]; then + if [ -d $DEVELOPER_DIR ]; then + if [ -e "$BUILD_DIR/debugserver" ]; then + echo Updating "$DEVELOPER_DIR/usr/bin/debugserver" + sudo rm -rf "$DEVELOPER_DIR/usr/bin/debugserver" + sudo cp "$BUILD_DIR/debugserver" "$DEVELOPER_DIR/usr/bin/debugserver" + fi + + if [ -e "$BUILD_DIR/lldb" ]; then + echo Updating "$DEVELOPER_DIR/usr/bin/lldb" + sudo rm -rf "$DEVELOPER_DIR/usr/bin/lldb" + sudo cp "$BUILD_DIR/lldb" "$DEVELOPER_DIR/usr/bin/lldb" + fi + + if [ -e "$BUILD_DIR/libEnhancedDisassembly.dylib" ]; then + echo Updating "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib" + sudo rm -rf "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib" + sudo cp "$BUILD_DIR/libEnhancedDisassembly.dylib" "$DEVELOPER_DIR/usr/lib/libEnhancedDisassembly.dylib" + fi + + if [ -d "$BUILD_DIR/LLDB.framework" ]; then + echo Updating "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework" + sudo rm -rf "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework" + sudo cp -r "$BUILD_DIR/LLDB.framework" "$DEVELOPER_DIR/Library/PrivateFrameworks/LLDB.framework" + elif [ -e "$BUILD_DIR/LLDB.framework" ]; then + echo BUILD_DIR path to LLDB.framework is not a directory: "$BUILD_DIR/LLDB.framework" + exit 2; + fi + + else + echo DEVELOPER_DIR must be a directory: "$DEVELOPER_DIR" + exit 3; + fi + +else + echo BUILD_DIR must be a directory: "$BUILD_DIR" + exit 4; +fi diff --git a/scripts/install_custom_python.py b/scripts/install_custom_python.py new file mode 100644 index 0000000000000..5a8f48aac9491 --- /dev/null +++ b/scripts/install_custom_python.py @@ -0,0 +1,134 @@ +""" Copies the build output of a custom python interpreter to a directory + structure that mirrors that of an official Python distribution. + + -------------------------------------------------------------------------- + File: install_custom_python.py + + Overview: Most users build LLDB by linking against the standard + Python distribution installed on their system. Occasionally + a user may want to build their own version of Python, and on + platforms such as Windows this is a hard requirement. This + script will take the build output of a custom interpreter and + install it into a canonical structure that mirrors that of an + official Python distribution, thus allowing PYTHONHOME to be + set appropriately. + + Gotchas: None. + + Copyright: None. + -------------------------------------------------------------------------- + +""" + +import argparse +import itertools +import os +import shutil +import sys + +def copy_one_file(dest_dir, source_dir, filename): + source_path = os.path.join(source_dir, filename) + dest_path = os.path.join(dest_dir, filename) + print 'Copying file %s ==> %s...' % (source_path, dest_path) + shutil.copyfile(source_path, dest_path) + +def copy_named_files(dest_dir, source_dir, files, extensions, copy_debug_suffix_also): + for (file, ext) in itertools.product(files, extensions): + copy_one_file(dest_dir, source_dir, file + '.' + ext) + if copy_debug_suffix_also: + copy_one_file(dest_dir, source_dir, file + '_d.' + ext) + +def copy_subdirectory(dest_dir, source_dir, subdir): + dest_dir = os.path.join(dest_dir, subdir) + source_dir = os.path.join(source_dir, subdir) + print 'Copying directory %s ==> %s...' % (source_dir, dest_dir) + shutil.copytree(source_dir, dest_dir) + +def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix): + dest_dir = os.path.join(dest_dir, dest_subdir) + + print 'Copying distribution %s ==> %s' % (source_dir, dest_dir) + + os.mkdir(dest_dir) + PCbuild_dir = os.path.join(source_dir, 'PCbuild') + if source_prefix: + PCbuild_dir = os.path.join(PCbuild_dir, source_prefix) + # First copy the files that go into the root of the new distribution. This + # includes the Python executables, python27(_d).dll, and relevant PDB files. + print 'Copying Python executables...' + copy_named_files(dest_dir, PCbuild_dir, ['w9xpopen'], ['exe', 'pdb'], False) + copy_named_files(dest_dir, PCbuild_dir, ['python_d', 'pythonw_d'], ['exe'], False) + copy_named_files(dest_dir, PCbuild_dir, ['python', 'pythonw'], ['exe', 'pdb'], False) + copy_named_files(dest_dir, PCbuild_dir, ['python27'], ['dll', 'pdb'], True) + + # Next copy everything in the Include directory. + print 'Copying Python include directory' + copy_subdirectory(dest_dir, source_dir, 'Include') + + # Copy Lib folder (builtin Python modules) + print 'Copying Python Lib directory' + copy_subdirectory(dest_dir, source_dir, 'Lib') + + # Copy tools folder. These are probably not necessary, but we copy them anyway to + # match an official distribution as closely as possible. Note that we don't just copy + # the subdirectory recursively. The source distribution ships with many more tools + # than what you get by installing python regularly. We only copy the tools that appear + # in an installed distribution. + tools_dest_dir = os.path.join(dest_dir, 'Tools') + tools_source_dir = os.path.join(source_dir, 'Tools') + os.mkdir(tools_dest_dir) + copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n') + copy_subdirectory(tools_dest_dir, tools_source_dir, 'pynche') + copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts') + copy_subdirectory(tools_dest_dir, tools_source_dir, 'versioncheck') + copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker') + + pyd_names = ['_ctypes', '_ctypes_test', '_elementtree', '_multiprocessing', '_socket', + '_testcapi', 'pyexpat', 'select', 'unicodedata', 'winsound'] + + # Copy builtin extension modules (pyd files) + dlls_dir = os.path.join(dest_dir, 'DLLs') + os.mkdir(dlls_dir) + print 'Copying DLLs directory' + copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True) + + # Copy libs folder (implibs for the pyd files) + libs_dir = os.path.join(dest_dir, 'libs') + os.mkdir(libs_dir) + print 'Copying libs directory' + copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False) + copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True) + + +parser = argparse.ArgumentParser(description='Install a custom Python distribution') +parser.add_argument('--source', required=True, help='The root of the source tree where Python is built.') +parser.add_argument('--dest', required=True, help='The location to install the Python distributions.') +parser.add_argument('--overwrite', default=False, action='store_true', help='If the destination directory already exists, destroys its contents first.') +parser.add_argument('--silent', default=False, action='store_true', help='If --overwite was specified, suppress confirmation before deleting a directory tree.') + +args = parser.parse_args() + +args.source = os.path.normpath(args.source) +args.dest = os.path.normpath(args.dest) + +if not os.path.exists(args.source): + print 'The source directory %s does not exist. Exiting...' + sys.exit(1) + +if os.path.exists(args.dest): + if not args.overwrite: + print 'The destination directory \'%s\' already exists and --overwrite was not specified. Exiting...' % args.dest + sys.exit(1) + while not args.silent: + print 'Ok to recursively delete \'%s\' and all contents (Y/N)? Choosing Y will permanently delete the contents.' % args.dest + result = str.upper(sys.stdin.read(1)) + if result == 'N': + print 'Unable to copy files to the destination. The destination already exists.' + sys.exit(1) + elif result == 'Y': + break + shutil.rmtree(args.dest) + +os.mkdir(args.dest) +copy_distro(args.dest, 'x86', args.source, None) +copy_distro(args.dest, 'x64', args.source, 'amd64') diff --git a/scripts/interface/SBAddress.i b/scripts/interface/SBAddress.i new file mode 100644 index 0000000000000..735b42c1d5b69 --- /dev/null +++ b/scripts/interface/SBAddress.i @@ -0,0 +1,201 @@ +//===-- SWIG Interface for SBAddress ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"A section + offset based address class. + +The SBAddress class allows addresses to be relative to a section +that can move during runtime due to images (executables, shared +libraries, bundles, frameworks) being loaded at different +addresses than the addresses found in the object file that +represents them on disk. There are currently two types of addresses +for a section: + o file addresses + o load addresses + +File addresses represents the virtual addresses that are in the 'on +disk' object files. These virtual addresses are converted to be +relative to unique sections scoped to the object file so that +when/if the addresses slide when the images are loaded/unloaded +in memory, we can easily track these changes without having to +update every object (compile unit ranges, line tables, function +address ranges, lexical block and inlined subroutine address +ranges, global and static variables) each time an image is loaded or +unloaded. + +Load addresses represents the virtual addresses where each section +ends up getting loaded at runtime. Before executing a program, it +is common for all of the load addresses to be unresolved. When a +DynamicLoader plug-in receives notification that shared libraries +have been loaded/unloaded, the load addresses of the main executable +and any images (shared libraries) will be resolved/unresolved. When +this happens, breakpoints that are in one of these sections can be +set/cleared. + +See docstring of SBFunction for example usage of SBAddress." +) SBAddress; +class SBAddress +{ +public: + + SBAddress (); + + SBAddress (const lldb::SBAddress &rhs); + + SBAddress (lldb::SBSection section, + lldb::addr_t offset); + + %feature("docstring", " + Create an address by resolving a load address using the supplied target. + ") SBAddress; + SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target); + + ~SBAddress (); + + bool + IsValid () const; + + void + Clear (); + + addr_t + GetFileAddress () const; + + addr_t + GetLoadAddress (const lldb::SBTarget &target) const; + + void + SetLoadAddress (lldb::addr_t load_addr, + lldb::SBTarget &target); + + bool + OffsetAddress (addr_t offset); + + bool + GetDescription (lldb::SBStream &description); + + lldb::SBSection + GetSection (); + + lldb::addr_t + SBAddress::GetOffset (); + + void + SetAddress (lldb::SBSection section, + lldb::addr_t offset); + + + lldb::AddressClass + GetAddressClass (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// GetSymbolContext() and the following can lookup symbol information for a given address. + /// An address might refer to code or data from an existing module, or it + /// might refer to something on the stack or heap. The following functions + /// will only return valid values if the address has been resolved to a code + /// or data address using 'void SBAddress::SetLoadAddress(...)' or + /// 'lldb::SBAddress SBTarget::ResolveLoadAddress (...)'. + //------------------------------------------------------------------ + ") GetSymbolContext; + lldb::SBSymbolContext + GetSymbolContext (uint32_t resolve_scope); + + %feature("docstring", " + //------------------------------------------------------------------ + /// GetModule() and the following grab individual objects for a given address and + /// are less efficient if you want more than one symbol related objects. + /// Use one of the following when you want multiple debug symbol related + /// objects for an address: + /// lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t resolve_scope); + /// lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const SBAddress &addr, uint32_t resolve_scope); + /// One or more bits from the SymbolContextItem enumerations can be logically + /// OR'ed together to more efficiently retrieve multiple symbol objects. + //------------------------------------------------------------------ + ") GetModule; + lldb::SBModule + GetModule (); + + lldb::SBCompileUnit + GetCompileUnit (); + + lldb::SBFunction + GetFunction (); + + lldb::SBBlock + GetBlock (); + + lldb::SBSymbol + GetSymbol (); + + lldb::SBLineEntry + GetLineEntry (); + + %pythoncode %{ + def __get_load_addr_property__ (self): + '''Get the load address for a lldb.SBAddress using the current target.''' + return self.GetLoadAddress (target) + + def __set_load_addr_property__ (self, load_addr): + '''Set the load address for a lldb.SBAddress using the current target.''' + return self.SetLoadAddress (load_addr, target) + + def __int__(self): + '''Convert an address to a load address if there is a process and that process is alive, or to a file address otherwise.''' + if process.is_alive: + return self.GetLoadAddress (target) + else: + return self.GetFileAddress () + + def __oct__(self): + '''Convert the address to an octal string''' + return '%o' % int(self) + + def __hex__(self): + '''Convert the address to an hex string''' + return '0x%x' % int(self) + + __swig_getmethods__["module"] = GetModule + if _newclass: module = property(GetModule, None, doc='''A read only property that returns an lldb object that represents the module (lldb.SBModule) that this address resides within.''') + + __swig_getmethods__["compile_unit"] = GetCompileUnit + if _newclass: compile_unit = property(GetCompileUnit, None, doc='''A read only property that returns an lldb object that represents the compile unit (lldb.SBCompileUnit) that this address resides within.''') + + __swig_getmethods__["line_entry"] = GetLineEntry + if _newclass: line_entry = property(GetLineEntry, None, doc='''A read only property that returns an lldb object that represents the line entry (lldb.SBLineEntry) that this address resides within.''') + + __swig_getmethods__["function"] = GetFunction + if _newclass: function = property(GetFunction, None, doc='''A read only property that returns an lldb object that represents the function (lldb.SBFunction) that this address resides within.''') + + __swig_getmethods__["block"] = GetBlock + if _newclass: block = property(GetBlock, None, doc='''A read only property that returns an lldb object that represents the block (lldb.SBBlock) that this address resides within.''') + + __swig_getmethods__["symbol"] = GetSymbol + if _newclass: symbol = property(GetSymbol, None, doc='''A read only property that returns an lldb object that represents the symbol (lldb.SBSymbol) that this address resides within.''') + + __swig_getmethods__["offset"] = GetOffset + if _newclass: offset = property(GetOffset, None, doc='''A read only property that returns the section offset in bytes as an integer.''') + + __swig_getmethods__["section"] = GetSection + if _newclass: section = property(GetSection, None, doc='''A read only property that returns an lldb object that represents the section (lldb.SBSection) that this address resides within.''') + + __swig_getmethods__["file_addr"] = GetFileAddress + if _newclass: file_addr = property(GetFileAddress, None, doc='''A read only property that returns file address for the section as an integer. This is the address that represents the address as it is found in the object file that defines it.''') + + __swig_getmethods__["load_addr"] = __get_load_addr_property__ + __swig_setmethods__["load_addr"] = __set_load_addr_property__ + if _newclass: load_addr = property(__get_load_addr_property__, __set_load_addr_property__, doc='''A read/write property that gets/sets the SBAddress using load address. The setter resolves SBAddress using the SBTarget from lldb.target so this property can ONLY be used in the interactive script interpreter (i.e. under the lldb script command) and not in Python based commands, or breakpoint commands.''') + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBAttachInfo.i b/scripts/interface/SBAttachInfo.i new file mode 100644 index 0000000000000..4c8ef643c90a5 --- /dev/null +++ b/scripts/interface/SBAttachInfo.i @@ -0,0 +1,116 @@ +//===-- SWIG Interface for SBAttachInfo--------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBAttachInfo +{ +public: + SBAttachInfo (); + + SBAttachInfo (lldb::pid_t pid); + + SBAttachInfo (const char *path, bool wait_for); + + SBAttachInfo (const char *path, bool wait_for, bool async); + + SBAttachInfo (const lldb::SBAttachInfo &rhs); + + lldb::pid_t + GetProcessID (); + + void + SetProcessID (lldb::pid_t pid); + + void + SetExecutable (const char *path); + + void + SetExecutable (lldb::SBFileSpec exe_file); + + bool + GetWaitForLaunch (); + + void + SetWaitForLaunch (bool b); + + void + SetWaitForLaunch (bool b, bool async); + + bool + GetIgnoreExisting (); + + void + SetIgnoreExisting (bool b); + + uint32_t + GetResumeCount (); + + void + SetResumeCount (uint32_t c); + + const char * + GetProcessPluginName (); + + void + SetProcessPluginName (const char *plugin_name); + + uint32_t + GetUserID(); + + uint32_t + GetGroupID(); + + bool + UserIDIsValid (); + + bool + GroupIDIsValid (); + + void + SetUserID (uint32_t uid); + + void + SetGroupID (uint32_t gid); + + uint32_t + GetEffectiveUserID(); + + uint32_t + GetEffectiveGroupID(); + + bool + EffectiveUserIDIsValid (); + + bool + EffectiveGroupIDIsValid (); + + void + SetEffectiveUserID (uint32_t uid); + + void + SetEffectiveGroupID (uint32_t gid); + + lldb::pid_t + GetParentProcessID (); + + void + SetParentProcessID (lldb::pid_t pid); + + bool + ParentProcessIDIsValid(); + + lldb::SBListener + GetListener (); + + void + SetListener (lldb::SBListener &listener); +}; + +} // namespace lldb diff --git a/scripts/interface/SBBlock.i b/scripts/interface/SBBlock.i new file mode 100644 index 0000000000000..9180ef581d577 --- /dev/null +++ b/scripts/interface/SBBlock.i @@ -0,0 +1,179 @@ +//===-- SWIG Interface for SBBlock ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a lexical block. SBFunction contains SBBlock(s)." +) SBBlock; +class SBBlock +{ +public: + + SBBlock (); + + SBBlock (const lldb::SBBlock &rhs); + + ~SBBlock (); + + %feature("docstring", + "Does this block represent an inlined function?" + ) IsInlined; + bool + IsInlined () const; + + bool + IsValid () const; + + %feature("docstring", " + Get the function name if this block represents an inlined function; + otherwise, return None. + ") GetInlinedName; + const char * + GetInlinedName () const; + + %feature("docstring", " + Get the call site file if this block represents an inlined function; + otherwise, return an invalid file spec. + ") GetInlinedCallSiteFile; + lldb::SBFileSpec + GetInlinedCallSiteFile () const; + + %feature("docstring", " + Get the call site line if this block represents an inlined function; + otherwise, return 0. + ") GetInlinedCallSiteLine; + uint32_t + GetInlinedCallSiteLine () const; + + %feature("docstring", " + Get the call site column if this block represents an inlined function; + otherwise, return 0. + ") GetInlinedCallSiteColumn; + uint32_t + GetInlinedCallSiteColumn () const; + + %feature("docstring", "Get the parent block.") GetParent; + lldb::SBBlock + GetParent (); + + %feature("docstring", "Get the inlined block that is or contains this block.") GetContainingInlinedBlock; + lldb::SBBlock + GetContainingInlinedBlock (); + + %feature("docstring", "Get the sibling block for this block.") GetSibling; + lldb::SBBlock + GetSibling (); + + %feature("docstring", "Get the first child block.") GetFirstChild; + lldb::SBBlock + GetFirstChild (); + + uint32_t + GetNumRanges (); + + lldb::SBAddress + GetRangeStartAddress (uint32_t idx); + + lldb::SBAddress + GetRangeEndAddress (uint32_t idx); + + uint32_t + GetRangeIndexForBlockAddress (lldb::SBAddress block_addr); + + bool + GetDescription (lldb::SBStream &description); + + lldb::SBValueList + GetVariables (lldb::SBFrame& frame, + bool arguments, + bool locals, + bool statics, + lldb::DynamicValueType use_dynamic); + + lldb::SBValueList + GetVariables (lldb::SBTarget& target, + bool arguments, + bool locals, + bool statics); + + %pythoncode %{ + def get_range_at_index(self, idx): + if idx < self.GetNumRanges(): + return [self.GetRangeStartAddress(idx), self.GetRangeEndAddress(idx)] + return [] + + class ranges_access(object): + '''A helper object that will lazily hand out an array of lldb.SBAddress that represent address ranges for a block.''' + def __init__(self, sbblock): + self.sbblock = sbblock + + def __len__(self): + if self.sbblock: + return int(self.sbblock.GetNumRanges()) + return 0 + + def __getitem__(self, key): + count = len(self) + if type(key) is int: + return self.sbblock.get_range_at_index (key); + if isinstance(key, SBAddress): + range_idx = self.sbblock.GetRangeIndexForBlockAddress(key); + if range_idx < len(self): + return [self.sbblock.GetRangeStartAddress(range_idx), self.sbblock.GetRangeEndAddress(range_idx)] + else: + print("error: unsupported item type: %s" % type(key)) + return None + + def get_ranges_access_object(self): + '''An accessor function that returns a ranges_access() object which allows lazy block address ranges access.''' + return self.ranges_access (self) + + def get_ranges_array(self): + '''An accessor function that returns an array object that contains all ranges in this block object.''' + if not hasattr(self, 'ranges_array'): + self.ranges_array = [] + for idx in range(self.num_ranges): + self.ranges_array.append ([self.GetRangeStartAddress(idx), self.GetRangeEndAddress(idx)]) + return self.ranges_array + + def get_call_site(self): + return declaration(self.GetInlinedCallSiteFile(), self.GetInlinedCallSiteLine(), self.GetInlinedCallSiteColumn()) + + __swig_getmethods__["parent"] = GetParent + if _newclass: parent = property(GetParent, None, doc='''A read only property that returns the same result as GetParent().''') + + __swig_getmethods__["first_child"] = GetFirstChild + if _newclass: first_child = property(GetFirstChild, None, doc='''A read only property that returns the same result as GetFirstChild().''') + + __swig_getmethods__["call_site"] = get_call_site + if _newclass: call_site = property(get_call_site, None, doc='''A read only property that returns a lldb.declaration object that contains the inlined call site file, line and column.''') + + __swig_getmethods__["sibling"] = GetSibling + if _newclass: sibling = property(GetSibling, None, doc='''A read only property that returns the same result as GetSibling().''') + + __swig_getmethods__["name"] = GetInlinedName + if _newclass: name = property(GetInlinedName, None, doc='''A read only property that returns the same result as GetInlinedName().''') + + __swig_getmethods__["inlined_block"] = GetContainingInlinedBlock + if _newclass: inlined_block = property(GetContainingInlinedBlock, None, doc='''A read only property that returns the same result as GetContainingInlinedBlock().''') + + __swig_getmethods__["range"] = get_ranges_access_object + if _newclass: range = property(get_ranges_access_object, None, doc='''A read only property that allows item access to the address ranges for a block by integer (range = block.range[0]) and by lldb.SBAdddress (find the range that contains the specified lldb.SBAddress like "pc_range = lldb.frame.block.range[frame.addr]").''') + + __swig_getmethods__["ranges"] = get_ranges_array + if _newclass: ranges = property(get_ranges_array, None, doc='''A read only property that returns a list() object that contains all of the address ranges for the block.''') + + __swig_getmethods__["num_ranges"] = GetNumRanges + if _newclass: num_ranges = property(GetNumRanges, None, doc='''A read only property that returns the same result as GetNumRanges().''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBBreakpoint.i b/scripts/interface/SBBreakpoint.i new file mode 100644 index 0000000000000..6394d741b8517 --- /dev/null +++ b/scripts/interface/SBBreakpoint.i @@ -0,0 +1,266 @@ +//===-- SWIG Interface for SBBreakpoint -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a logical breakpoint and its associated settings. + +For example (from test/functionalities/breakpoint/breakpoint_ignore_count/ +TestBreakpointIgnoreCount.py), + + def breakpoint_ignore_count_python(self): + '''Use Python APIs to set breakpoint ignore count.''' + exe = os.path.join(os.getcwd(), 'a.out') + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Now create a breakpoint on main.c by name 'c'. + breakpoint = target.BreakpointCreateByName('c', 'a.out') + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + + # Get the breakpoint location from breakpoint after we verified that, + # indeed, it has one location. + location = breakpoint.GetLocationAtIndex(0) + self.assertTrue(location and + location.IsEnabled(), + VALID_BREAKPOINT_LOCATION) + + # Set the ignore count on the breakpoint location. + location.SetIgnoreCount(2) + self.assertTrue(location.GetIgnoreCount() == 2, + 'SetIgnoreCount() works correctly') + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple(None, None, os.getcwd()) + self.assertTrue(process, PROCESS_IS_VALID) + + # Frame#0 should be on main.c:37, frame#1 should be on main.c:25, and + # frame#2 should be on main.c:48. + #lldbutil.print_stacktraces(process) + from lldbutil import get_stopped_thread + thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread != None, 'There should be a thread stopped due to breakpoint') + frame0 = thread.GetFrameAtIndex(0) + frame1 = thread.GetFrameAtIndex(1) + frame2 = thread.GetFrameAtIndex(2) + self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and + frame1.GetLineEntry().GetLine() == self.line3 and + frame2.GetLineEntry().GetLine() == self.line4, + STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT) + + # The hit count for the breakpoint should be 3. + self.assertTrue(breakpoint.GetHitCount() == 3) + + process.Continue() + +SBBreakpoint supports breakpoint location iteration, for example, + + for bl in breakpoint: + print('breakpoint location load addr: %s' % hex(bl.GetLoadAddress())) + print('breakpoint location condition: %s' % hex(bl.GetCondition())) + +and rich comparion methods which allow the API program to use, + + if aBreakpoint == bBreakpoint: + ... + +to compare two breakpoints for equality." +) SBBreakpoint; +class SBBreakpoint +{ +public: + + typedef bool (*BreakpointHitCallback) (void *baton, + SBProcess &process, + SBThread &thread, + lldb::SBBreakpointLocation &location); + + SBBreakpoint (); + + SBBreakpoint (const lldb::SBBreakpoint& rhs); + + ~SBBreakpoint(); + + break_id_t + GetID () const; + + bool + IsValid() const; + + void + ClearAllBreakpointSites (); + + lldb::SBBreakpointLocation + FindLocationByAddress (lldb::addr_t vm_addr); + + lldb::break_id_t + FindLocationIDByAddress (lldb::addr_t vm_addr); + + lldb::SBBreakpointLocation + FindLocationByID (lldb::break_id_t bp_loc_id); + + lldb::SBBreakpointLocation + GetLocationAtIndex (uint32_t index); + + void + SetEnabled (bool enable); + + bool + IsEnabled (); + + void + SetOneShot (bool one_shot); + + bool + IsOneShot (); + + bool + IsInternal (); + + uint32_t + GetHitCount () const; + + void + SetIgnoreCount (uint32_t count); + + uint32_t + GetIgnoreCount () const; + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// The breakpoint stops only if the condition expression evaluates to true. + //-------------------------------------------------------------------------- + ") SetCondition; + void + SetCondition (const char *condition); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get the condition expression for the breakpoint. + //------------------------------------------------------------------ + ") GetCondition; + const char * + GetCondition (); + + void + SetThreadID (lldb::tid_t sb_thread_id); + + lldb::tid_t + GetThreadID (); + + void + SetThreadIndex (uint32_t index); + + uint32_t + GetThreadIndex() const; + + void + SetThreadName (const char *thread_name); + + const char * + GetThreadName () const; + + void + SetQueueName (const char *queue_name); + + const char * + GetQueueName () const; + + %feature("docstring", " + //------------------------------------------------------------------ + /// Set the name of the script function to be called when the breakpoint is hit. + //------------------------------------------------------------------ + ") SetScriptCallbackFunction; + void + SetScriptCallbackFunction (const char *callback_function_name); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Provide the body for the script function to be called when the breakpoint is hit. + /// The body will be wrapped in a function, which be passed two arguments: + /// 'frame' - which holds the bottom-most SBFrame of the thread that hit the breakpoint + /// 'bpno' - which is the SBBreakpointLocation to which the callback was attached. + /// + /// The error parameter is currently ignored, but will at some point hold the Python + /// compilation diagnostics. + /// Returns true if the body compiles successfully, false if not. + //------------------------------------------------------------------ + ") SetScriptCallbackBody; + SBError + SetScriptCallbackBody (const char *script_body_text); + + bool + AddName (const char *new_name); + + void + RemoveName (const char *name_to_remove); + + bool + MatchesName (const char *name); + + void + GetNames (SBStringList &names); + + size_t + GetNumResolvedLocations() const; + + size_t + GetNumLocations() const; + + bool + GetDescription (lldb::SBStream &description); + + bool + operator == (const lldb::SBBreakpoint& rhs); + + bool + operator != (const lldb::SBBreakpoint& rhs); + + static bool + EventIsBreakpointEvent (const lldb::SBEvent &event); + + static lldb::BreakpointEventType + GetBreakpointEventTypeFromEvent (const lldb::SBEvent& event); + + static lldb::SBBreakpoint + GetBreakpointFromEvent (const lldb::SBEvent& event); + + static lldb::SBBreakpointLocation + GetBreakpointLocationAtIndexFromEvent (const lldb::SBEvent& event, uint32_t loc_idx); + + static uint32_t + GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp); + + %pythoncode %{ + + __swig_getmethods__["id"] = GetID + if _newclass: id = property(GetID, None, doc='''A read only property that returns the ID of this breakpoint.''') + + __swig_getmethods__["enabled"] = IsEnabled + __swig_setmethods__["enabled"] = SetEnabled + if _newclass: enabled = property(IsEnabled, SetEnabled, doc='''A read/write property that configures whether this breakpoint is enabled or not.''') + + __swig_getmethods__["one_shot"] = IsOneShot + __swig_setmethods__["one_shot"] = SetOneShot + if _newclass: one_shot = property(IsOneShot, SetOneShot, doc='''A read/write property that configures whether this breakpoint is one-shot (deleted when hit) or not.''') + + __swig_getmethods__["num_locations"] = GetNumLocations + if _newclass: num_locations = property(GetNumLocations, None, doc='''A read only property that returns the count of locations of this breakpoint.''') + + %} + + +}; + +} // namespace lldb diff --git a/scripts/interface/SBBreakpointLocation.i b/scripts/interface/SBBreakpointLocation.i new file mode 100644 index 0000000000000..a3073538e6766 --- /dev/null +++ b/scripts/interface/SBBreakpointLocation.i @@ -0,0 +1,130 @@ +//===-- SWIG Interface for SBBreakpointLocation -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents one unique instance (by address) of a logical breakpoint. + +A breakpoint location is defined by the breakpoint that produces it, +and the address that resulted in this particular instantiation. +Each breakpoint location has its settable options. + +SBBreakpoint contains SBBreakpointLocation(s). See docstring of SBBreakpoint +for retrieval of an SBBreakpointLocation from an SBBreakpoint." +) SBBreakpointLocation; +class SBBreakpointLocation +{ +public: + + SBBreakpointLocation (); + + SBBreakpointLocation (const lldb::SBBreakpointLocation &rhs); + + ~SBBreakpointLocation (); + + break_id_t + GetID (); + + bool + IsValid() const; + + lldb::SBAddress + GetAddress(); + + lldb::addr_t + GetLoadAddress (); + + void + SetEnabled(bool enabled); + + bool + IsEnabled (); + + uint32_t + GetIgnoreCount (); + + void + SetIgnoreCount (uint32_t n); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// The breakpoint location stops only if the condition expression evaluates + /// to true. + //-------------------------------------------------------------------------- + ") SetCondition; + void + SetCondition (const char *condition); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get the condition expression for the breakpoint location. + //------------------------------------------------------------------ + ") GetCondition; + const char * + GetCondition (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Set the callback to the given Python function name. + //------------------------------------------------------------------ + ") SetScriptCallbackFunction; + void + SetScriptCallbackFunction (const char *callback_function_name); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Provide the body for the script function to be called when the breakpoint location is hit. + /// The body will be wrapped in a function, which be passed two arguments: + /// 'frame' - which holds the bottom-most SBFrame of the thread that hit the breakpoint + /// 'bpno' - which is the SBBreakpointLocation to which the callback was attached. + /// + /// The error parameter is currently ignored, but will at some point hold the Python + /// compilation diagnostics. + /// Returns true if the body compiles successfully, false if not. + //------------------------------------------------------------------ + ") SetScriptCallbackBody; + SBError + SetScriptCallbackBody (const char *script_body_text); + + void + SetThreadID (lldb::tid_t sb_thread_id); + + lldb::tid_t + GetThreadID (); + + void + SetThreadIndex (uint32_t index); + + uint32_t + GetThreadIndex() const; + + void + SetThreadName (const char *thread_name); + + const char * + GetThreadName () const; + + void + SetQueueName (const char *queue_name); + + const char * + GetQueueName () const; + + bool + IsResolved (); + + bool + GetDescription (lldb::SBStream &description, DescriptionLevel level); + + SBBreakpoint + GetBreakpoint (); +}; + +} // namespace lldb diff --git a/scripts/interface/SBBroadcaster.i b/scripts/interface/SBBroadcaster.i new file mode 100644 index 0000000000000..b5e25b6d52047 --- /dev/null +++ b/scripts/interface/SBBroadcaster.i @@ -0,0 +1,68 @@ +//===-- SWIG Interface for SBBroadcaster ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents an entity which can broadcast events. A default broadcaster is +associated with an SBCommandInterpreter, SBProcess, and SBTarget. For +example, use + + broadcaster = process.GetBroadcaster() + +to retrieve the process's broadcaster. + +See also SBEvent for example usage of interacting with a broadcaster." +) SBBroadcaster; +class SBBroadcaster +{ +public: + SBBroadcaster (); + + SBBroadcaster (const char *name); + + SBBroadcaster (const SBBroadcaster &rhs); + + ~SBBroadcaster(); + + bool + IsValid () const; + + void + Clear (); + + void + BroadcastEventByType (uint32_t event_type, bool unique = false); + + void + BroadcastEvent (const lldb::SBEvent &event, bool unique = false); + + void + AddInitialEventsToListener (const lldb::SBListener &listener, uint32_t requested_events); + + uint32_t + AddListener (const lldb::SBListener &listener, uint32_t event_mask); + + const char * + GetName () const; + + bool + EventTypeHasListeners (uint32_t event_type); + + bool + RemoveListener (const lldb::SBListener &listener, uint32_t event_mask = UINT32_MAX); + + bool + operator == (const lldb::SBBroadcaster &rhs) const; + + bool + operator != (const lldb::SBBroadcaster &rhs) const; +}; + +} // namespace lldb diff --git a/scripts/interface/SBCommandInterpreter.i b/scripts/interface/SBCommandInterpreter.i new file mode 100644 index 0000000000000..c427d38b14d82 --- /dev/null +++ b/scripts/interface/SBCommandInterpreter.i @@ -0,0 +1,218 @@ +//===-- SWIG Interface for SBCommandInterpreter -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"SBCommandInterpreterRunOptions controls how the RunCommandInterpreter runs the code it is fed. +A default SBCommandInterpreterRunOptions object has: + StopOnContinue: false + StopOnError: false + StopOnCrash: false + EchoCommands: true + PrintResults: true + AddToHistory: true + + +") SBCommandInterpreterRunOptions; +class SBCommandInterpreterRunOptions +{ +friend class SBDebugger; +public: + SBCommandInterpreterRunOptions(); + ~SBCommandInterpreterRunOptions(); + + bool + GetStopOnContinue () const; + + void + SetStopOnContinue (bool); + + bool + GetStopOnError () const; + + void + SetStopOnError (bool); + + bool + GetStopOnCrash () const; + + void + SetStopOnCrash (bool); + + bool + GetEchoCommands () const; + + void + SetEchoCommands (bool); + + bool + GetPrintResults () const; + + void + SetPrintResults (bool); + + bool + GetAddToHistory () const; + + void + SetAddToHistory (bool); +private: + lldb_private::CommandInterpreterRunOptions * + get () const; + + lldb_private::CommandInterpreterRunOptions & + ref () const; + + // This is set in the constructor and will always be valid. + mutable std::unique_ptr<lldb_private::CommandInterpreterRunOptions> m_opaque_up; +}; + +%feature("docstring", +"SBCommandInterpreter handles/interprets commands for lldb. You get the +command interpreter from the SBDebugger instance. For example (from test/ +python_api/interpreter/TestCommandInterpreterAPI.py), + + def command_interpreter_api(self): + '''Test the SBCommandInterpreter APIs.''' + exe = os.path.join(os.getcwd(), 'a.out') + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Retrieve the associated command interpreter from our debugger. + ci = self.dbg.GetCommandInterpreter() + self.assertTrue(ci, VALID_COMMAND_INTERPRETER) + + # Exercise some APIs.... + + self.assertTrue(ci.HasCommands()) + self.assertTrue(ci.HasAliases()) + self.assertTrue(ci.HasAliasOptions()) + self.assertTrue(ci.CommandExists('breakpoint')) + self.assertTrue(ci.CommandExists('target')) + self.assertTrue(ci.CommandExists('platform')) + self.assertTrue(ci.AliasExists('file')) + self.assertTrue(ci.AliasExists('run')) + self.assertTrue(ci.AliasExists('bt')) + + res = lldb.SBCommandReturnObject() + ci.HandleCommand('breakpoint set -f main.c -l %d' % self.line, res) + self.assertTrue(res.Succeeded()) + ci.HandleCommand('process launch', res) + self.assertTrue(res.Succeeded()) + + process = ci.GetProcess() + self.assertTrue(process) + + ... + +The HandleCommand() instance method takes two args: the command string and +an SBCommandReturnObject instance which encapsulates the result of command +execution. +") SBCommandInterpreter; +class SBCommandInterpreter +{ +public: + enum + { + eBroadcastBitThreadShouldExit = (1 << 0), + eBroadcastBitResetPrompt = (1 << 1), + eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit + eBroadcastBitAsynchronousOutputData = (1 << 3), + eBroadcastBitAsynchronousErrorData = (1 << 4) + }; + + SBCommandInterpreter (const lldb::SBCommandInterpreter &rhs); + + ~SBCommandInterpreter (); + + static const char * + GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type); + + static const char * + GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type); + + static bool + EventIsCommandInterpreterEvent (const lldb::SBEvent &event); + + bool + IsValid() const; + + const char * + GetIOHandlerControlSequence(char ch); + + bool + GetPromptOnQuit(); + + void + SetPromptOnQuit(bool b); + + void + ResolveCommand(const char *command_line, SBCommandReturnObject &result); + + bool + CommandExists (const char *cmd); + + bool + AliasExists (const char *cmd); + + lldb::SBBroadcaster + GetBroadcaster (); + + static const char * + GetBroadcasterClass (); + + bool + HasCommands (); + + bool + HasAliases (); + + bool + HasAliasOptions (); + + lldb::SBProcess + GetProcess (); + + lldb::SBDebugger + GetDebugger (); + + void + SourceInitFileInHomeDirectory (lldb::SBCommandReturnObject &result); + + void + SourceInitFileInCurrentWorkingDirectory (lldb::SBCommandReturnObject &result); + + lldb::ReturnStatus + HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false); + + lldb::ReturnStatus + HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false); + + void + HandleCommandsFromFile (lldb::SBFileSpec &file, + lldb::SBExecutionContext &override_context, + lldb::SBCommandInterpreterRunOptions &options, + lldb::SBCommandReturnObject result); + + int + HandleCompletion (const char *current_line, + uint32_t cursor_pos, + int match_start_point, + int max_return_elements, + lldb::SBStringList &matches); + + bool + IsActive (); + +}; + +} // namespace lldb diff --git a/scripts/interface/SBCommandReturnObject.i b/scripts/interface/SBCommandReturnObject.i new file mode 100644 index 0000000000000..5ade97bebfec4 --- /dev/null +++ b/scripts/interface/SBCommandReturnObject.i @@ -0,0 +1,107 @@ +//===-- SWIG Interface for SBCommandReturnObject ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a container which holds the result from command execution. +It works with SBCommandInterpreter.HandleCommand() to encapsulate the result +of command execution. + +See SBCommandInterpreter for example usage of SBCommandReturnObject." +) SBCommandReturnObject; +class SBCommandReturnObject +{ +public: + + SBCommandReturnObject (); + + SBCommandReturnObject (const lldb::SBCommandReturnObject &rhs); + + ~SBCommandReturnObject (); + + bool + IsValid() const; + + const char * + GetOutput (); + + const char * + GetError (); + + size_t + GetOutputSize (); + + size_t + GetErrorSize (); + + const char * + GetOutput (bool only_if_no_immediate); + + const char * + GetError (bool if_no_immediate); + + size_t + PutOutput (FILE *fh); + + size_t + PutError (FILE *fh); + + void + Clear(); + + void + SetStatus (lldb::ReturnStatus status); + + void + SetError (lldb::SBError &error, + const char *fallback_error_cstr = NULL); + + void + SetError (const char *error_cstr); + + lldb::ReturnStatus + GetStatus(); + + bool + Succeeded (); + + bool + HasResult (); + + void + AppendMessage (const char *message); + + void + AppendWarning (const char *message); + + bool + GetDescription (lldb::SBStream &description); + + void + SetImmediateOutputFile (FILE *fh); + + void + SetImmediateErrorFile (FILE *fh); + + void + PutCString(const char* string, int len); + + // wrapping the variadic Printf() with a plain Print() + // because it is hard to support varargs in SWIG bridgings + %extend { + void Print (const char* str) + { + self->Printf("%s", str); + } + } + +}; + +} // namespace lldb diff --git a/scripts/interface/SBCommunication.i b/scripts/interface/SBCommunication.i new file mode 100644 index 0000000000000..99814d9f30342 --- /dev/null +++ b/scripts/interface/SBCommunication.i @@ -0,0 +1,82 @@ +//===-- SWIG Interface for SBCommunication ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBCommunication +{ +public: + enum { + eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost. + eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available. + eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients. + eBroadcastBitReadThreadShouldExit = (1 << 3), ///< Sent by clients that need to cancel the read thread. + eBroadcastBitPacketAvailable = (1 << 4), ///< Sent when data received makes a complete packet. + eAllEventBits = 0xffffffff + }; + + typedef void (*ReadThreadBytesReceived) (void *baton, const void *src, size_t src_len); + + SBCommunication (); + SBCommunication (const char * broadcaster_name); + ~SBCommunication (); + + + bool + IsValid () const; + + lldb::SBBroadcaster + GetBroadcaster (); + + static const char *GetBroadcasterClass(); + + lldb::ConnectionStatus + AdoptFileDesriptor (int fd, bool owns_fd); + + lldb::ConnectionStatus + Connect (const char *url); + + lldb::ConnectionStatus + Disconnect (); + + bool + IsConnected () const; + + bool + GetCloseOnEOF (); + + void + SetCloseOnEOF (bool b); + + size_t + Read (void *dst, + size_t dst_len, + uint32_t timeout_usec, + lldb::ConnectionStatus &status); + + size_t + Write (const void *src, + size_t src_len, + lldb::ConnectionStatus &status); + + bool + ReadThreadStart (); + + bool + ReadThreadStop (); + + bool + ReadThreadIsRunning (); + + bool + SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback, + void *callback_baton); +}; + +} // namespace lldb diff --git a/scripts/interface/SBCompileUnit.i b/scripts/interface/SBCompileUnit.i new file mode 100644 index 0000000000000..430e7447d9973 --- /dev/null +++ b/scripts/interface/SBCompileUnit.i @@ -0,0 +1,130 @@ +//===-- SWIG Interface for SBCompileUnit ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a compilation unit, or compiled source file. + +SBCompileUnit supports line entry iteration. For example, + + # Now get the SBSymbolContext from this frame. We want everything. :-) + context = frame0.GetSymbolContext(lldb.eSymbolContextEverything) + ... + + compileUnit = context.GetCompileUnit() + + for lineEntry in compileUnit: + print('line entry: %s:%d' % (str(lineEntry.GetFileSpec()), + lineEntry.GetLine())) + print('start addr: %s' % str(lineEntry.GetStartAddress())) + print('end addr: %s' % str(lineEntry.GetEndAddress())) + +produces: + +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 +start addr: a.out[0x100000d98] +end addr: a.out[0x100000da3] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 +start addr: a.out[0x100000da3] +end addr: a.out[0x100000da9] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 +start addr: a.out[0x100000da9] +end addr: a.out[0x100000db6] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 +start addr: a.out[0x100000db6] +end addr: a.out[0x100000dbc] +... + +See also SBSymbolContext and SBLineEntry" +) SBCompileUnit; +class SBCompileUnit +{ +public: + + SBCompileUnit (); + + SBCompileUnit (const lldb::SBCompileUnit &rhs); + + ~SBCompileUnit (); + + bool + IsValid () const; + + lldb::SBFileSpec + GetFileSpec () const; + + uint32_t + GetNumLineEntries () const; + + lldb::SBLineEntry + GetLineEntryAtIndex (uint32_t idx) const; + + uint32_t + FindLineEntryIndex (uint32_t start_idx, + uint32_t line, + lldb::SBFileSpec *inline_file_spec) const; + + uint32_t + FindLineEntryIndex (uint32_t start_idx, + uint32_t line, + lldb::SBFileSpec *inline_file_spec, + bool exact) const; + + SBFileSpec + GetSupportFileAtIndex (uint32_t idx) const; + + uint32_t + GetNumSupportFiles () const; + + uint32_t + FindSupportFileIndex (uint32_t start_idx, const SBFileSpec &sb_file, bool full); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get all types matching \a type_mask from debug info in this + /// compile unit. + /// + /// @param[in] type_mask + /// A bitfield that consists of one or more bits logically OR'ed + /// together from the lldb::TypeClass enumeration. This allows + /// you to request only structure types, or only class, struct + /// and union types. Passing in lldb::eTypeClassAny will return + /// all types found in the debug information for this compile + /// unit. + /// + /// @return + /// A list of types in this compile unit that match \a type_mask + //------------------------------------------------------------------ + ") GetTypes; + lldb::SBTypeList + GetTypes (uint32_t type_mask = lldb::eTypeClassAny); + + lldb::LanguageType + GetLanguage (); + + bool + GetDescription (lldb::SBStream &description); + + bool + operator == (const lldb::SBCompileUnit &rhs) const; + + bool + operator != (const lldb::SBCompileUnit &rhs) const; + + %pythoncode %{ + __swig_getmethods__["file"] = GetFileSpec + if _newclass: file = property(GetFileSpec, None, doc='''A read only property that returns the same result an lldb object that represents the source file (lldb.SBFileSpec) for the compile unit.''') + + __swig_getmethods__["num_line_entries"] = GetNumLineEntries + if _newclass: num_line_entries = property(GetNumLineEntries, None, doc='''A read only property that returns the number of line entries in a compile unit as an integer.''') + %} +}; + +} // namespace lldb diff --git a/scripts/interface/SBData.i b/scripts/interface/SBData.i new file mode 100644 index 0000000000000..41aaf8dbdedc3 --- /dev/null +++ b/scripts/interface/SBData.i @@ -0,0 +1,340 @@ +//===-- SWIG Interface for SBData -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +namespace lldb { + +class SBData +{ +public: + + SBData (); + + SBData (const SBData &rhs); + + ~SBData (); + + uint8_t + GetAddressByteSize (); + + void + SetAddressByteSize (uint8_t addr_byte_size); + + void + Clear (); + + bool + IsValid(); + + size_t + GetByteSize (); + + lldb::ByteOrder + GetByteOrder(); + + void + SetByteOrder (lldb::ByteOrder endian); + + float + GetFloat (lldb::SBError& error, lldb::offset_t offset); + + double + GetDouble (lldb::SBError& error, lldb::offset_t offset); + + long double + GetLongDouble (lldb::SBError& error, lldb::offset_t offset); + + lldb::addr_t + GetAddress (lldb::SBError& error, lldb::offset_t offset); + + uint8_t + GetUnsignedInt8 (lldb::SBError& error, lldb::offset_t offset); + + uint16_t + GetUnsignedInt16 (lldb::SBError& error, lldb::offset_t offset); + + uint32_t + GetUnsignedInt32 (lldb::SBError& error, lldb::offset_t offset); + + uint64_t + GetUnsignedInt64 (lldb::SBError& error, lldb::offset_t offset); + + int8_t + GetSignedInt8 (lldb::SBError& error, lldb::offset_t offset); + + int16_t + GetSignedInt16 (lldb::SBError& error, lldb::offset_t offset); + + int32_t + GetSignedInt32 (lldb::SBError& error, lldb::offset_t offset); + + int64_t + GetSignedInt64 (lldb::SBError& error, lldb::offset_t offset); + + const char* + GetString (lldb::SBError& error, lldb::offset_t offset); + + bool + GetDescription (lldb::SBStream &description, lldb::addr_t base_addr); + + size_t + ReadRawData (lldb::SBError& error, + lldb::offset_t offset, + void *buf, + size_t size); + + void + SetData (lldb::SBError& error, const void *buf, size_t size, lldb::ByteOrder endian, uint8_t addr_size); + + bool + Append (const SBData& rhs); + + static lldb::SBData + CreateDataFromCString (lldb::ByteOrder endian, uint32_t addr_byte_size, const char* data); + + // in the following CreateData*() and SetData*() prototypes, the two parameters array and array_len + // should not be renamed or rearranged, because doing so will break the SWIG typemap + static lldb::SBData + CreateDataFromUInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint64_t* array, size_t array_len); + + static lldb::SBData + CreateDataFromUInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint32_t* array, size_t array_len); + + static lldb::SBData + CreateDataFromSInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int64_t* array, size_t array_len); + + static lldb::SBData + CreateDataFromSInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int32_t* array, size_t array_len); + + static lldb::SBData + CreateDataFromDoubleArray (lldb::ByteOrder endian, uint32_t addr_byte_size, double* array, size_t array_len); + + bool + SetDataFromCString (const char* data); + + bool + SetDataFromUInt64Array (uint64_t* array, size_t array_len); + + bool + SetDataFromUInt32Array (uint32_t* array, size_t array_len); + + bool + SetDataFromSInt64Array (int64_t* array, size_t array_len); + + bool + SetDataFromSInt32Array (int32_t* array, size_t array_len); + + bool + SetDataFromDoubleArray (double* array, size_t array_len); + + %pythoncode %{ + + class read_data_helper: + def __init__(self, sbdata, readerfunc, item_size): + self.sbdata = sbdata + self.readerfunc = readerfunc + self.item_size = item_size + def __getitem__(self,key): + if isinstance(key,slice): + list = [] + for x in range(*key.indices(self.__len__())): + list.append(self.__getitem__(x)) + return list + if not (isinstance(key,six.integer_types)): + raise TypeError('must be int') + key = key * self.item_size # SBData uses byte-based indexes, but we want to use itemsize-based indexes here + error = SBError() + my_data = self.readerfunc(self.sbdata,error,key) + if error.Fail(): + raise IndexError(error.GetCString()) + else: + return my_data + def __len__(self): + return int(self.sbdata.GetByteSize()/self.item_size) + def all(self): + return self[0:len(self)] + + @classmethod + def CreateDataFromInt (cls, value, size = None, target = None, ptr_size = None, endian = None): + import sys + lldbmodule = sys.modules[cls.__module__] + lldbdict = lldbmodule.__dict__ + if 'target' in lldbdict: + lldbtarget = lldbdict['target'] + else: + lldbtarget = None + if target == None and lldbtarget != None and lldbtarget.IsValid(): + target = lldbtarget + if ptr_size == None: + if target and target.IsValid(): + ptr_size = target.addr_size + else: + ptr_size = 8 + if endian == None: + if target and target.IsValid(): + endian = target.byte_order + else: + endian = lldbdict['eByteOrderLittle'] + if size == None: + if value > 2147483647: + size = 8 + elif value < -2147483648: + size = 8 + elif value > 4294967295: + size = 8 + else: + size = 4 + if size == 4: + if value < 0: + return SBData().CreateDataFromSInt32Array(endian, ptr_size, [value]) + return SBData().CreateDataFromUInt32Array(endian, ptr_size, [value]) + if size == 8: + if value < 0: + return SBData().CreateDataFromSInt64Array(endian, ptr_size, [value]) + return SBData().CreateDataFromUInt64Array(endian, ptr_size, [value]) + return None + + def _make_helper(self, sbdata, getfunc, itemsize): + return self.read_data_helper(sbdata, getfunc, itemsize) + + def _make_helper_uint8(self): + return self._make_helper(self, SBData.GetUnsignedInt8, 1) + + def _make_helper_uint16(self): + return self._make_helper(self, SBData.GetUnsignedInt16, 2) + + def _make_helper_uint32(self): + return self._make_helper(self, SBData.GetUnsignedInt32, 4) + + def _make_helper_uint64(self): + return self._make_helper(self, SBData.GetUnsignedInt64, 8) + + def _make_helper_sint8(self): + return self._make_helper(self, SBData.GetSignedInt8, 1) + + def _make_helper_sint16(self): + return self._make_helper(self, SBData.GetSignedInt16, 2) + + def _make_helper_sint32(self): + return self._make_helper(self, SBData.GetSignedInt32, 4) + + def _make_helper_sint64(self): + return self._make_helper(self, SBData.GetSignedInt64, 8) + + def _make_helper_float(self): + return self._make_helper(self, SBData.GetFloat, 4) + + def _make_helper_double(self): + return self._make_helper(self, SBData.GetDouble, 8) + + def _read_all_uint8(self): + return self._make_helper_uint8().all() + + def _read_all_uint16(self): + return self._make_helper_uint16().all() + + def _read_all_uint32(self): + return self._make_helper_uint32().all() + + def _read_all_uint64(self): + return self._make_helper_uint64().all() + + def _read_all_sint8(self): + return self._make_helper_sint8().all() + + def _read_all_sint16(self): + return self._make_helper_sint16().all() + + def _read_all_sint32(self): + return self._make_helper_sint32().all() + + def _read_all_sint64(self): + return self._make_helper_sint64().all() + + def _read_all_float(self): + return self._make_helper_float().all() + + def _read_all_double(self): + return self._make_helper_double().all() + + __swig_getmethods__["uint8"] = _make_helper_uint8 + if _newclass: uint8 = property(_make_helper_uint8, None, doc='''A read only property that returns an array-like object out of which you can read uint8 values.''') + + __swig_getmethods__["uint16"] = _make_helper_uint16 + if _newclass: uint16 = property(_make_helper_uint16, None, doc='''A read only property that returns an array-like object out of which you can read uint16 values.''') + + __swig_getmethods__["uint32"] = _make_helper_uint32 + if _newclass: uint32 = property(_make_helper_uint32, None, doc='''A read only property that returns an array-like object out of which you can read uint32 values.''') + + __swig_getmethods__["uint64"] = _make_helper_uint64 + if _newclass: uint64 = property(_make_helper_uint64, None, doc='''A read only property that returns an array-like object out of which you can read uint64 values.''') + + __swig_getmethods__["sint8"] = _make_helper_sint8 + if _newclass: sint8 = property(_make_helper_sint8, None, doc='''A read only property that returns an array-like object out of which you can read sint8 values.''') + + __swig_getmethods__["sint16"] = _make_helper_sint16 + if _newclass: sint16 = property(_make_helper_sint16, None, doc='''A read only property that returns an array-like object out of which you can read sint16 values.''') + + __swig_getmethods__["sint32"] = _make_helper_sint32 + if _newclass: sint32 = property(_make_helper_sint32, None, doc='''A read only property that returns an array-like object out of which you can read sint32 values.''') + + __swig_getmethods__["sint64"] = _make_helper_sint64 + if _newclass: sint64 = property(_make_helper_sint64, None, doc='''A read only property that returns an array-like object out of which you can read sint64 values.''') + + __swig_getmethods__["float"] = _make_helper_float + if _newclass: float = property(_make_helper_float, None, doc='''A read only property that returns an array-like object out of which you can read float values.''') + + __swig_getmethods__["double"] = _make_helper_double + if _newclass: double = property(_make_helper_double, None, doc='''A read only property that returns an array-like object out of which you can read double values.''') + + __swig_getmethods__["uint8s"] = _read_all_uint8 + if _newclass: uint8s = property(_read_all_uint8, None, doc='''A read only property that returns an array with all the contents of this SBData represented as uint8 values.''') + + __swig_getmethods__["uint16s"] = _read_all_uint16 + if _newclass: uint16s = property(_read_all_uint16, None, doc='''A read only property that returns an array with all the contents of this SBData represented as uint16 values.''') + + __swig_getmethods__["uint32s"] = _read_all_uint32 + if _newclass: uint32s = property(_read_all_uint32, None, doc='''A read only property that returns an array with all the contents of this SBData represented as uint32 values.''') + + __swig_getmethods__["uint64s"] = _read_all_uint64 + if _newclass: uint64s = property(_read_all_uint64, None, doc='''A read only property that returns an array with all the contents of this SBData represented as uint64 values.''') + + __swig_getmethods__["sint8s"] = _read_all_sint8 + if _newclass: sint8s = property(_read_all_sint8, None, doc='''A read only property that returns an array with all the contents of this SBData represented as sint8 values.''') + + __swig_getmethods__["sint16s"] = _read_all_sint16 + if _newclass: sint16s = property(_read_all_sint16, None, doc='''A read only property that returns an array with all the contents of this SBData represented as sint16 values.''') + + __swig_getmethods__["sint32s"] = _read_all_sint32 + if _newclass: sint32s = property(_read_all_sint32, None, doc='''A read only property that returns an array with all the contents of this SBData represented as sint32 values.''') + + __swig_getmethods__["sint64s"] = _read_all_sint64 + if _newclass: sint64s = property(_read_all_sint64, None, doc='''A read only property that returns an array with all the contents of this SBData represented as sint64 values.''') + + __swig_getmethods__["floats"] = _read_all_float + if _newclass: floats = property(_read_all_float, None, doc='''A read only property that returns an array with all the contents of this SBData represented as float values.''') + + __swig_getmethods__["doubles"] = _read_all_double + if _newclass: doubles = property(_read_all_double, None, doc='''A read only property that returns an array with all the contents of this SBData represented as double values.''') + + %} + + %pythoncode %{ + __swig_getmethods__["byte_order"] = GetByteOrder + __swig_setmethods__["byte_order"] = SetByteOrder + if _newclass: byte_order = property(GetByteOrder, SetByteOrder, doc='''A read/write property getting and setting the endianness of this SBData (data.byte_order = lldb.eByteOrderLittle).''') + + __swig_getmethods__["size"] = GetByteSize + if _newclass: size = property(GetByteSize, None, doc='''A read only property that returns the size the same result as GetByteSize().''') + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBDebugger.i b/scripts/interface/SBDebugger.i new file mode 100644 index 0000000000000..89b2882aeb91e --- /dev/null +++ b/scripts/interface/SBDebugger.i @@ -0,0 +1,388 @@ +//===-- SWIG Interface for SBDebugger ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"SBDebugger is the primordial object that creates SBTargets and provides +access to them. It also manages the overall debugging experiences. + +For example (from example/disasm.py), + +import lldb +import os +import sys + +def disassemble_instructions (insts): + for i in insts: + print i + +... + +# Create a new debugger instance +debugger = lldb.SBDebugger.Create() + +# When we step or continue, don't return from the function until the process +# stops. We do this by setting the async mode to false. +debugger.SetAsync (False) + +# Create a target from a file and arch +print('Creating a target for \'%s\'' % exe) + +target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) + +if target: + # If the target is valid set a breakpoint at main + main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename()); + + print main_bp + + # Launch the process. Since we specified synchronous mode, we won't return + # from this function until we hit the breakpoint at main + process = target.LaunchSimple (None, None, os.getcwd()) + + # Make sure the launch went ok + if process: + # Print some simple process info + state = process.GetState () + print process + if state == lldb.eStateStopped: + # Get the first thread + thread = process.GetThreadAtIndex (0) + if thread: + # Print some simple thread info + print thread + # Get the first frame + frame = thread.GetFrameAtIndex (0) + if frame: + # Print some simple frame info + print frame + function = frame.GetFunction() + # See if we have debug info (a function) + if function: + # We do have a function, print some info for the function + print function + # Now get all instructions for this function and print them + insts = function.GetInstructions(target) + disassemble_instructions (insts) + else: + # See if we have a symbol in the symbol table for where we stopped + symbol = frame.GetSymbol(); + if symbol: + # We do have a symbol, print some info for the symbol + print symbol + # Now get all instructions for this symbol and print them + insts = symbol.GetInstructions(target) + disassemble_instructions (insts) + + registerList = frame.GetRegisters() + print('Frame registers (size of register set = %d):' % registerList.GetSize()) + for value in registerList: + #print value + print('%s (number of children = %d):' % (value.GetName(), value.GetNumChildren())) + for child in value: + print('Name: ', child.GetName(), ' Value: ', child.GetValue()) + + print('Hit the breakpoint at main, enter to continue and wait for program to exit or \'Ctrl-D\'/\'quit\' to terminate the program') + next = sys.stdin.readline() + if not next or next.rstrip('\n') == 'quit': + print('Terminating the inferior process...') + process.Kill() + else: + # Now continue to the program exit + process.Continue() + # When we return from the above function we will hopefully be at the + # program exit. Print out some process info + print process + elif state == lldb.eStateExited: + print('Didn\'t hit the breakpoint at main, program has exited...') + else: + print('Unexpected process state: %s, killing process...' % debugger.StateAsCString (state)) + process.Kill() +") SBDebugger; +class SBDebugger +{ +public: + + static void + Initialize(); + + static void + Terminate(); + + static lldb::SBDebugger + Create(); + + static lldb::SBDebugger + Create(bool source_init_files); + + static lldb::SBDebugger + Create(bool source_init_files, lldb::LogOutputCallback log_callback, void *baton); + + static void + Destroy (lldb::SBDebugger &debugger); + + static void + MemoryPressureDetected(); + + SBDebugger(); + + SBDebugger(const lldb::SBDebugger &rhs); + + ~SBDebugger(); + + bool + IsValid() const; + + void + Clear (); + + void + SetAsync (bool b); + + bool + GetAsync (); + + void + SkipLLDBInitFiles (bool b); + + void + SetInputFileHandle (FILE *f, bool transfer_ownership); + + void + SetOutputFileHandle (FILE *f, bool transfer_ownership); + + void + SetErrorFileHandle (FILE *f, bool transfer_ownership); + + FILE * + GetInputFileHandle (); + + FILE * + GetOutputFileHandle (); + + FILE * + GetErrorFileHandle (); + + lldb::SBCommandInterpreter + GetCommandInterpreter (); + + void + HandleCommand (const char *command); + + lldb::SBListener + GetListener (); + + void + HandleProcessEvent (const lldb::SBProcess &process, + const lldb::SBEvent &event, + FILE *out, + FILE *err); + + lldb::SBTarget + CreateTarget (const char *filename, + const char *target_triple, + const char *platform_name, + bool add_dependent_modules, + lldb::SBError& sb_error); + + lldb::SBTarget + CreateTargetWithFileAndTargetTriple (const char *filename, + const char *target_triple); + + lldb::SBTarget + CreateTargetWithFileAndArch (const char *filename, + const char *archname); + + lldb::SBTarget + CreateTarget (const char *filename); + + %feature("docstring", + "Return true if target is deleted from the target list of the debugger." + ) DeleteTarget; + bool + DeleteTarget (lldb::SBTarget &target); + + lldb::SBTarget + GetTargetAtIndex (uint32_t idx); + + uint32_t + GetIndexOfTarget (lldb::SBTarget target); + + lldb::SBTarget + FindTargetWithProcessID (pid_t pid); + + lldb::SBTarget + FindTargetWithFileAndArch (const char *filename, + const char *arch); + + uint32_t + GetNumTargets (); + + lldb::SBTarget + GetSelectedTarget (); + + void + SetSelectedTarget (lldb::SBTarget &target); + + lldb::SBPlatform + GetSelectedPlatform(); + + void + SetSelectedPlatform(lldb::SBPlatform &platform); + + lldb::SBSourceManager + GetSourceManager (); + + // REMOVE: just for a quick fix, need to expose platforms through + // SBPlatform from this class. + lldb::SBError + SetCurrentPlatform (const char *platform_name); + + bool + SetCurrentPlatformSDKRoot (const char *sysroot); + + // FIXME: Once we get the set show stuff in place, the driver won't need + // an interface to the Set/Get UseExternalEditor. + bool + SetUseExternalEditor (bool input); + + bool + GetUseExternalEditor (); + + bool + SetUseColor (bool use_color); + + bool + GetUseColor () const; + + static bool + GetDefaultArchitecture (char *arch_name, size_t arch_name_len); + + static bool + SetDefaultArchitecture (const char *arch_name); + + lldb::ScriptLanguage + GetScriptingLanguage (const char *script_language_name); + + static const char * + GetVersionString (); + + static const char * + StateAsCString (lldb::StateType state); + + static bool + StateIsRunningState (lldb::StateType state); + + static bool + StateIsStoppedState (lldb::StateType state); + + bool + EnableLog (const char *channel, const char ** types); + + void + SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton); + + void + DispatchInput (const void *data, size_t data_len); + + void + DispatchInputInterrupt (); + + void + DispatchInputEndOfFile (); + + const char * + GetInstanceName (); + + static SBDebugger + FindDebuggerWithID (int id); + + static lldb::SBError + SetInternalVariable (const char *var_name, const char *value, const char *debugger_instance_name); + + static lldb::SBStringList + GetInternalVariableValue (const char *var_name, const char *debugger_instance_name); + + bool + GetDescription (lldb::SBStream &description); + + uint32_t + GetTerminalWidth () const; + + void + SetTerminalWidth (uint32_t term_width); + + lldb::user_id_t + GetID (); + + const char * + GetPrompt() const; + + void + SetPrompt (const char *prompt); + + lldb::ScriptLanguage + GetScriptLanguage() const; + + void + SetScriptLanguage (lldb::ScriptLanguage script_lang); + + bool + GetCloseInputOnEOF () const; + + void + SetCloseInputOnEOF (bool b); + + lldb::SBTypeCategory + GetCategory (const char* category_name); + + SBTypeCategory + GetCategory (lldb::LanguageType lang_type); + + lldb::SBTypeCategory + CreateCategory (const char* category_name); + + bool + DeleteCategory (const char* category_name); + + uint32_t + GetNumCategories (); + + lldb::SBTypeCategory + GetCategoryAtIndex (uint32_t); + + lldb::SBTypeCategory + GetDefaultCategory(); + + lldb::SBTypeFormat + GetFormatForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeSummary + GetSummaryForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeFilter + GetFilterForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeSynthetic + GetSyntheticForType (lldb::SBTypeNameSpecifier); + + void + RunCommandInterpreter (bool auto_handle_events, + bool spawn_thread, + SBCommandInterpreterRunOptions &options, + int &num_errors, + bool &quit_requested, + bool &stopped_for_crash); + + lldb::SBError + RunREPL (lldb::LanguageType language, const char *repl_options); +}; // class SBDebugger + +} // namespace lldb diff --git a/scripts/interface/SBDeclaration.i b/scripts/interface/SBDeclaration.i new file mode 100644 index 0000000000000..e7a6b6d44b734 --- /dev/null +++ b/scripts/interface/SBDeclaration.i @@ -0,0 +1,68 @@ +//===-- SWIG Interface for SBDeclaration --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Specifies an association with a line and column for a variable." + ) SBDeclaration; + class SBDeclaration + { + public: + + SBDeclaration (); + + SBDeclaration (const lldb::SBDeclaration &rhs); + + ~SBDeclaration (); + + bool + IsValid () const; + + lldb::SBFileSpec + GetFileSpec () const; + + uint32_t + GetLine () const; + + uint32_t + GetColumn () const; + + bool + GetDescription (lldb::SBStream &description); + + void + SetFileSpec (lldb::SBFileSpec filespec); + + void + SetLine (uint32_t line); + + void + SetColumn (uint32_t column); + + bool + operator == (const lldb::SBDeclaration &rhs) const; + + bool + operator != (const lldb::SBDeclaration &rhs) const; + + %pythoncode %{ + __swig_getmethods__["file"] = GetFileSpec + if _newclass: file = property(GetFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this line entry.''') + + __swig_getmethods__["line"] = GetLine + if _newclass: line = property(GetLine, None, doc='''A read only property that returns the 1 based line number for this line entry, a return value of zero indicates that no line information is available.''') + + __swig_getmethods__["column"] = GetColumn + if _newclass: column = property(GetColumn, None, doc='''A read only property that returns the 1 based column number for this line entry, a return value of zero indicates that no column information is available.''') + %} + + }; + +} // namespace lldb diff --git a/scripts/interface/SBError.i b/scripts/interface/SBError.i new file mode 100644 index 0000000000000..bebf2d7d72a59 --- /dev/null +++ b/scripts/interface/SBError.i @@ -0,0 +1,128 @@ +//===-- SWIG Interface for SBError ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a container for holding any error code. + +For example (from test/python_api/hello_world/TestHelloWorld.py), + + def hello_world_attach_with_id_api(self): + '''Create target, spawn a process, and attach to it by id.''' + + target = self.dbg.CreateTarget(self.exe) + + # Spawn a new process and don't display the stdout if not in TraceOn() mode. + import subprocess + popen = subprocess.Popen([self.exe, 'abc', 'xyz'], + stdout = open(os.devnull, 'w') if not self.TraceOn() else None) + + listener = lldb.SBListener('my.attach.listener') + error = lldb.SBError() + process = target.AttachToProcessWithID(listener, popen.pid, error) + + self.assertTrue(error.Success() and process, PROCESS_IS_VALID) + + # Let's check the stack traces of the attached process. + import lldbutil + stacktraces = lldbutil.print_stacktraces(process, string_buffer=True) + self.expect(stacktraces, exe=False, + substrs = ['main.c:%d' % self.line2, + '(int)argc=3']) + + listener = lldb.SBListener('my.attach.listener') + error = lldb.SBError() + process = target.AttachToProcessWithID(listener, popen.pid, error) + + self.assertTrue(error.Success() and process, PROCESS_IS_VALID) + +checks that after the attach, there is no error condition by asserting +that error.Success() is True and we get back a valid process object. + +And (from test/python_api/event/TestEvent.py), + + # Now launch the process, and do not stop at entry point. + error = lldb.SBError() + process = target.Launch(listener, None, None, None, None, None, None, 0, False, error) + self.assertTrue(error.Success() and process, PROCESS_IS_VALID) + +checks that after calling the target.Launch() method there's no error +condition and we get back a void process object. +") SBError; + +class SBError { +public: + SBError (); + + SBError (const lldb::SBError &rhs); + + ~SBError(); + + const char * + GetCString () const; + + void + Clear (); + + bool + Fail () const; + + bool + Success () const; + + uint32_t + GetError () const; + + lldb::ErrorType + GetType () const; + + void + SetError (uint32_t err, lldb::ErrorType type); + + void + SetErrorToErrno (); + + void + SetErrorToGenericError (); + + void + SetErrorString (const char *err_str); + + %varargs(3, char *str = NULL) SetErrorStringWithFormat; + int + SetErrorStringWithFormat (const char *format, ...); + + bool + IsValid () const; + + bool + GetDescription (lldb::SBStream &description); + + %pythoncode %{ + __swig_getmethods__["value"] = GetError + if _newclass: value = property(GetError, None, doc='''A read only property that returns the same result as GetError().''') + + __swig_getmethods__["fail"] = Fail + if _newclass: fail = property(Fail, None, doc='''A read only property that returns the same result as Fail().''') + + __swig_getmethods__["success"] = Success + if _newclass: success = property(Success, None, doc='''A read only property that returns the same result as Success().''') + + __swig_getmethods__["description"] = GetCString + if _newclass: description = property(GetCString, None, doc='''A read only property that returns the same result as GetCString().''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns the same result as GetType().''') + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBEvent.i b/scripts/interface/SBEvent.i new file mode 100644 index 0000000000000..ddbd5135b9e3d --- /dev/null +++ b/scripts/interface/SBEvent.i @@ -0,0 +1,153 @@ +//===-- SWIG Interface for SBEvent ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBBroadcaster; + +%feature("docstring", +"API clients can register to receive events. + +For example, check out the following output: + +Try wait for event... +Event description: 0x103d0bb70 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = running} +Event data flavor: Process::ProcessEventData +Process state: running + +Try wait for event... +Event description: 0x103a700a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = stopped} +Event data flavor: Process::ProcessEventData +Process state: stopped + +Try wait for event... +Event description: 0x103d0d4a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = exited} +Event data flavor: Process::ProcessEventData +Process state: exited + +Try wait for event... +timeout occurred waiting for event... + +from test/python_api/event/TestEventspy: + + def do_listen_for_and_print_event(self): + '''Create a listener and use SBEvent API to print the events received.''' + exe = os.path.join(os.getcwd(), 'a.out') + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + # Now create a breakpoint on main.c by name 'c'. + breakpoint = target.BreakpointCreateByName('c', 'a.out') + + # Now launch the process, and do not stop at the entry point. + process = target.LaunchSimple(None, None, os.getcwd()) + self.assertTrue(process.GetState() == lldb.eStateStopped, + PROCESS_STOPPED) + + # Get a handle on the process's broadcaster. + broadcaster = process.GetBroadcaster() + + # Create an empty event object. + event = lldb.SBEvent() + + # Create a listener object and register with the broadcaster. + listener = lldb.SBListener('my listener') + rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) + self.assertTrue(rc, 'AddListener successfully retruns') + + traceOn = self.TraceOn() + if traceOn: + lldbutil.print_stacktraces(process) + + # Create MyListeningThread class to wait for any kind of event. + import threading + class MyListeningThread(threading.Thread): + def run(self): + count = 0 + # Let's only try at most 4 times to retrieve any kind of event. + # After that, the thread exits. + while not count > 3: + if traceOn: + print('Try wait for event...') + if listener.WaitForEventForBroadcasterWithType(5, + broadcaster, + lldb.SBProcess.eBroadcastBitStateChanged, + event): + if traceOn: + desc = lldbutil.get_description(event)) + print('Event description:', desc) + print('Event data flavor:', event.GetDataFlavor()) + print('Process state:', lldbutil.state_type_to_str(process.GetState())) + print() + else: + if traceOn: + print 'timeout occurred waiting for event...' + count = count + 1 + return + + # Let's start the listening thread to retrieve the events. + my_thread = MyListeningThread() + my_thread.start() + + # Use Python API to continue the process. The listening thread should be + # able to receive the state changed events. + process.Continue() + + # Use Python API to kill the process. The listening thread should be + # able to receive the state changed event, too. + process.Kill() + + # Wait until the 'MyListeningThread' terminates. + my_thread.join() +") SBEvent; +class SBEvent +{ +public: + SBEvent(); + + SBEvent (const lldb::SBEvent &rhs); + + %feature("autodoc", + "__init__(self, int type, str data) -> SBEvent (make an event that contains a C string)" + ) SBEvent; + SBEvent (uint32_t event, const char *cstr, uint32_t cstr_len); + + ~SBEvent(); + + bool + IsValid() const; + + const char * + GetDataFlavor (); + + uint32_t + GetType () const; + + lldb::SBBroadcaster + GetBroadcaster () const; + + const char * + GetBroadcasterClass () const; + + bool + BroadcasterMatchesRef (const lldb::SBBroadcaster &broadcaster); + + void + Clear(); + + static const char * + GetCStringFromEvent (const lldb::SBEvent &event); + + bool + GetDescription (lldb::SBStream &description) const; +}; + +} // namespace lldb diff --git a/scripts/interface/SBExecutionContext.i b/scripts/interface/SBExecutionContext.i new file mode 100644 index 0000000000000..cd9d9287bd22f --- /dev/null +++ b/scripts/interface/SBExecutionContext.i @@ -0,0 +1,57 @@ +//===-- SWIG Interface for SBExecutionContext ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBExecutionContext +{ +public: + SBExecutionContext(); + + SBExecutionContext (const lldb::SBExecutionContext &rhs); + + SBExecutionContext (const lldb::SBTarget &target); + + SBExecutionContext (const lldb::SBProcess &process); + + SBExecutionContext (lldb::SBThread thread); // can't be a const& because SBThread::get() isn't itself a const function + + SBExecutionContext (const lldb::SBFrame &frame); + + ~SBExecutionContext(); + + SBTarget + GetTarget () const; + + SBProcess + GetProcess () const; + + SBThread + GetThread () const; + + SBFrame + GetFrame () const; + + %pythoncode %{ + __swig_getmethods__["target"] = GetTarget + if _newclass: target = property(GetTarget, None, doc='''A read only property that returns the same result as GetTarget().''') + + __swig_getmethods__["process"] = GetProcess + if _newclass: process = property(GetProcess, None, doc='''A read only property that returns the same result as GetProcess().''') + + __swig_getmethods__["thread"] = GetThread + if _newclass: thread = property(GetThread, None, doc='''A read only property that returns the same result as GetThread().''') + + __swig_getmethods__["frame"] = GetFrame + if _newclass: frame = property(GetFrame, None, doc='''A read only property that returns the same result as GetFrame().''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBExpressionOptions.i b/scripts/interface/SBExpressionOptions.i new file mode 100644 index 0000000000000..1f423cf47e425 --- /dev/null +++ b/scripts/interface/SBExpressionOptions.i @@ -0,0 +1,137 @@ +//===-- SWIG interface for SBExpressionOptions -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"A container for options to use when evaluating expressions." +) SBExpressionOptions; + +class SBExpressionOptions +{ +friend class SBFrame; +friend class SBValue; + +public: + SBExpressionOptions(); + + SBExpressionOptions (const lldb::SBExpressionOptions &rhs); + + ~SBExpressionOptions(); + + bool + GetCoerceResultToId () const; + + %feature("docstring", "Sets whether to coerce the expression result to ObjC id type after evaluation.") SetCoerceResultToId; + + void + SetCoerceResultToId (bool coerce = true); + + bool + GetUnwindOnError () const; + + %feature("docstring", "Sets whether to unwind the expression stack on error.") SetUnwindOnError; + + void + SetUnwindOnError (bool unwind = true); + + bool + GetIgnoreBreakpoints () const; + + %feature("docstring", "Sets whether to ignore breakpoint hits while running expressions.") SetUnwindOnError; + + void + SetIgnoreBreakpoints (bool ignore = true); + + lldb::DynamicValueType + GetFetchDynamicValue () const; + + %feature("docstring", "Sets whether to cast the expression result to its dynamic type.") SetFetchDynamicValue; + + void + SetFetchDynamicValue (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget); + + uint32_t + GetTimeoutInMicroSeconds () const; + + %feature("docstring", "Sets the timeout in microseconds to run the expression for. If try all threads is set to true and the expression doesn't complete within the specified timeout, all threads will be resumed for the same timeout to see if the expresson will finish.") SetTimeoutInMicroSeconds; + void + SetTimeoutInMicroSeconds (uint32_t timeout = 0); + + uint32_t + GetOneThreadTimeoutInMicroSeconds () const; + + %feature("docstring", "Sets the timeout in microseconds to run the expression on one thread before either timing out or trying all threads.") SetTimeoutInMicroSeconds; + void + SetOneThreadTimeoutInMicroSeconds (uint32_t timeout = 0); + + bool + GetTryAllThreads () const; + + %feature("docstring", "Sets whether to run all threads if the expression does not complete on one thread.") SetTryAllThreads; + void + SetTryAllThreads (bool run_others = true); + + bool + GetStopOthers () const; + + %feature("docstring", "Sets whether to stop other threads at all while running expressins. If false, TryAllThreads does nothing.") SetTryAllThreads; + void + SetStopOthers (bool stop_others = true); + + bool + GetTrapExceptions () const; + + %feature("docstring", "Sets whether to abort expression evaluation if an exception is thrown while executing. Don't set this to false unless you know the function you are calling traps all exceptions itself.") SetTryAllThreads; + void + SetTrapExceptions (bool trap_exceptions = true); + + %feature ("docstring", "Sets the language that LLDB should assume the expression is written in") SetLanguage; + void + SetLanguage (lldb::LanguageType language); + + bool + GetGenerateDebugInfo (); + + %feature("docstring", "Sets whether to generate debug information for the expression and also controls if a SBModule is generated.") SetGenerateDebugInfo; + void + SetGenerateDebugInfo (bool b = true); + + bool + GetSuppressPersistentResult (); + + %feature("docstring", "Sets whether to produce a persistent result that can be used in future expressions.") SetSuppressPersistentResult; + void + SetSuppressPersistentResult (bool b = false); + + + %feature("docstring", "Gets the prefix to use for this expression.") GetPrefix; + const char * + GetPrefix () const; + + %feature("docstring", "Sets the prefix to use for this expression. This prefix gets inserted after the 'target.expr-prefix' prefix contents, but before the wrapped expression function body.") SetPrefix; + void + SetPrefix (const char *prefix); + +protected: + + SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); + + lldb_private::EvaluateExpressionOptions * + get () const; + + lldb_private::EvaluateExpressionOptions & + ref () const; + +private: + // This auto_pointer is made in the constructor and is always valid. + mutable std::unique_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap; +}; + +} // namespace lldb diff --git a/scripts/interface/SBFileSpec.i b/scripts/interface/SBFileSpec.i new file mode 100644 index 0000000000000..c153f2bd86f64 --- /dev/null +++ b/scripts/interface/SBFileSpec.i @@ -0,0 +1,103 @@ +//===-- SWIG Interface for SBFileSpec ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a file specification that divides the path into a directory and +basename. The string values of the paths are put into uniqued string pools +for fast comparisons and efficient memory usage. + +For example, the following code + + lineEntry = context.GetLineEntry() + self.expect(lineEntry.GetFileSpec().GetDirectory(), 'The line entry should have the correct directory', + exe=False, + substrs = [self.mydir]) + self.expect(lineEntry.GetFileSpec().GetFilename(), 'The line entry should have the correct filename', + exe=False, + substrs = ['main.c']) + self.assertTrue(lineEntry.GetLine() == self.line, + 'The line entry's line number should match ') + +gets the line entry from the symbol context when a thread is stopped. +It gets the file spec corresponding to the line entry and checks that +the filename and the directory matches what we expect. +") SBFileSpec; +class SBFileSpec +{ +public: + SBFileSpec (); + + SBFileSpec (const lldb::SBFileSpec &rhs); + + SBFileSpec (const char *path);// Deprecated, use SBFileSpec (const char *path, bool resolve) + + SBFileSpec (const char *path, bool resolve); + + ~SBFileSpec (); + + bool + IsValid() const; + + bool + Exists () const; + + bool + ResolveExecutableLocation (); + + const char * + GetFilename() const; + + const char * + GetDirectory() const; + + void + SetFilename(const char *filename); + + void + SetDirectory(const char *directory); + + uint32_t + GetPath (char *dst_path, size_t dst_len) const; + + static int + ResolvePath (const char *src_path, char *dst_path, size_t dst_len); + + bool + GetDescription (lldb::SBStream &description) const; + + %pythoncode %{ + def __get_fullpath__(self): + spec_dir = self.GetDirectory() + spec_file = self.GetFilename() + if spec_dir and spec_file: + return '%s/%s' % (spec_dir, spec_file) + elif spec_dir: + return spec_dir + elif spec_file: + return spec_file + return None + + __swig_getmethods__["fullpath"] = __get_fullpath__ + if _newclass: fullpath = property(__get_fullpath__, None, doc='''A read only property that returns the fullpath as a python string.''') + + __swig_getmethods__["basename"] = GetFilename + if _newclass: basename = property(GetFilename, None, doc='''A read only property that returns the path basename as a python string.''') + + __swig_getmethods__["dirname"] = GetDirectory + if _newclass: dirname = property(GetDirectory, None, doc='''A read only property that returns the path directory name as a python string.''') + + __swig_getmethods__["exists"] = Exists + if _newclass: exists = property(Exists, None, doc='''A read only property that returns a boolean value that indicates if the file exists.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBFileSpecList.i b/scripts/interface/SBFileSpecList.i new file mode 100644 index 0000000000000..38a6f43bdc764 --- /dev/null +++ b/scripts/interface/SBFileSpecList.i @@ -0,0 +1,45 @@ +//===-- SWIG Interface for SBFileSpecList -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBFileSpecList +{ +public: + SBFileSpecList (); + + SBFileSpecList (const lldb::SBFileSpecList &rhs); + + ~SBFileSpecList (); + + uint32_t + GetSize () const; + + bool + GetDescription (SBStream &description) const; + + void + Append (const SBFileSpec &sb_file); + + bool + AppendIfUnique (const SBFileSpec &sb_file); + + void + Clear(); + + uint32_t + FindFileIndex (uint32_t idx, const SBFileSpec &sb_file, bool full); + + const SBFileSpec + GetFileSpecAtIndex (uint32_t idx) const; + +}; + + +} // namespace lldb diff --git a/scripts/interface/SBFrame.i b/scripts/interface/SBFrame.i new file mode 100644 index 0000000000000..1c10a9b6e3e81 --- /dev/null +++ b/scripts/interface/SBFrame.i @@ -0,0 +1,407 @@ +//===-- SWIG Interface for SBFrame ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents one of the stack frames associated with a thread. +SBThread contains SBFrame(s). For example (from test/lldbutil.py), + +def print_stacktrace(thread, string_buffer = False): + '''Prints a simple stack trace of this thread.''' + + ... + + for i in range(depth): + frame = thread.GetFrameAtIndex(i) + function = frame.GetFunction() + + load_addr = addrs[i].GetLoadAddress(target) + if not function: + file_addr = addrs[i].GetFileAddress() + start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() + symbol_offset = file_addr - start_addr + print >> output, ' frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}'.format( + num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset) + else: + print >> output, ' frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}'.format( + num=i, addr=load_addr, mod=mods[i], + func='%s [inlined]' % funcs[i] if frame.IsInlined() else funcs[i], + file=files[i], line=lines[i], + args=get_args_as_string(frame, showFuncName=False) if not frame.IsInlined() else '()') + + ... + +And, + + for frame in thread: + print frame + +See also SBThread." +) SBFrame; +class SBFrame +{ +public: + SBFrame (); + + SBFrame (const lldb::SBFrame &rhs); + + ~SBFrame(); + + bool + IsEqual (const lldb::SBFrame &rhs) const; + + bool + IsValid() const; + + uint32_t + GetFrameID () const; + + %feature("docstring", " + Get the Canonical Frame Address for this stack frame. + This is the DWARF standard's definition of a CFA, a stack address + that remains constant throughout the lifetime of the function. + Returns an lldb::addr_t stack address, or LLDB_INVALID_ADDRESS if + the CFA cannot be determined.") GetCFA; + lldb::addr_t + GetCFA () const; + + lldb::addr_t + GetPC () const; + + bool + SetPC (lldb::addr_t new_pc); + + lldb::addr_t + GetSP () const; + + lldb::addr_t + GetFP () const; + + lldb::SBAddress + GetPCAddress () const; + + lldb::SBSymbolContext + GetSymbolContext (uint32_t resolve_scope) const; + + lldb::SBModule + GetModule () const; + + lldb::SBCompileUnit + GetCompileUnit () const; + + lldb::SBFunction + GetFunction () const; + + lldb::SBSymbol + GetSymbol () const; + + %feature("docstring", " + /// Gets the deepest block that contains the frame PC. + /// + /// See also GetFrameBlock(). + ") GetBlock; + lldb::SBBlock + GetBlock () const; + + %feature("docstring", " + /// Get the appropriate function name for this frame. Inlined functions in + /// LLDB are represented by Blocks that have inlined function information, so + /// just looking at the SBFunction or SBSymbol for a frame isn't enough. + /// This function will return the appropriate function, symbol or inlined + /// function name for the frame. + /// + /// This function returns: + /// - the name of the inlined function (if there is one) + /// - the name of the concrete function (if there is one) + /// - the name of the symbol (if there is one) + /// - NULL + /// + /// See also IsInlined(). + ") GetFunctionName; + const char * + GetFunctionName(); + + const char * + GetDisplayFunctionName (); + + const char * + GetFunctionName() const; + + %feature("docstring", " + /// Return true if this frame represents an inlined function. + /// + /// See also GetFunctionName(). + ") IsInlined; + bool + IsInlined(); + + bool + IsInlined() const; + + %feature("docstring", " + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + ") EvaluateExpression; + lldb::SBValue + EvaluateExpression (const char *expr); + + lldb::SBValue + EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic); + + lldb::SBValue + EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error); + + lldb::SBValue + EvaluateExpression (const char *expr, SBExpressionOptions &options); + + %feature("docstring", " + /// Gets the lexical block that defines the stack frame. Another way to think + /// of this is it will return the block that contains all of the variables + /// for a stack frame. Inlined functions are represented as SBBlock objects + /// that have inlined function information: the name of the inlined function, + /// where it was called from. The block that is returned will be the first + /// block at or above the block for the PC (SBFrame::GetBlock()) that defines + /// the scope of the frame. When a function contains no inlined functions, + /// this will be the top most lexical block that defines the function. + /// When a function has inlined functions and the PC is currently + /// in one of those inlined functions, this method will return the inlined + /// block that defines this frame. If the PC isn't currently in an inlined + /// function, the lexical block that defines the function is returned. + ") GetFrameBlock; + lldb::SBBlock + GetFrameBlock () const; + + lldb::SBLineEntry + GetLineEntry () const; + + lldb::SBThread + GetThread () const; + + const char * + Disassemble () const; + + void + Clear(); + +#ifndef SWIG + bool + operator == (const lldb::SBFrame &rhs) const; + + bool + operator != (const lldb::SBFrame &rhs) const; + +#endif + + %feature("docstring", " + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + ") GetVariables; + lldb::SBValueList + GetVariables (bool arguments, + bool locals, + bool statics, + bool in_scope_only); + + lldb::SBValueList + GetVariables (bool arguments, + bool locals, + bool statics, + bool in_scope_only, + lldb::DynamicValueType use_dynamic); + + lldb::SBValueList + GetVariables (const lldb::SBVariablesOptions& options); + + lldb::SBValueList + GetRegisters (); + + %feature("docstring", " + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + ") FindVariable; + lldb::SBValue + FindVariable (const char *var_name); + + lldb::SBValue + FindVariable (const char *var_name, lldb::DynamicValueType use_dynamic); + + lldb::SBValue + FindRegister (const char *name); + + %feature("docstring", " + /// Get a lldb.SBValue for a variable path. + /// + /// Variable paths can include access to pointer or instance members: + /// rect_ptr->origin.y + /// pt.x + /// Pointer dereferences: + /// *this->foo_ptr + /// **argv + /// Address of: + /// &pt + /// &my_array[3].x + /// Array accesses and treating pointers as arrays: + /// int_array[1] + /// pt_ptr[22].x + /// + /// Unlike EvaluateExpression() which returns lldb.SBValue objects + /// with constant copies of the values at the time of evaluation, + /// the result of this function is a value that will continue to + /// track the current value of the value as execution progresses + /// in the current frame. + ") GetValueForVariablePath; + lldb::SBValue + GetValueForVariablePath (const char *var_path); + + lldb::SBValue + GetValueForVariablePath (const char *var_path, lldb::DynamicValueType use_dynamic); + + %feature("docstring", " + /// Find variables, register sets, registers, or persistent variables using + /// the frame as the scope. + /// + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + ") FindValue; + lldb::SBValue + FindValue (const char *name, ValueType value_type); + + lldb::SBValue + FindValue (const char *name, ValueType value_type, lldb::DynamicValueType use_dynamic); + + bool + GetDescription (lldb::SBStream &description); + + %pythoncode %{ + def get_all_variables(self): + return self.GetVariables(True,True,True,True) + + def get_parent_frame(self): + parent_idx = self.idx + 1 + if parent_idx >= 0 and parent_idx < len(self.thread.frame): + return self.thread.frame[parent_idx] + else: + return SBFrame() + + def get_arguments(self): + return self.GetVariables(True,False,False,False) + + def get_locals(self): + return self.GetVariables(False,True,False,False) + + def get_statics(self): + return self.GetVariables(False,False,True,False) + + def var(self, var_expr_path): + '''Calls through to lldb.SBFrame.GetValueForVariablePath() and returns + a value that represents the variable expression path''' + return self.GetValueForVariablePath(var_expr_path) + + def get_registers_access(self): + class registers_access(object): + '''A helper object that exposes a flattened view of registers, masking away the notion of register sets for easy scripting.''' + def __init__(self, regs): + self.regs = regs + + def __getitem__(self, key): + if type(key) is str: + for i in range(0,len(self.regs)): + rs = self.regs[i] + for j in range (0,rs.num_children): + reg = rs.GetChildAtIndex(j) + if reg.name == key: return reg + else: + return lldb.SBValue() + + return registers_access(self.registers) + + __swig_getmethods__["pc"] = GetPC + __swig_setmethods__["pc"] = SetPC + if _newclass: pc = property(GetPC, SetPC) + + __swig_getmethods__["addr"] = GetPCAddress + if _newclass: addr = property(GetPCAddress, None, doc='''A read only property that returns the program counter (PC) as a section offset address (lldb.SBAddress).''') + + __swig_getmethods__["fp"] = GetFP + if _newclass: fp = property(GetFP, None, doc='''A read only property that returns the frame pointer (FP) as an unsigned integer.''') + + __swig_getmethods__["sp"] = GetSP + if _newclass: sp = property(GetSP, None, doc='''A read only property that returns the stack pointer (SP) as an unsigned integer.''') + + __swig_getmethods__["module"] = GetModule + if _newclass: module = property(GetModule, None, doc='''A read only property that returns an lldb object that represents the module (lldb.SBModule) for this stack frame.''') + + __swig_getmethods__["compile_unit"] = GetCompileUnit + if _newclass: compile_unit = property(GetCompileUnit, None, doc='''A read only property that returns an lldb object that represents the compile unit (lldb.SBCompileUnit) for this stack frame.''') + + __swig_getmethods__["function"] = GetFunction + if _newclass: function = property(GetFunction, None, doc='''A read only property that returns an lldb object that represents the function (lldb.SBFunction) for this stack frame.''') + + __swig_getmethods__["symbol"] = GetSymbol + if _newclass: symbol = property(GetSymbol, None, doc='''A read only property that returns an lldb object that represents the symbol (lldb.SBSymbol) for this stack frame.''') + + __swig_getmethods__["block"] = GetBlock + if _newclass: block = property(GetBlock, None, doc='''A read only property that returns an lldb object that represents the block (lldb.SBBlock) for this stack frame.''') + + __swig_getmethods__["is_inlined"] = IsInlined + if _newclass: is_inlined = property(IsInlined, None, doc='''A read only property that returns an boolean that indicates if the block frame is an inlined function.''') + + __swig_getmethods__["name"] = GetFunctionName + if _newclass: name = property(GetFunctionName, None, doc='''A read only property that retuns the name for the function that this frame represents. Inlined stack frame might have a concrete function that differs from the name of the inlined function (a named lldb.SBBlock).''') + + __swig_getmethods__["line_entry"] = GetLineEntry + if _newclass: line_entry = property(GetLineEntry, None, doc='''A read only property that returns an lldb object that represents the line table entry (lldb.SBLineEntry) for this stack frame.''') + + __swig_getmethods__["thread"] = GetThread + if _newclass: thread = property(GetThread, None, doc='''A read only property that returns an lldb object that represents the thread (lldb.SBThread) for this stack frame.''') + + __swig_getmethods__["disassembly"] = Disassemble + if _newclass: disassembly = property(Disassemble, None, doc='''A read only property that returns the disassembly for this stack frame as a python string.''') + + __swig_getmethods__["idx"] = GetFrameID + if _newclass: idx = property(GetFrameID, None, doc='''A read only property that returns the zero based stack frame index.''') + + __swig_getmethods__["variables"] = get_all_variables + if _newclass: variables = property(get_all_variables, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the variables in this stack frame.''') + + __swig_getmethods__["vars"] = get_all_variables + if _newclass: vars = property(get_all_variables, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the variables in this stack frame.''') + + __swig_getmethods__["locals"] = get_locals + if _newclass: locals = property(get_locals, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the local variables in this stack frame.''') + + __swig_getmethods__["args"] = get_arguments + if _newclass: args = property(get_arguments, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the argument variables in this stack frame.''') + + __swig_getmethods__["arguments"] = get_arguments + if _newclass: arguments = property(get_arguments, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the argument variables in this stack frame.''') + + __swig_getmethods__["statics"] = get_statics + if _newclass: statics = property(get_statics, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the static variables in this stack frame.''') + + __swig_getmethods__["registers"] = GetRegisters + if _newclass: registers = property(GetRegisters, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the CPU registers for this stack frame.''') + + __swig_getmethods__["regs"] = GetRegisters + if _newclass: regs = property(GetRegisters, None, doc='''A read only property that returns a list() that contains a collection of lldb.SBValue objects that represent the CPU registers for this stack frame.''') + + __swig_getmethods__["register"] = get_registers_access + if _newclass: register = property(get_registers_access, None, doc='''A read only property that returns an helper object providing a flattened indexable view of the CPU registers for this stack frame.''') + + __swig_getmethods__["reg"] = get_registers_access + if _newclass: reg = property(get_registers_access, None, doc='''A read only property that returns an helper object providing a flattened indexable view of the CPU registers for this stack frame''') + + __swig_getmethods__["parent"] = get_parent_frame + if _newclass: parent = property(get_parent_frame, None, doc='''A read only property that returns the parent (caller) frame of the current frame.''') + + %} +}; + +} // namespace lldb diff --git a/scripts/interface/SBFunction.i b/scripts/interface/SBFunction.i new file mode 100644 index 0000000000000..435e3e4bf30bb --- /dev/null +++ b/scripts/interface/SBFunction.i @@ -0,0 +1,145 @@ +//===-- SWIG Interface for SBFunction ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a generic function, which can be inlined or not. + +For example (from test/lldbutil.py, but slightly modified for doc purpose), + + ... + + frame = thread.GetFrameAtIndex(i) + addr = frame.GetPCAddress() + load_addr = addr.GetLoadAddress(target) + function = frame.GetFunction() + mod_name = frame.GetModule().GetFileSpec().GetFilename() + + if not function: + # No debug info for 'function'. + symbol = frame.GetSymbol() + file_addr = addr.GetFileAddress() + start_addr = symbol.GetStartAddress().GetFileAddress() + symbol_name = symbol.GetName() + symbol_offset = file_addr - start_addr + print >> output, ' frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}'.format( + num=i, addr=load_addr, mod=mod_name, symbol=symbol_name, offset=symbol_offset) + else: + # Debug info is available for 'function'. + func_name = frame.GetFunctionName() + file_name = frame.GetLineEntry().GetFileSpec().GetFilename() + line_num = frame.GetLineEntry().GetLine() + print >> output, ' frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}'.format( + num=i, addr=load_addr, mod=mod_name, + func='%s [inlined]' % func_name] if frame.IsInlined() else func_name, + file=file_name, line=line_num, args=get_args_as_string(frame, showFuncName=False)) + + ... +") SBFunction; +class SBFunction +{ +public: + + SBFunction (); + + SBFunction (const lldb::SBFunction &rhs); + + ~SBFunction (); + + bool + IsValid () const; + + const char * + GetName() const; + + const char * + GetDisplayName() const; + + const char * + GetMangledName () const; + + lldb::SBInstructionList + GetInstructions (lldb::SBTarget target); + + lldb::SBInstructionList + GetInstructions (lldb::SBTarget target, const char *flavor); + + lldb::SBAddress + GetStartAddress (); + + lldb::SBAddress + GetEndAddress (); + + const char * + GetArgumentName (uint32_t arg_idx); + + uint32_t + GetPrologueByteSize (); + + lldb::SBType + GetType (); + + lldb::SBBlock + GetBlock (); + + lldb::LanguageType + GetLanguage (); + + %feature("docstring", " + Returns true if the function was compiled with optimization. + Optimization, in this case, is meant to indicate that the debugger + experience may be confusing for the user -- variables optimized away, + stepping jumping between source lines -- and the driver may want to + provide some guidance to the user about this. + Returns false if unoptimized, or unknown.") GetIsOptimized; + bool + GetIsOptimized(); + + bool + GetDescription (lldb::SBStream &description); + + bool + operator == (const lldb::SBFunction &rhs) const; + + bool + operator != (const lldb::SBFunction &rhs) const; + + %pythoncode %{ + def get_instructions_from_current_target (self): + return self.GetInstructions (target) + + __swig_getmethods__["addr"] = GetStartAddress + if _newclass: addr = property(GetStartAddress, None, doc='''A read only property that returns an lldb object that represents the start address (lldb.SBAddress) for this function.''') + + __swig_getmethods__["end_addr"] = GetEndAddress + if _newclass: end_addr = property(GetEndAddress, None, doc='''A read only property that returns an lldb object that represents the end address (lldb.SBAddress) for this function.''') + + __swig_getmethods__["block"] = GetBlock + if _newclass: block = property(GetBlock, None, doc='''A read only property that returns an lldb object that represents the top level lexical block (lldb.SBBlock) for this function.''') + + __swig_getmethods__["instructions"] = get_instructions_from_current_target + if _newclass: instructions = property(get_instructions_from_current_target, None, doc='''A read only property that returns an lldb object that represents the instructions (lldb.SBInstructionList) for this function.''') + + __swig_getmethods__["mangled"] = GetMangledName + if _newclass: mangled = property(GetMangledName, None, doc='''A read only property that returns the mangled (linkage) name for this function as a string.''') + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name for this function as a string.''') + + __swig_getmethods__["prologue_size"] = GetPrologueByteSize + if _newclass: prologue_size = property(GetPrologueByteSize, None, doc='''A read only property that returns the size in bytes of the prologue instructions as an unsigned integer.''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns an lldb object that represents the return type (lldb.SBType) for this function.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBHostOS.i b/scripts/interface/SBHostOS.i new file mode 100644 index 0000000000000..d9f42160bf09e --- /dev/null +++ b/scripts/interface/SBHostOS.i @@ -0,0 +1,47 @@ +//===-- SWIG Interface for SBHostOS -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBHostOS +{ +public: + + static lldb::SBFileSpec + GetProgramFileSpec (); + + static lldb::SBFileSpec + GetLLDBPythonPath (); + + static lldb::SBFileSpec + GetLLDBPath (lldb::PathType path_type); + + static void + ThreadCreated (const char *name); + + static lldb::thread_t + ThreadCreate (const char *name, + lldb::thread_func_t, + void *thread_arg, + lldb::SBError *err); + + static bool + ThreadCancel (lldb::thread_t thread, + lldb::SBError *err); + + static bool + ThreadDetach (lldb::thread_t thread, + lldb::SBError *err); + static bool + ThreadJoin (lldb::thread_t thread, + lldb::thread_result_t *result, + lldb::SBError *err); +}; + +} // namespace lldb diff --git a/scripts/interface/SBInstruction.i b/scripts/interface/SBInstruction.i new file mode 100644 index 0000000000000..421990646a120 --- /dev/null +++ b/scripts/interface/SBInstruction.i @@ -0,0 +1,103 @@ +//===-- SWIG Interface for SBInstruction ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +// There's a lot to be fixed here, but need to wait for underlying insn implementation +// to be revised & settle down first. + +namespace lldb { + +class SBInstruction +{ +public: + + SBInstruction (); + + SBInstruction (const SBInstruction &rhs); + + ~SBInstruction (); + + bool + IsValid(); + + lldb::SBAddress + GetAddress(); + + lldb::AddressClass + GetAddressClass (); + + const char * + GetMnemonic (lldb::SBTarget target); + + const char * + GetOperands (lldb::SBTarget target); + + const char * + GetComment (lldb::SBTarget target); + + lldb::SBData + GetData (lldb::SBTarget target); + + size_t + GetByteSize (); + + bool + DoesBranch (); + + void + Print (FILE *out); + + bool + GetDescription (lldb::SBStream &description); + + bool + EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options); + + bool + DumpEmulation (const char * triple); // triple is to specify the architecture, e.g. 'armv6' or 'armv7-apple-ios' + + bool + TestEmulation (lldb::SBStream &output_stream, const char *test_file); + + %pythoncode %{ + def __mnemonic_property__ (self): + return self.GetMnemonic (target) + def __operands_property__ (self): + return self.GetOperands (target) + def __comment_property__ (self): + return self.GetComment (target) + def __file_addr_property__ (self): + return self.GetAddress ().GetFileAddress() + def __load_adrr_property__ (self): + return self.GetComment (target) + + __swig_getmethods__["mnemonic"] = __mnemonic_property__ + if _newclass: mnemonic = property(__mnemonic_property__, None, doc='''A read only property that returns the mnemonic for this instruction as a string.''') + + __swig_getmethods__["operands"] = __operands_property__ + if _newclass: operands = property(__operands_property__, None, doc='''A read only property that returns the operands for this instruction as a string.''') + + __swig_getmethods__["comment"] = __comment_property__ + if _newclass: comment = property(__comment_property__, None, doc='''A read only property that returns the comment for this instruction as a string.''') + + __swig_getmethods__["addr"] = GetAddress + if _newclass: addr = property(GetAddress, None, doc='''A read only property that returns an lldb object that represents the address (lldb.SBAddress) for this instruction.''') + + __swig_getmethods__["size"] = GetByteSize + if _newclass: size = property(GetByteSize, None, doc='''A read only property that returns the size in bytes for this instruction as an integer.''') + + __swig_getmethods__["is_branch"] = DoesBranch + if _newclass: is_branch = property(DoesBranch, None, doc='''A read only property that returns a boolean value that indicates if this instruction is a branch instruction.''') + %} + + +}; + +} // namespace lldb diff --git a/scripts/interface/SBInstructionList.i b/scripts/interface/SBInstructionList.i new file mode 100644 index 0000000000000..32603be5cc1e0 --- /dev/null +++ b/scripts/interface/SBInstructionList.i @@ -0,0 +1,91 @@ +//===-- SWIG Interface for SBInstructionList --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +namespace lldb { + +%feature("docstring", +"Represents a list of machine instructions. SBFunction and SBSymbol have +GetInstructions() methods which return SBInstructionList instances. + +SBInstructionList supports instruction (SBInstruction instance) iteration. +For example (see also SBDebugger for a more complete example), + +def disassemble_instructions (insts): + for i in insts: + print i + +defines a function which takes an SBInstructionList instance and prints out +the machine instructions in assembly format." +) SBInstructionList; +class SBInstructionList +{ +public: + + SBInstructionList (); + + SBInstructionList (const SBInstructionList &rhs); + + ~SBInstructionList (); + + bool + IsValid () const; + + size_t + GetSize (); + + lldb::SBInstruction + GetInstructionAtIndex (uint32_t idx); + + void + Clear (); + + void + AppendInstruction (lldb::SBInstruction inst); + + void + Print (FILE *out); + + bool + GetDescription (lldb::SBStream &description); + + bool + DumpEmulationForAllInstructions (const char *triple); + + %pythoncode %{ + def __len__(self): + '''Access len of the instruction list.''' + return int(self.GetSize()) + + def __getitem__(self, key): + '''Access instructions by integer index for array access or by lldb.SBAddress to find an instruction that matches a section offset address object.''' + if type(key) is int: + # Find an instruction by index + if key < len(self): + return self.GetInstructionAtIndex(key) + elif type(key) is SBAddress: + # Find an instruction using a lldb.SBAddress object + lookup_file_addr = key.file_addr + closest_inst = None + for idx in range(self.GetSize()): + inst = self.GetInstructionAtIndex(idx) + inst_file_addr = inst.addr.file_addr + if inst_file_addr == lookup_file_addr: + return inst + elif inst_file_addr > lookup_file_addr: + return closest_inst + else: + closest_inst = inst + return None + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBLanguageRuntime.i b/scripts/interface/SBLanguageRuntime.i new file mode 100644 index 0000000000000..95153ba0cdcb3 --- /dev/null +++ b/scripts/interface/SBLanguageRuntime.i @@ -0,0 +1,22 @@ +//===-- SWIG Interface for SBLanguageRuntime --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBLanguageRuntime +{ +public: + static lldb::LanguageType + GetLanguageTypeFromString (const char *string); + + static const char * + GetNameForLanguageType (lldb::LanguageType language); +}; + +} // namespace lldb diff --git a/scripts/interface/SBLaunchInfo.i b/scripts/interface/SBLaunchInfo.i new file mode 100644 index 0000000000000..24f3f853f198f --- /dev/null +++ b/scripts/interface/SBLaunchInfo.i @@ -0,0 +1,132 @@ +//===-- SWIG Interface for SBLaunchInfo--------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBLaunchInfo +{ +public: + SBLaunchInfo (const char **argv); + + pid_t + GetProcessID(); + + uint32_t + GetUserID(); + + uint32_t + GetGroupID(); + + bool + UserIDIsValid (); + + bool + GroupIDIsValid (); + + void + SetUserID (uint32_t uid); + + void + SetGroupID (uint32_t gid); + + lldb::SBFileSpec + GetExecutableFile (); + + void + SetExecutableFile (lldb::SBFileSpec exe_file, bool add_as_first_arg); + + lldb::SBListener + GetListener (); + + void + SetListener (lldb::SBListener &listener); + + uint32_t + GetNumArguments (); + + const char * + GetArgumentAtIndex (uint32_t idx); + + void + SetArguments (const char **argv, bool append); + + uint32_t + GetNumEnvironmentEntries (); + + const char * + GetEnvironmentEntryAtIndex (uint32_t idx); + + void + SetEnvironmentEntries (const char **envp, bool append); + + void + Clear (); + + const char * + GetWorkingDirectory () const; + + void + SetWorkingDirectory (const char *working_dir); + + uint32_t + GetLaunchFlags (); + + void + SetLaunchFlags (uint32_t flags); + + const char * + GetProcessPluginName (); + + void + SetProcessPluginName (const char *plugin_name); + + const char * + GetShell (); + + void + SetShell (const char * path); + + bool + GetShellExpandArguments (); + + void + SetShellExpandArguments (bool expand); + + uint32_t + GetResumeCount (); + + void + SetResumeCount (uint32_t c); + + bool + AddCloseFileAction (int fd); + + bool + AddDuplicateFileAction (int fd, int dup_fd); + + bool + AddOpenFileAction (int fd, const char *path, bool read, bool write); + + bool + AddSuppressFileAction (int fd, bool read, bool write); + + void + SetLaunchEventData (const char *data); + + const char * + GetLaunchEventData () const; + + bool + GetDetachOnError() const; + + void + SetDetachOnError(bool enable); +}; + +} // namespace lldb diff --git a/scripts/interface/SBLineEntry.i b/scripts/interface/SBLineEntry.i new file mode 100644 index 0000000000000..fbe2100086f1b --- /dev/null +++ b/scripts/interface/SBLineEntry.i @@ -0,0 +1,106 @@ +//===-- SWIG Interface for SBLineEntry --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Specifies an association with a contiguous range of instructions and +a source file location. SBCompileUnit contains SBLineEntry(s). For example, + + for lineEntry in compileUnit: + print('line entry: %s:%d' % (str(lineEntry.GetFileSpec()), + lineEntry.GetLine())) + print('start addr: %s' % str(lineEntry.GetStartAddress())) + print('end addr: %s' % str(lineEntry.GetEndAddress())) + +produces: + +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 +start addr: a.out[0x100000d98] +end addr: a.out[0x100000da3] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 +start addr: a.out[0x100000da3] +end addr: a.out[0x100000da9] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 +start addr: a.out[0x100000da9] +end addr: a.out[0x100000db6] +line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 +start addr: a.out[0x100000db6] +end addr: a.out[0x100000dbc] +... + +See also SBCompileUnit." +) SBLineEntry; +class SBLineEntry +{ +public: + + SBLineEntry (); + + SBLineEntry (const lldb::SBLineEntry &rhs); + + ~SBLineEntry (); + + lldb::SBAddress + GetStartAddress () const; + + lldb::SBAddress + GetEndAddress () const; + + bool + IsValid () const; + + lldb::SBFileSpec + GetFileSpec () const; + + uint32_t + GetLine () const; + + uint32_t + GetColumn () const; + + bool + GetDescription (lldb::SBStream &description); + + void + SetFileSpec (lldb::SBFileSpec filespec); + + void + SetLine (uint32_t line); + + void + SetColumn (uint32_t column); + + bool + operator == (const lldb::SBLineEntry &rhs) const; + + bool + operator != (const lldb::SBLineEntry &rhs) const; + + %pythoncode %{ + __swig_getmethods__["file"] = GetFileSpec + if _newclass: file = property(GetFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this line entry.''') + + __swig_getmethods__["line"] = GetLine + if _newclass: line = property(GetLine, None, doc='''A read only property that returns the 1 based line number for this line entry, a return value of zero indicates that no line information is available.''') + + __swig_getmethods__["column"] = GetColumn + if _newclass: column = property(GetColumn, None, doc='''A read only property that returns the 1 based column number for this line entry, a return value of zero indicates that no column information is available.''') + + __swig_getmethods__["addr"] = GetStartAddress + if _newclass: addr = property(GetStartAddress, None, doc='''A read only property that returns an lldb object that represents the start address (lldb.SBAddress) for this line entry.''') + + __swig_getmethods__["end_addr"] = GetEndAddress + if _newclass: end_addr = property(GetEndAddress, None, doc='''A read only property that returns an lldb object that represents the end address (lldb.SBAddress) for this line entry.''') + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBListener.i b/scripts/interface/SBListener.i new file mode 100644 index 0000000000000..3bd376012f046 --- /dev/null +++ b/scripts/interface/SBListener.i @@ -0,0 +1,99 @@ +//===-- SWIG Interface for SBListener ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"API clients can register its own listener to debugger events. + +See aslo SBEvent for example usage of creating and adding a listener." +) SBListener; +class SBListener +{ +public: + SBListener (); + + SBListener (const char *name); + + SBListener (const SBListener &rhs); + + ~SBListener (); + + void + AddEvent (const lldb::SBEvent &event); + + void + Clear (); + + bool + IsValid () const; + + uint32_t + StartListeningForEventClass (SBDebugger &debugger, + const char *broadcaster_class, + uint32_t event_mask); + + uint32_t + StopListeningForEventClass (SBDebugger &debugger, + const char *broadcaster_class, + uint32_t event_mask); + + uint32_t + StartListeningForEvents (const lldb::SBBroadcaster& broadcaster, + uint32_t event_mask); + + bool + StopListeningForEvents (const lldb::SBBroadcaster& broadcaster, + uint32_t event_mask); + + // Returns true if an event was received, false if we timed out. + bool + WaitForEvent (uint32_t num_seconds, + lldb::SBEvent &event); + + bool + WaitForEventForBroadcaster (uint32_t num_seconds, + const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool + WaitForEventForBroadcasterWithType (uint32_t num_seconds, + const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, + lldb::SBEvent &sb_event); + + bool + PeekAtNextEvent (lldb::SBEvent &sb_event); + + bool + PeekAtNextEventForBroadcaster (const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool + PeekAtNextEventForBroadcasterWithType (const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, + lldb::SBEvent &sb_event); + + bool + GetNextEvent (lldb::SBEvent &sb_event); + + bool + GetNextEventForBroadcaster (const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool + GetNextEventForBroadcasterWithType (const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, + lldb::SBEvent &sb_event); + + bool + HandleBroadcastEvent (const lldb::SBEvent &event); +}; + +} // namespace lldb diff --git a/scripts/interface/SBModule.i b/scripts/interface/SBModule.i new file mode 100644 index 0000000000000..b1b6d2a7ca3d6 --- /dev/null +++ b/scripts/interface/SBModule.i @@ -0,0 +1,530 @@ +//===-- SWIG Interface for SBModule -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents an executable image and its associated object and symbol files. + +The module is designed to be able to select a single slice of an +executable image as it would appear on disk and during program +execution. + +You can retrieve SBModule from SBSymbolContext, which in turn is available +from SBFrame. + +SBModule supports symbol iteration, for example, + + for symbol in module: + name = symbol.GetName() + saddr = symbol.GetStartAddress() + eaddr = symbol.GetEndAddress() + +and rich comparion methods which allow the API program to use, + + if thisModule == thatModule: + print('This module is the same as that module') + +to test module equality. A module also contains object file sections, namely +SBSection. SBModule supports section iteration through section_iter(), for +example, + + print('Number of sections: %d' % module.GetNumSections()) + for sec in module.section_iter(): + print(sec) + +And to iterate the symbols within a SBSection, use symbol_in_section_iter(), + + # Iterates the text section and prints each symbols within each sub-section. + for subsec in text_sec: + print(INDENT + repr(subsec)) + for sym in exe_module.symbol_in_section_iter(subsec): + print(INDENT2 + repr(sym)) + print(INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())) + +produces this following output: + + [0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text + id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870) + symbol type: code + id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0) + symbol type: code + id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c) + symbol type: code + id = {0x00000023}, name = 'start', address = 0x0000000100001780 + symbol type: code + [0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs + id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62) + symbol type: trampoline + id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68) + symbol type: trampoline + id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e) + symbol type: trampoline + id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74) + symbol type: trampoline + id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a) + symbol type: trampoline + id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80) + symbol type: trampoline + id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86) + symbol type: trampoline + id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c) + symbol type: trampoline + id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92) + symbol type: trampoline + id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98) + symbol type: trampoline + id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e) + symbol type: trampoline + id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4) + symbol type: trampoline + [0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper + [0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring + [0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info + [0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame +" +) SBModule; +class SBModule +{ +public: + + SBModule (); + + SBModule (const lldb::SBModule &rhs); + + SBModule (const lldb::SBModuleSpec &module_spec); + + SBModule (lldb::SBProcess &process, + lldb::addr_t header_addr); + + ~SBModule (); + + bool + IsValid () const; + + void + Clear(); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get const accessor for the module file specification. + /// + /// This function returns the file for the module on the host system + /// that is running LLDB. This can differ from the path on the + /// platform since we might be doing remote debugging. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + ") GetFileSpec; + lldb::SBFileSpec + GetFileSpec () const; + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get accessor for the module platform file specification. + /// + /// Platform file refers to the path of the module as it is known on + /// the remote system on which it is being debugged. For local + /// debugging this is always the same as Module::GetFileSpec(). But + /// remote debugging might mention a file '/usr/lib/liba.dylib' + /// which might be locally downloaded and cached. In this case the + /// platform file could be something like: + /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib' + /// The file could also be cached in a local developer kit directory. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + ") GetPlatformFileSpec; + lldb::SBFileSpec + GetPlatformFileSpec () const; + + bool + SetPlatformFileSpec (const lldb::SBFileSpec &platform_file); + + lldb::SBFileSpec + GetRemoteInstallFileSpec (); + + bool + SetRemoteInstallFileSpec (lldb::SBFileSpec &file); + + %feature("docstring", "Returns the UUID of the module as a Python string." + ) GetUUIDString; + const char * + GetUUIDString () const; + + lldb::SBSection + FindSection (const char *sect_name); + + lldb::SBAddress + ResolveFileAddress (lldb::addr_t vm_addr); + + lldb::SBSymbolContext + ResolveSymbolContextForAddress (const lldb::SBAddress& addr, + uint32_t resolve_scope); + + bool + GetDescription (lldb::SBStream &description); + + uint32_t + GetNumCompileUnits(); + + lldb::SBCompileUnit + GetCompileUnitAtIndex (uint32_t); + + size_t + GetNumSymbols (); + + lldb::SBSymbol + GetSymbolAtIndex (size_t idx); + + lldb::SBSymbol + FindSymbol (const char *name, + lldb::SymbolType type = eSymbolTypeAny); + + lldb::SBSymbolContextList + FindSymbols (const char *name, + lldb::SymbolType type = eSymbolTypeAny); + + + size_t + GetNumSections (); + + lldb::SBSection + GetSectionAtIndex (size_t idx); + + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// @param[in] name + /// The name of the function we are looking for. + /// + /// @param[in] name_type_mask + /// A logical OR of one or more FunctionNameType enum bits that + /// indicate what kind of names should be used when doing the + /// lookup. Bits include fully qualified names, base names, + /// C++ methods, or ObjC selectors. + /// See FunctionNameType for more details. + /// + /// @return + /// A symbol context list that gets filled in with all of the + /// matches. + //------------------------------------------------------------------ + ") FindFunctions; + lldb::SBSymbolContextList + FindFunctions (const char *name, + uint32_t name_type_mask = lldb::eFunctionNameTypeAny); + + lldb::SBType + FindFirstType (const char* name); + + lldb::SBTypeList + FindTypes (const char* type); + + lldb::SBType + GetTypeByID (lldb::user_id_t uid); + + lldb::SBType + GetBasicType(lldb::BasicType type); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get all types matching \a type_mask from debug info in this + /// module. + /// + /// @param[in] type_mask + /// A bitfield that consists of one or more bits logically OR'ed + /// together from the lldb::TypeClass enumeration. This allows + /// you to request only structure types, or only class, struct + /// and union types. Passing in lldb::eTypeClassAny will return + /// all types found in the debug information for this module. + /// + /// @return + /// A list of types in this module that match \a type_mask + //------------------------------------------------------------------ + ") GetTypes; + lldb::SBTypeList + GetTypes (uint32_t type_mask = lldb::eTypeClassAny); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find global and static variables by name. + /// + /// @param[in] target + /// A valid SBTarget instance representing the debuggee. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + ") FindGlobalVariables; + lldb::SBValueList + FindGlobalVariables (lldb::SBTarget &target, + const char *name, + uint32_t max_matches); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find the first global (or static) variable by name. + /// + /// @param[in] target + /// A valid SBTarget instance representing the debuggee. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @return + /// An SBValue that gets filled in with the found variable (if any). + //------------------------------------------------------------------ + ") FindFirstGlobalVariable; + lldb::SBValue + FindFirstGlobalVariable (lldb::SBTarget &target, const char *name); + + lldb::ByteOrder + GetByteOrder (); + + uint32_t + GetAddressByteSize(); + + const char * + GetTriple (); + + uint32_t + GetVersion (uint32_t *versions, + uint32_t num_versions); + + lldb::SBFileSpec + GetSymbolFileSpec() const; + + lldb::SBAddress + GetObjectFileHeaderAddress() const; + + bool + operator == (const lldb::SBModule &rhs) const; + + bool + operator != (const lldb::SBModule &rhs) const; + + %pythoncode %{ + class symbols_access(object): + re_compile_type = type(re.compile('.')) + '''A helper object that will lazily hand out lldb.SBSymbol objects for a module when supplied an index, name, or regular expression.''' + def __init__(self, sbmodule): + self.sbmodule = sbmodule + + def __len__(self): + if self.sbmodule: + return int(self.sbmodule.GetNumSymbols()) + return 0 + + def __getitem__(self, key): + count = len(self) + if type(key) is int: + if key < count: + return self.sbmodule.GetSymbolAtIndex(key) + elif type(key) is str: + matches = [] + sc_list = self.sbmodule.FindSymbols(key) + for sc in sc_list: + symbol = sc.symbol + if symbol: + matches.append(symbol) + return matches + elif isinstance(key, self.re_compile_type): + matches = [] + for idx in range(count): + symbol = self.sbmodule.GetSymbolAtIndex(idx) + added = False + name = symbol.name + if name: + re_match = key.search(name) + if re_match: + matches.append(symbol) + added = True + if not added: + mangled = symbol.mangled + if mangled: + re_match = key.search(mangled) + if re_match: + matches.append(symbol) + return matches + else: + print("error: unsupported item type: %s" % type(key)) + return None + + def get_symbols_access_object(self): + '''An accessor function that returns a symbols_access() object which allows lazy symbol access from a lldb.SBModule object.''' + return self.symbols_access (self) + + def get_compile_units_access_object (self): + '''An accessor function that returns a compile_units_access() object which allows lazy compile unit access from a lldb.SBModule object.''' + return self.compile_units_access (self) + + def get_symbols_array(self): + '''An accessor function that returns a list() that contains all symbols in a lldb.SBModule object.''' + symbols = [] + for idx in range(self.num_symbols): + symbols.append(self.GetSymbolAtIndex(idx)) + return symbols + + class sections_access(object): + re_compile_type = type(re.compile('.')) + '''A helper object that will lazily hand out lldb.SBSection objects for a module when supplied an index, name, or regular expression.''' + def __init__(self, sbmodule): + self.sbmodule = sbmodule + + def __len__(self): + if self.sbmodule: + return int(self.sbmodule.GetNumSections()) + return 0 + + def __getitem__(self, key): + count = len(self) + if type(key) is int: + if key < count: + return self.sbmodule.GetSectionAtIndex(key) + elif type(key) is str: + for idx in range(count): + section = self.sbmodule.GetSectionAtIndex(idx) + if section.name == key: + return section + elif isinstance(key, self.re_compile_type): + matches = [] + for idx in range(count): + section = self.sbmodule.GetSectionAtIndex(idx) + name = section.name + if name: + re_match = key.search(name) + if re_match: + matches.append(section) + return matches + else: + print("error: unsupported item type: %s" % type(key)) + return None + + class compile_units_access(object): + re_compile_type = type(re.compile('.')) + '''A helper object that will lazily hand out lldb.SBCompileUnit objects for a module when supplied an index, full or partial path, or regular expression.''' + def __init__(self, sbmodule): + self.sbmodule = sbmodule + + def __len__(self): + if self.sbmodule: + return int(self.sbmodule.GetNumCompileUnits()) + return 0 + + def __getitem__(self, key): + count = len(self) + if type(key) is int: + if key < count: + return self.sbmodule.GetCompileUnitAtIndex(key) + elif type(key) is str: + is_full_path = key[0] == '/' + for idx in range(count): + comp_unit = self.sbmodule.GetCompileUnitAtIndex(idx) + if is_full_path: + if comp_unit.file.fullpath == key: + return comp_unit + else: + if comp_unit.file.basename == key: + return comp_unit + elif isinstance(key, self.re_compile_type): + matches = [] + for idx in range(count): + comp_unit = self.sbmodule.GetCompileUnitAtIndex(idx) + fullpath = comp_unit.file.fullpath + if fullpath: + re_match = key.search(fullpath) + if re_match: + matches.append(comp_unit) + return matches + else: + print("error: unsupported item type: %s" % type(key)) + return None + + def get_sections_access_object(self): + '''An accessor function that returns a sections_access() object which allows lazy section array access.''' + return self.sections_access (self) + + def get_sections_array(self): + '''An accessor function that returns an array object that contains all sections in this module object.''' + if not hasattr(self, 'sections_array'): + self.sections_array = [] + for idx in range(self.num_sections): + self.sections_array.append(self.GetSectionAtIndex(idx)) + return self.sections_array + + def get_compile_units_array(self): + '''An accessor function that returns an array object that contains all compile_units in this module object.''' + if not hasattr(self, 'compile_units_array'): + self.compile_units_array = [] + for idx in range(self.GetNumCompileUnits()): + self.compile_units_array.append(self.GetCompileUnitAtIndex(idx)) + return self.compile_units_array + + __swig_getmethods__["symbols"] = get_symbols_array + if _newclass: symbols = property(get_symbols_array, None, doc='''A read only property that returns a list() of lldb.SBSymbol objects contained in this module.''') + + __swig_getmethods__["symbol"] = get_symbols_access_object + if _newclass: symbol = property(get_symbols_access_object, None, doc='''A read only property that can be used to access symbols by index ("symbol = module.symbol[0]"), name ("symbols = module.symbol['main']"), or using a regular expression ("symbols = module.symbol[re.compile(...)]"). The return value is a single lldb.SBSymbol object for array access, and a list() of lldb.SBSymbol objects for name and regular expression access''') + + __swig_getmethods__["sections"] = get_sections_array + if _newclass: sections = property(get_sections_array, None, doc='''A read only property that returns a list() of lldb.SBSection objects contained in this module.''') + + __swig_getmethods__["compile_units"] = get_compile_units_array + if _newclass: compile_units = property(get_compile_units_array, None, doc='''A read only property that returns a list() of lldb.SBCompileUnit objects contained in this module.''') + + __swig_getmethods__["section"] = get_sections_access_object + if _newclass: section = property(get_sections_access_object, None, doc='''A read only property that can be used to access symbols by index ("section = module.section[0]"), name ("sections = module.section[\'main\']"), or using a regular expression ("sections = module.section[re.compile(...)]"). The return value is a single lldb.SBSection object for array access, and a list() of lldb.SBSection objects for name and regular expression access''') + + __swig_getmethods__["compile_unit"] = get_compile_units_access_object + if _newclass: section = property(get_sections_access_object, None, doc='''A read only property that can be used to access compile units by index ("compile_unit = module.compile_unit[0]"), name ("compile_unit = module.compile_unit[\'main.cpp\']"), or using a regular expression ("compile_unit = module.compile_unit[re.compile(...)]"). The return value is a single lldb.SBCompileUnit object for array access or by full or partial path, and a list() of lldb.SBCompileUnit objects regular expressions.''') + + def get_uuid(self): + return uuid.UUID (self.GetUUIDString()) + + __swig_getmethods__["uuid"] = get_uuid + if _newclass: uuid = property(get_uuid, None, doc='''A read only property that returns a standard python uuid.UUID object that represents the UUID of this module.''') + + __swig_getmethods__["file"] = GetFileSpec + if _newclass: file = property(GetFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this object file for this module as it is represented where it is being debugged.''') + + __swig_getmethods__["platform_file"] = GetPlatformFileSpec + if _newclass: platform_file = property(GetPlatformFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this object file for this module as it is represented on the current host system.''') + + __swig_getmethods__["byte_order"] = GetByteOrder + if _newclass: byte_order = property(GetByteOrder, None, doc='''A read only property that returns an lldb enumeration value (lldb.eByteOrderLittle, lldb.eByteOrderBig, lldb.eByteOrderInvalid) that represents the byte order for this module.''') + + __swig_getmethods__["addr_size"] = GetAddressByteSize + if _newclass: addr_size = property(GetAddressByteSize, None, doc='''A read only property that returns the size in bytes of an address for this module.''') + + __swig_getmethods__["triple"] = GetTriple + if _newclass: triple = property(GetTriple, None, doc='''A read only property that returns the target triple (arch-vendor-os) for this module.''') + + __swig_getmethods__["num_symbols"] = GetNumSymbols + if _newclass: num_symbols = property(GetNumSymbols, None, doc='''A read only property that returns number of symbols in the module symbol table as an integer.''') + + __swig_getmethods__["num_sections"] = GetNumSections + if _newclass: num_sections = property(GetNumSections, None, doc='''A read only property that returns number of sections in the module as an integer.''') + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBModuleSpec.i b/scripts/interface/SBModuleSpec.i new file mode 100644 index 0000000000000..55fd9b1a043de --- /dev/null +++ b/scripts/interface/SBModuleSpec.i @@ -0,0 +1,133 @@ +//===-- SWIG Interface for SBModule -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBModuleSpec +{ +public: + + SBModuleSpec (); + + SBModuleSpec (const lldb::SBModuleSpec &rhs); + + ~SBModuleSpec (); + + bool + IsValid () const; + + void + Clear(); + + //------------------------------------------------------------------ + /// Get const accessor for the module file. + /// + /// This function returns the file for the module on the host system + /// that is running LLDB. This can differ from the path on the + /// platform since we might be doing remote debugging. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec + GetFileSpec (); + + void + SetFileSpec (const lldb::SBFileSpec &fspec); + + //------------------------------------------------------------------ + /// Get accessor for the module platform file. + /// + /// Platform file refers to the path of the module as it is known on + /// the remote system on which it is being debugged. For local + /// debugging this is always the same as Module::GetFileSpec(). But + /// remote debugging might mention a file '/usr/lib/liba.dylib' + /// which might be locally downloaded and cached. In this case the + /// platform file could be something like: + /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib' + /// The file could also be cached in a local developer kit directory. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec + GetPlatformFileSpec (); + + void + SetPlatformFileSpec (const lldb::SBFileSpec &fspec); + + lldb::SBFileSpec + GetSymbolFileSpec (); + + void + SetSymbolFileSpec (const lldb::SBFileSpec &fspec); + + const char * + GetObjectName (); + + void + SetObjectName (const char *name); + + const char * + GetTriple (); + + void + SetTriple (const char *triple); + + const uint8_t * + GetUUIDBytes (); + + size_t + GetUUIDLength (); + + bool + SetUUIDBytes (const uint8_t *uuid, size_t uuid_len); + + bool + GetDescription (lldb::SBStream &description); + +}; + + +class SBModuleSpecList +{ +public: + SBModuleSpecList(); + + SBModuleSpecList (const SBModuleSpecList &rhs); + + ~SBModuleSpecList(); + + static SBModuleSpecList + GetModuleSpecifications (const char *path); + + void + Append (const lldb::SBModuleSpec &spec); + + void + Append (const lldb::SBModuleSpecList &spec_list); + + lldb::SBModuleSpec + FindFirstMatchingSpec (const lldb::SBModuleSpec &match_spec); + + lldb::SBModuleSpecList + FindMatchingSpecs (const lldb::SBModuleSpec &match_spec); + + size_t + GetSize(); + + lldb::SBModuleSpec + GetSpecAtIndex (size_t i); + + bool + GetDescription (lldb::SBStream &description); + +}; + +} // namespace lldb diff --git a/scripts/interface/SBPlatform.i b/scripts/interface/SBPlatform.i new file mode 100644 index 0000000000000..9234a3dbd86f7 --- /dev/null +++ b/scripts/interface/SBPlatform.i @@ -0,0 +1,196 @@ +//===-- SWIG Interface for SBPlatform ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + +class SBPlatformConnectOptions +{ +public: + SBPlatformConnectOptions (const char *url); + + SBPlatformConnectOptions (const SBPlatformConnectOptions &rhs); + + ~SBPlatformConnectOptions (); + + const char * + GetURL(); + + void + SetURL(const char *url); + + bool + GetRsyncEnabled(); + + void + EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_remote_hostname); + + void + DisableRsync (); + + const char * + GetLocalCacheDirectory(); + + void + SetLocalCacheDirectory(const char *path); +}; + +class SBPlatformShellCommand +{ +public: + SBPlatformShellCommand (const char *shell_command); + + SBPlatformShellCommand (const SBPlatformShellCommand &rhs); + + ~SBPlatformShellCommand(); + + void + Clear(); + + const char * + GetCommand(); + + void + SetCommand(const char *shell_command); + + const char * + GetWorkingDirectory (); + + void + SetWorkingDirectory (const char *path); + + uint32_t + GetTimeoutSeconds (); + + void + SetTimeoutSeconds (uint32_t sec); + + int + GetSignal (); + + int + GetStatus (); + + const char * + GetOutput (); +}; + +%feature("docstring", +"A class that represents a platform that can represent the current host or a remote host debug platform. + +The SBPlatform class represents the current host, or a remote host. +It can be connected to a remote platform in order to provide ways +to remotely launch and attach to processes, upload/download files, +create directories, run remote shell commands, find locally cached +versions of files from the remote system, and much more. + +SBPlatform objects can be created and then used to connect to a remote +platform which allows the SBPlatform to be used to get a list of the +current processes on the remote host, attach to one of those processes, +install programs on the remote system, attach and launch processes, +and much more. + +Every SBTarget has a corresponding SBPlatform. The platform can be +specified upon target creation, or the currently selected platform +will attempt to be used when creating the target automatically as long +as the currently selected platform matches the target architecture +and executable type. If the architecture or executable type do not match, +a suitable platform will be found automatically." + +) SBPlatform; +class SBPlatform +{ +public: + + SBPlatform (); + + SBPlatform (const char *); + + ~SBPlatform(); + + bool + IsValid () const; + + void + Clear (); + + const char * + GetWorkingDirectory(); + + bool + SetWorkingDirectory(const char *); + + const char * + GetName (); + + SBError + ConnectRemote (lldb::SBPlatformConnectOptions &connect_options); + + void + DisconnectRemote (); + + bool + IsConnected(); + + const char * + GetTriple(); + + const char * + GetHostname (); + + const char * + GetOSBuild (); + + const char * + GetOSDescription (); + + uint32_t + GetOSMajorVersion (); + + uint32_t + GetOSMinorVersion (); + + uint32_t + GetOSUpdateVersion (); + + lldb::SBError + Get (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Put (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Install (lldb::SBFileSpec &src, lldb::SBFileSpec &dst); + + lldb::SBError + Run (lldb::SBPlatformShellCommand &shell_command); + + lldb::SBError + Launch (lldb::SBLaunchInfo &launch_info); + + lldb::SBError + Kill (const lldb::pid_t pid); + + lldb::SBError + MakeDirectory (const char *path, uint32_t file_permissions = lldb::eFilePermissionsDirectoryDefault); + + uint32_t + GetFilePermissions (const char *path); + + lldb::SBError + SetFilePermissions (const char *path, uint32_t file_permissions); + + lldb::SBUnixSignals + GetUnixSignals(); + +}; + +} // namespace lldb diff --git a/scripts/interface/SBProcess.i b/scripts/interface/SBProcess.i new file mode 100644 index 0000000000000..1571ebc4cb68d --- /dev/null +++ b/scripts/interface/SBProcess.i @@ -0,0 +1,502 @@ +//===-- SWIG Interface for SBProcess ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents the process associated with the target program. + +SBProcess supports thread iteration. For example (from test/lldbutil.py), + +# ================================================== +# Utility functions related to Threads and Processes +# ================================================== + +def get_stopped_threads(process, reason): + '''Returns the thread(s) with the specified stop reason in a list. + + The list can be empty if no such thread exists. + ''' + threads = [] + for t in process: + if t.GetStopReason() == reason: + threads.append(t) + return threads + +... +" +) SBProcess; +class SBProcess +{ +public: + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + enum + { + eBroadcastBitStateChanged = (1 << 0), + eBroadcastBitInterrupt = (1 << 1), + eBroadcastBitSTDOUT = (1 << 2), + eBroadcastBitSTDERR = (1 << 3), + eBroadcastBitProfileData = (1 << 4) + }; + + SBProcess (); + + SBProcess (const lldb::SBProcess& rhs); + + ~SBProcess(); + + static const char * + GetBroadcasterClassName (); + + const char * + GetPluginName (); + + const char * + GetShortPluginName (); + + void + Clear (); + + bool + IsValid() const; + + lldb::SBTarget + GetTarget() const; + + lldb::ByteOrder + GetByteOrder() const; + + %feature("autodoc", " + Writes data into the current process's stdin. API client specifies a Python + string as the only argument. + ") PutSTDIN; + size_t + PutSTDIN (const char *src, size_t src_len); + + %feature("autodoc", " + Reads data from the current process's stdout stream. API client specifies + the size of the buffer to read data into. It returns the byte buffer in a + Python string. + ") GetSTDOUT; + size_t + GetSTDOUT (char *dst, size_t dst_len) const; + + %feature("autodoc", " + Reads data from the current process's stderr stream. API client specifies + the size of the buffer to read data into. It returns the byte buffer in a + Python string. + ") GetSTDERR; + size_t + GetSTDERR (char *dst, size_t dst_len) const; + + size_t + GetAsyncProfileData(char *dst, size_t dst_len) const; + + void + ReportEventState (const lldb::SBEvent &event, FILE *out) const; + + void + AppendEventStateReport (const lldb::SBEvent &event, lldb::SBCommandReturnObject &result); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Remote connection related functions. These will fail if the + /// process is not in eStateConnected. They are intended for use + /// when connecting to an externally managed debugserver instance. + //------------------------------------------------------------------ + ") RemoteAttachToProcessWithID; + bool + RemoteAttachToProcessWithID (lldb::pid_t pid, + lldb::SBError& error); + + %feature("docstring", + "See SBTarget.Launch for argument description and usage." + ) RemoteLaunch; + bool + RemoteLaunch (char const **argv, + char const **envp, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + const char *working_directory, + uint32_t launch_flags, + bool stop_at_entry, + lldb::SBError& error); + + //------------------------------------------------------------------ + // Thread related functions + //------------------------------------------------------------------ + uint32_t + GetNumThreads (); + + %feature("autodoc", " + Returns the INDEX'th thread from the list of current threads. The index + of a thread is only valid for the current stop. For a persistent thread + identifier use either the thread ID or the IndexID. See help on SBThread + for more details. + ") GetThreadAtIndex; + lldb::SBThread + GetThreadAtIndex (size_t index); + + %feature("autodoc", " + Returns the thread with the given thread ID. + ") GetThreadByID; + lldb::SBThread + GetThreadByID (lldb::tid_t sb_thread_id); + + %feature("autodoc", " + Returns the thread with the given thread IndexID. + ") GetThreadByIndexID; + lldb::SBThread + GetThreadByIndexID (uint32_t index_id); + + %feature("autodoc", " + Returns the currently selected thread. + ") GetSelectedThread; + lldb::SBThread + GetSelectedThread () const; + + %feature("autodoc", " + Lazily create a thread on demand through the current OperatingSystem plug-in, if the current OperatingSystem plug-in supports it. + ") CreateOSPluginThread; + lldb::SBThread + CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context); + + bool + SetSelectedThread (const lldb::SBThread &thread); + + bool + SetSelectedThreadByID (lldb::tid_t tid); + + bool + SetSelectedThreadByIndexID (uint32_t index_id); + + //------------------------------------------------------------------ + // Queue related functions + //------------------------------------------------------------------ + uint32_t + GetNumQueues (); + + lldb::SBQueue + GetQueueAtIndex (uint32_t index); + + //------------------------------------------------------------------ + // Stepping related functions + //------------------------------------------------------------------ + + lldb::StateType + GetState (); + + int + GetExitStatus (); + + const char * + GetExitDescription (); + + %feature("autodoc", " + Returns the process ID of the process. + ") GetProcessID; + lldb::pid_t + GetProcessID (); + + %feature("autodoc", " + Returns an integer ID that is guaranteed to be unique across all process instances. This is not the process ID, just a unique integer for comparison and caching purposes. + ") GetUniqueID; + uint32_t + GetUniqueID(); + + uint32_t + GetAddressByteSize() const; + + %feature("docstring", " + Kills the process and shuts down all threads that were spawned to + track and monitor process. + ") Destroy; + lldb::SBError + Destroy (); + + lldb::SBError + Continue (); + + lldb::SBError + Stop (); + + %feature("docstring", "Same as Destroy(self).") Destroy; + lldb::SBError + Kill (); + + lldb::SBError + Detach (); + + %feature("docstring", "Sends the process a unix signal.") Signal; + lldb::SBError + Signal (int signal); + + lldb::SBUnixSignals + GetUnixSignals(); + + %feature("docstring", " + Returns a stop id that will increase every time the process executes. If + include_expression_stops is true, then stops caused by expression evaluation + will cause the returned value to increase, otherwise the counter returned will + only increase when execution is continued explicitly by the user. Note, the value + will always increase, but may increase by more than one per stop. + ") GetStopID; + uint32_t + GetStopID(bool include_expression_stops = false); + + void + SendAsyncInterrupt(); + + %feature("autodoc", " + Reads memory from the current process's address space and removes any + traps that may have been inserted into the memory. It returns the byte + buffer in a Python string. Example: + + # Read 4 bytes from address 'addr' and assume error.Success() is True. + content = process.ReadMemory(addr, 4, error) + new_bytes = bytearray(content) + ") ReadMemory; + size_t + ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error); + + %feature("autodoc", " + Writes memory to the current process's address space and maintains any + traps that might be present due to software breakpoints. Example: + + # Create a Python string from the byte array. + new_value = str(bytes) + result = process.WriteMemory(addr, new_value, error) + if not error.Success() or result != len(bytes): + print('SBProcess.WriteMemory() failed!') + ") WriteMemory; + size_t + WriteMemory (addr_t addr, const void *buf, size_t size, lldb::SBError &error); + + %feature("autodoc", " + Reads a NULL terminated C string from the current process's address space. + It returns a python string of the exact length, or truncates the string if + the maximum character limit is reached. Example: + + # Read a C string of at most 256 bytes from address '0x1000' + error = lldb.SBError() + cstring = process.ReadCStringFromMemory(0x1000, 256, error) + if error.Success(): + print('cstring: ', cstring) + else + print('error: ', error) + ") ReadCStringFromMemory; + + size_t + ReadCStringFromMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error); + + %feature("autodoc", " + Reads an unsigned integer from memory given a byte size and an address. + Returns the unsigned integer that was read. Example: + + # Read a 4 byte unsigned integer from address 0x1000 + error = lldb.SBError() + uint = ReadUnsignedFromMemory(0x1000, 4, error) + if error.Success(): + print('integer: %u' % uint) + else + print('error: ', error) + + ") ReadUnsignedFromMemory; + + uint64_t + ReadUnsignedFromMemory (addr_t addr, uint32_t byte_size, lldb::SBError &error); + + %feature("autodoc", " + Reads a pointer from memory from an address and returns the value. Example: + + # Read a pointer from address 0x1000 + error = lldb.SBError() + ptr = ReadPointerFromMemory(0x1000, error) + if error.Success(): + print('pointer: 0x%x' % ptr) + else + print('error: ', error) + + ") ReadPointerFromMemory; + + lldb::addr_t + ReadPointerFromMemory (addr_t addr, lldb::SBError &error); + + + // Events + static lldb::StateType + GetStateFromEvent (const lldb::SBEvent &event); + + static bool + GetRestartedFromEvent (const lldb::SBEvent &event); + + static size_t + GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event); + + static const char * + GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx); + + static lldb::SBProcess + GetProcessFromEvent (const lldb::SBEvent &event); + + static bool + GetInterruptedFromEvent (const lldb::SBEvent &event); + + static bool + EventIsProcessEvent (const lldb::SBEvent &event); + + lldb::SBBroadcaster + GetBroadcaster () const; + + bool + GetDescription (lldb::SBStream &description); + + uint32_t + GetNumSupportedHardwareWatchpoints (lldb::SBError &error) const; + + uint32_t + LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error); + + lldb::SBError + UnloadImage (uint32_t image_token); + + lldb::SBError + SendEventData (const char *event_data); + + %feature("autodoc", " + Return the number of different thread-origin extended backtraces + this process can support as a uint32_t. + When the process is stopped and you have an SBThread, lldb may be + able to show a backtrace of when that thread was originally created, + or the work item was enqueued to it (in the case of a libdispatch + queue). + ") GetNumExtendedBacktraceTypes; + + uint32_t + GetNumExtendedBacktraceTypes (); + + %feature("autodoc", " + Takes an index argument, returns the name of one of the thread-origin + extended backtrace methods as a str. + ") GetExtendedBacktraceTypeAtIndex; + + const char * + GetExtendedBacktraceTypeAtIndex (uint32_t idx); + + lldb::SBThreadCollection + GetHistoryThreads (addr_t addr); + + bool + IsInstrumentationRuntimePresent(lldb::InstrumentationRuntimeType type); + + lldb::SBError + SaveCore(const char *file_name); + + %pythoncode %{ + def __get_is_alive__(self): + '''Returns "True" if the process is currently alive, "False" otherwise''' + s = self.GetState() + if (s == eStateAttaching or + s == eStateLaunching or + s == eStateStopped or + s == eStateRunning or + s == eStateStepping or + s == eStateCrashed or + s == eStateSuspended): + return True + return False + + def __get_is_running__(self): + '''Returns "True" if the process is currently running, "False" otherwise''' + state = self.GetState() + if state == eStateRunning or state == eStateStepping: + return True + return False + + def __get_is_running__(self): + '''Returns "True" if the process is currently stopped, "False" otherwise''' + state = self.GetState() + if state == eStateStopped or state == eStateCrashed or state == eStateSuspended: + return True + return False + + class threads_access(object): + '''A helper object that will lazily hand out thread for a process when supplied an index.''' + def __init__(self, sbprocess): + self.sbprocess = sbprocess + + def __len__(self): + if self.sbprocess: + return int(self.sbprocess.GetNumThreads()) + return 0 + + def __getitem__(self, key): + if type(key) is int and key < len(self): + return self.sbprocess.GetThreadAtIndex(key) + return None + + def get_threads_access_object(self): + '''An accessor function that returns a modules_access() object which allows lazy thread access from a lldb.SBProcess object.''' + return self.threads_access (self) + + def get_process_thread_list(self): + '''An accessor function that returns a list() that contains all threads in a lldb.SBProcess object.''' + threads = [] + accessor = self.get_threads_access_object() + for idx in range(len(accessor)): + threads.append(accessor[idx]) + return threads + + __swig_getmethods__["threads"] = get_process_thread_list + if _newclass: threads = property(get_process_thread_list, None, doc='''A read only property that returns a list() of lldb.SBThread objects for this process.''') + + __swig_getmethods__["thread"] = get_threads_access_object + if _newclass: thread = property(get_threads_access_object, None, doc='''A read only property that returns an object that can access threads by thread index (thread = lldb.process.thread[12]).''') + + __swig_getmethods__["is_alive"] = __get_is_alive__ + if _newclass: is_alive = property(__get_is_alive__, None, doc='''A read only property that returns a boolean value that indicates if this process is currently alive.''') + + __swig_getmethods__["is_running"] = __get_is_running__ + if _newclass: is_running = property(__get_is_running__, None, doc='''A read only property that returns a boolean value that indicates if this process is currently running.''') + + __swig_getmethods__["is_stopped"] = __get_is_running__ + if _newclass: is_stopped = property(__get_is_running__, None, doc='''A read only property that returns a boolean value that indicates if this process is currently stopped.''') + + __swig_getmethods__["id"] = GetProcessID + if _newclass: id = property(GetProcessID, None, doc='''A read only property that returns the process ID as an integer.''') + + __swig_getmethods__["target"] = GetTarget + if _newclass: target = property(GetTarget, None, doc='''A read only property that an lldb object that represents the target (lldb.SBTarget) that owns this process.''') + + __swig_getmethods__["num_threads"] = GetNumThreads + if _newclass: num_threads = property(GetNumThreads, None, doc='''A read only property that returns the number of threads in this process as an integer.''') + + __swig_getmethods__["selected_thread"] = GetSelectedThread + __swig_setmethods__["selected_thread"] = SetSelectedThread + if _newclass: selected_thread = property(GetSelectedThread, SetSelectedThread, doc='''A read/write property that gets/sets the currently selected thread in this process. The getter returns a lldb.SBThread object and the setter takes an lldb.SBThread object.''') + + __swig_getmethods__["state"] = GetState + if _newclass: state = property(GetState, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eState") that represents the current state of this process (running, stopped, exited, etc.).''') + + __swig_getmethods__["exit_state"] = GetExitStatus + if _newclass: exit_state = property(GetExitStatus, None, doc='''A read only property that returns an exit status as an integer of this process when the process state is lldb.eStateExited.''') + + __swig_getmethods__["exit_description"] = GetExitDescription + if _newclass: exit_description = property(GetExitDescription, None, doc='''A read only property that returns an exit description as a string of this process when the process state is lldb.eStateExited.''') + + __swig_getmethods__["broadcaster"] = GetBroadcaster + if _newclass: broadcaster = property(GetBroadcaster, None, doc='''A read only property that an lldb object that represents the broadcaster (lldb.SBBroadcaster) for this process.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBQueue.i b/scripts/interface/SBQueue.i new file mode 100644 index 0000000000000..52724032a876b --- /dev/null +++ b/scripts/interface/SBQueue.i @@ -0,0 +1,75 @@ +//===-- SWIG Interface for SBQueue.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBQueue +{ +public: + SBQueue (); + + SBQueue (const lldb::QueueSP& queue_sp); + + ~SBQueue(); + + bool + IsValid() const; + + void + Clear (); + + lldb::SBProcess + GetProcess (); + + %feature("autodoc", " + Returns an lldb::queue_id_t type unique identifier number for this + queue that will not be used by any other queue during this process' + execution. These ID numbers often start at 1 with the first + system-created queues and increment from there. + ") + GetQueueID; + + lldb::queue_id_t + GetQueueID () const; + + const char * + GetName () const; + + %feature("autodoc", " + Returns an lldb::QueueKind enumerated value (e.g. eQueueKindUnknown, + eQueueKindSerial, eQueueKindConcurrent) describing the type of this + queue. + ") + GetKind(); + + lldb::QueueKind + GetKind(); + + uint32_t + GetIndexID () const; + + uint32_t + GetNumThreads (); + + lldb::SBThread + GetThreadAtIndex (uint32_t); + + uint32_t + GetNumPendingItems (); + + lldb::SBQueueItem + GetPendingItemAtIndex (uint32_t); + + uint32_t + GetNumRunningItems (); + +}; + +} // namespace lldb + diff --git a/scripts/interface/SBQueueItem.i b/scripts/interface/SBQueueItem.i new file mode 100644 index 0000000000000..ffa24150b678b --- /dev/null +++ b/scripts/interface/SBQueueItem.i @@ -0,0 +1,46 @@ +//===-- SWIG Interface for SBQueueItem.h ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBQueueItem +{ +public: + SBQueueItem (); + + SBQueueItem (const lldb::QueueItemSP& queue_item_sp); + + ~SBQueueItem(); + + bool + IsValid() const; + + void + Clear (); + + lldb::QueueItemKind + GetKind () const; + + void + SetKind (lldb::QueueItemKind kind); + + lldb::SBAddress + GetAddress () const; + + void + SetAddress (lldb::SBAddress addr); + + void + SetQueueItem (const lldb::QueueItemSP& queue_item_sp); + + lldb::SBThread + GetExtendedBacktraceThread (const char *type); +}; + +} // namespace lldb diff --git a/scripts/interface/SBSection.i b/scripts/interface/SBSection.i new file mode 100644 index 0000000000000..c94161e412b09 --- /dev/null +++ b/scripts/interface/SBSection.i @@ -0,0 +1,154 @@ +//===-- SWIG Interface for SBSection ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents an executable image section. + +SBSection supports iteration through its subsection, represented as SBSection +as well. For example, + + for sec in exe_module: + if sec.GetName() == '__TEXT': + print sec + break + print INDENT + 'Number of subsections: %d' % sec.GetNumSubSections() + for subsec in sec: + print INDENT + repr(subsec) + +produces: + +[0x0000000100000000-0x0000000100002000) a.out.__TEXT + Number of subsections: 6 + [0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text + [0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs + [0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper + [0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring + [0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info + [0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame + +See also SBModule." +) SBSection; + +class SBSection +{ +public: + + SBSection (); + + SBSection (const lldb::SBSection &rhs); + + ~SBSection (); + + bool + IsValid () const; + + const char * + GetName (); + + lldb::SBSection + GetParent(); + + lldb::SBSection + FindSubSection (const char *sect_name); + + size_t + GetNumSubSections (); + + lldb::SBSection + GetSubSectionAtIndex (size_t idx); + + lldb::addr_t + GetFileAddress (); + + lldb::addr_t + GetLoadAddress (lldb::SBTarget &target); + + lldb::addr_t + GetByteSize (); + + uint64_t + GetFileOffset (); + + uint64_t + GetFileByteSize (); + + lldb::SBData + GetSectionData (); + + lldb::SBData + GetSectionData (uint64_t offset, + uint64_t size); + + SectionType + GetSectionType (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Return the size of a target's byte represented by this section + /// in numbers of host bytes. Note that certain architectures have + /// varying minimum addressable unit (i.e. byte) size for their + /// CODE or DATA buses. + /// + /// @return + /// The number of host (8-bit) bytes needed to hold a target byte + //------------------------------------------------------------------ + ") GetTargetByteSize; + uint32_t + GetTargetByteSize (); + + bool + GetDescription (lldb::SBStream &description); + + bool + operator == (const lldb::SBSection &rhs); + + bool + operator != (const lldb::SBSection &rhs); + + %pythoncode %{ + def get_addr(self): + return SBAddress(self, 0) + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name of this section as a string.''') + + __swig_getmethods__["addr"] = get_addr + if _newclass: addr = property(get_addr, None, doc='''A read only property that returns an lldb object that represents the start address (lldb.SBAddress) for this section.''') + + __swig_getmethods__["file_addr"] = GetFileAddress + if _newclass: file_addr = property(GetFileAddress, None, doc='''A read only property that returns an integer that represents the starting "file" address for this section, or the address of the section in the object file in which it is defined.''') + + __swig_getmethods__["size"] = GetByteSize + if _newclass: size = property(GetByteSize, None, doc='''A read only property that returns the size in bytes of this section as an integer.''') + + __swig_getmethods__["file_offset"] = GetFileOffset + if _newclass: file_offset = property(GetFileOffset, None, doc='''A read only property that returns the file offset in bytes of this section as an integer.''') + + __swig_getmethods__["file_size"] = GetFileByteSize + if _newclass: file_size = property(GetFileByteSize, None, doc='''A read only property that returns the file size in bytes of this section as an integer.''') + + __swig_getmethods__["data"] = GetSectionData + if _newclass: data = property(GetSectionData, None, doc='''A read only property that returns an lldb object that represents the bytes for this section (lldb.SBData) for this section.''') + + __swig_getmethods__["type"] = GetSectionType + if _newclass: type = property(GetSectionType, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eSectionType") that represents the type of this section (code, data, etc.).''') + + __swig_getmethods__["target_byte_size"] = GetTargetByteSize + if _newclass: target_byte_size = property(GetTargetByteSize, None, doc='''A read only property that returns the size of a target byte represented by this section as a number of host bytes.''') + + %} + +private: + + std::unique_ptr<lldb_private::SectionImpl> m_opaque_ap; +}; + +} // namespace lldb diff --git a/scripts/interface/SBSourceManager.i b/scripts/interface/SBSourceManager.i new file mode 100644 index 0000000000000..09cd449149d9f --- /dev/null +++ b/scripts/interface/SBSourceManager.i @@ -0,0 +1,54 @@ +//===-- SWIG Interface for SBSourceManager ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a central authority for displaying source code. + +For example (from test/source-manager/TestSourceManager.py), + + # Create the filespec for 'main.c'. + filespec = lldb.SBFileSpec('main.c', False) + source_mgr = self.dbg.GetSourceManager() + # Use a string stream as the destination. + stream = lldb.SBStream() + source_mgr.DisplaySourceLinesWithLineNumbers(filespec, + self.line, + 2, # context before + 2, # context after + '=>', # prefix for current line + stream) + + # 2 + # 3 int main(int argc, char const *argv[]) { + # => 4 printf('Hello world.\\n'); // Set break point at this line. + # 5 return 0; + # 6 } + self.expect(stream.GetData(), 'Source code displayed correctly', + exe=False, + patterns = ['=> %d.*Hello world' % self.line]) +") SBSourceManager; +class SBSourceManager +{ +public: + SBSourceManager (const lldb::SBSourceManager &rhs); + + ~SBSourceManager(); + + size_t + DisplaySourceLinesWithLineNumbers (const lldb::SBFileSpec &file, + uint32_t line, + uint32_t context_before, + uint32_t context_after, + const char* current_line_cstr, + lldb::SBStream &s); +}; + +} // namespace lldb diff --git a/scripts/interface/SBStream.i b/scripts/interface/SBStream.i new file mode 100644 index 0000000000000..f634def72b164 --- /dev/null +++ b/scripts/interface/SBStream.i @@ -0,0 +1,100 @@ +//===-- SWIG Interface for SBStream -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +namespace lldb { + +%feature("docstring", +"Represents a destination for streaming data output to. By default, a string +stream is created. + +For example (from test/source-manager/TestSourceManager.py), + + # Create the filespec for 'main.c'. + filespec = lldb.SBFileSpec('main.c', False) + source_mgr = self.dbg.GetSourceManager() + # Use a string stream as the destination. + stream = lldb.SBStream() + source_mgr.DisplaySourceLinesWithLineNumbers(filespec, + self.line, + 2, # context before + 2, # context after + '=>', # prefix for current line + stream) + + # 2 + # 3 int main(int argc, char const *argv[]) { + # => 4 printf('Hello world.\\n'); // Set break point at this line. + # 5 return 0; + # 6 } + self.expect(stream.GetData(), 'Source code displayed correctly', + exe=False, + patterns = ['=> %d.*Hello world' % self.line]) +") SBStream; +class SBStream +{ +public: + + SBStream (); + + ~SBStream (); + + bool + IsValid() const; + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// If this stream is not redirected to a file, it will maintain a local + /// cache for the stream data which can be accessed using this accessor. + //-------------------------------------------------------------------------- + ") GetData; + const char * + GetData (); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// If this stream is not redirected to a file, it will maintain a local + /// cache for the stream output whose length can be accessed using this + /// accessor. + //-------------------------------------------------------------------------- + ") GetSize; + size_t + GetSize(); + + // wrapping the variadic Printf() with a plain Print() + // because it is hard to support varargs in SWIG bridgings + %extend { + void Print (const char* str) + { + self->Printf("%s", str); + } + } + + void + RedirectToFile (const char *path, bool append); + + void + RedirectToFileHandle (FILE *fh, bool transfer_fh_ownership); + + void + RedirectToFileDescriptor (int fd, bool transfer_fh_ownership); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// If the stream is redirected to a file, forget about the file and if + /// ownership of the file was transferred to this object, close the file. + /// If the stream is backed by a local cache, clear this cache. + //-------------------------------------------------------------------------- + ") Clear; + void + Clear (); +}; + +} // namespace lldb diff --git a/scripts/interface/SBStringList.i b/scripts/interface/SBStringList.i new file mode 100644 index 0000000000000..901aa88b183a4 --- /dev/null +++ b/scripts/interface/SBStringList.i @@ -0,0 +1,44 @@ +//===-- SWIG Interface for SBStringList -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBStringList +{ +public: + + SBStringList (); + + SBStringList (const lldb::SBStringList &rhs); + + ~SBStringList (); + + bool + IsValid() const; + + void + AppendString (const char *str); + + void + AppendList (const char **strv, int strc); + + void + AppendList (const lldb::SBStringList &strings); + + uint32_t + GetSize () const; + + const char * + GetStringAtIndex (size_t idx); + + void + Clear (); +}; + +} // namespace lldb diff --git a/scripts/interface/SBSymbol.i b/scripts/interface/SBSymbol.i new file mode 100644 index 0000000000000..b6717055e486a --- /dev/null +++ b/scripts/interface/SBSymbol.i @@ -0,0 +1,110 @@ +//===-- SWIG Interface for SBSymbol -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents the symbol possibly associated with a stack frame. +SBModule contains SBSymbol(s). SBSymbol can also be retrived from SBFrame. + +See also SBModule and SBFrame." +) SBSymbol; +class SBSymbol +{ +public: + + SBSymbol (); + + ~SBSymbol (); + + SBSymbol (const lldb::SBSymbol &rhs); + + bool + IsValid () const; + + + const char * + GetName() const; + + const char * + GetDisplayName() const; + + const char * + GetMangledName () const; + + lldb::SBInstructionList + GetInstructions (lldb::SBTarget target); + + lldb::SBInstructionList + GetInstructions (lldb::SBTarget target, const char *flavor_string); + + SBAddress + GetStartAddress (); + + SBAddress + GetEndAddress (); + + uint32_t + GetPrologueByteSize (); + + SymbolType + GetType (); + + bool + GetDescription (lldb::SBStream &description); + + bool + IsExternal(); + + bool + IsSynthetic(); + + bool + operator == (const lldb::SBSymbol &rhs) const; + + bool + operator != (const lldb::SBSymbol &rhs) const; + + %pythoncode %{ + def get_instructions_from_current_target (self): + return self.GetInstructions (target) + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name for this symbol as a string.''') + + __swig_getmethods__["mangled"] = GetMangledName + if _newclass: mangled = property(GetMangledName, None, doc='''A read only property that returns the mangled (linkage) name for this symbol as a string.''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eSymbolType") that represents the type of this symbol.''') + + __swig_getmethods__["addr"] = GetStartAddress + if _newclass: addr = property(GetStartAddress, None, doc='''A read only property that returns an lldb object that represents the start address (lldb.SBAddress) for this symbol.''') + + __swig_getmethods__["end_addr"] = GetEndAddress + if _newclass: end_addr = property(GetEndAddress, None, doc='''A read only property that returns an lldb object that represents the end address (lldb.SBAddress) for this symbol.''') + + __swig_getmethods__["prologue_size"] = GetPrologueByteSize + if _newclass: prologue_size = property(GetPrologueByteSize, None, doc='''A read only property that returns the size in bytes of the prologue instructions as an unsigned integer.''') + + __swig_getmethods__["instructions"] = get_instructions_from_current_target + if _newclass: instructions = property(get_instructions_from_current_target, None, doc='''A read only property that returns an lldb object that represents the instructions (lldb.SBInstructionList) for this symbol.''') + + __swig_getmethods__["external"] = IsExternal + if _newclass: external = property(IsExternal, None, doc='''A read only property that returns a boolean value that indicates if this symbol is externally visiable (exported) from the module that contains it.''') + + __swig_getmethods__["synthetic"] = IsSynthetic + if _newclass: synthetic = property(IsSynthetic, None, doc='''A read only property that returns a boolean value that indicates if this symbol was synthetically created from information in module that contains it.''') + + + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBSymbolContext.i b/scripts/interface/SBSymbolContext.i new file mode 100644 index 0000000000000..fa405842d6e53 --- /dev/null +++ b/scripts/interface/SBSymbolContext.i @@ -0,0 +1,112 @@ +//===-- SWIG Interface for SBSymbolContext ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"A context object that provides access to core debugger entities. + +Manay debugger functions require a context when doing lookups. This class +provides a common structure that can be used as the result of a query that +can contain a single result. + +For example, + + exe = os.path.join(os.getcwd(), 'a.out') + + # Create a target for the debugger. + target = self.dbg.CreateTarget(exe) + + # Now create a breakpoint on main.c by name 'c'. + breakpoint = target.BreakpointCreateByName('c', 'a.out') + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple(None, None, os.getcwd()) + + # The inferior should stop on 'c'. + from lldbutil import get_stopped_thread + thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) + frame0 = thread.GetFrameAtIndex(0) + + # Now get the SBSymbolContext from this frame. We want everything. :-) + context = frame0.GetSymbolContext(lldb.eSymbolContextEverything) + + # Get the module. + module = context.GetModule() + ... + + # And the compile unit associated with the frame. + compileUnit = context.GetCompileUnit() + ... +" +) SBSymbolContext; +class SBSymbolContext +{ +public: + SBSymbolContext (); + + SBSymbolContext (const lldb::SBSymbolContext& rhs); + + ~SBSymbolContext (); + + bool + IsValid () const; + + lldb::SBModule GetModule (); + lldb::SBCompileUnit GetCompileUnit (); + lldb::SBFunction GetFunction (); + lldb::SBBlock GetBlock (); + lldb::SBLineEntry GetLineEntry (); + lldb::SBSymbol GetSymbol (); + + void SetModule (lldb::SBModule module); + void SetCompileUnit (lldb::SBCompileUnit compile_unit); + void SetFunction (lldb::SBFunction function); + void SetBlock (lldb::SBBlock block); + void SetLineEntry (lldb::SBLineEntry line_entry); + void SetSymbol (lldb::SBSymbol symbol); + + lldb::SBSymbolContext + GetParentOfInlinedScope (const lldb::SBAddress &curr_frame_pc, + lldb::SBAddress &parent_frame_addr) const; + + + bool + GetDescription (lldb::SBStream &description); + + + %pythoncode %{ + __swig_getmethods__["module"] = GetModule + __swig_setmethods__["module"] = SetModule + if _newclass: module = property(GetModule, SetModule, doc='''A read/write property that allows the getting/setting of the module (lldb.SBModule) in this symbol context.''') + + __swig_getmethods__["compile_unit"] = GetCompileUnit + __swig_setmethods__["compile_unit"] = SetCompileUnit + if _newclass: compile_unit = property(GetCompileUnit, SetCompileUnit, doc='''A read/write property that allows the getting/setting of the compile unit (lldb.SBCompileUnit) in this symbol context.''') + + __swig_getmethods__["function"] = GetFunction + __swig_setmethods__["function"] = SetFunction + if _newclass: function = property(GetFunction, SetFunction, doc='''A read/write property that allows the getting/setting of the function (lldb.SBFunction) in this symbol context.''') + + __swig_getmethods__["block"] = GetBlock + __swig_setmethods__["block"] = SetBlock + if _newclass: block = property(GetBlock, SetBlock, doc='''A read/write property that allows the getting/setting of the block (lldb.SBBlock) in this symbol context.''') + + __swig_getmethods__["symbol"] = GetSymbol + __swig_setmethods__["symbol"] = SetSymbol + if _newclass: symbol = property(GetSymbol, SetSymbol, doc='''A read/write property that allows the getting/setting of the symbol (lldb.SBSymbol) in this symbol context.''') + + __swig_getmethods__["line_entry"] = GetLineEntry + __swig_setmethods__["line_entry"] = SetLineEntry + if _newclass: line_entry = property(GetLineEntry, SetLineEntry, doc='''A read/write property that allows the getting/setting of the line entry (lldb.SBLineEntry) in this symbol context.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBSymbolContextList.i b/scripts/interface/SBSymbolContextList.i new file mode 100644 index 0000000000000..25e889499c836 --- /dev/null +++ b/scripts/interface/SBSymbolContextList.i @@ -0,0 +1,140 @@ +//===-- SWIG Interface for SBSymbolContextList ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a list of symbol context object. See also SBSymbolContext. + +For example (from test/python_api/target/TestTargetAPI.py), + + def find_functions(self, exe_name): + '''Exercise SBTaget.FindFunctions() API.''' + exe = os.path.join(os.getcwd(), exe_name) + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + list = lldb.SBSymbolContextList() + num = target.FindFunctions('c', lldb.eFunctionNameTypeAuto, False, list) + self.assertTrue(num == 1 and list.GetSize() == 1) + + for sc in list: + self.assertTrue(sc.GetModule().GetFileSpec().GetFilename() == exe_name) + self.assertTrue(sc.GetSymbol().GetName() == 'c') +") SBSymbolContextList; +class SBSymbolContextList +{ +public: + SBSymbolContextList (); + + SBSymbolContextList (const lldb::SBSymbolContextList& rhs); + + ~SBSymbolContextList (); + + bool + IsValid () const; + + uint32_t + GetSize() const; + + SBSymbolContext + GetContextAtIndex (uint32_t idx); + + void + Append (lldb::SBSymbolContext &sc); + + void + Append (lldb::SBSymbolContextList &sc_list); + + bool + GetDescription (lldb::SBStream &description); + + void + Clear(); + + %pythoncode %{ + def __len__(self): + return int(self.GetSize()) + + def __getitem__(self, key): + count = len(self) + if type(key) is int: + if key < count: + return self.GetContextAtIndex(key) + else: + raise IndexError + raise TypeError + + def get_module_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).module + if obj: + a.append(obj) + return a + + def get_compile_unit_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).compile_unit + if obj: + a.append(obj) + return a + def get_function_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).function + if obj: + a.append(obj) + return a + def get_block_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).block + if obj: + a.append(obj) + return a + def get_symbol_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).symbol + if obj: + a.append(obj) + return a + def get_line_entry_array(self): + a = [] + for i in range(len(self)): + obj = self.GetContextAtIndex(i).line_entry + if obj: + a.append(obj) + return a + __swig_getmethods__["modules"] = get_module_array + if _newclass: modules = property(get_module_array, None, doc='''Returns a list() of lldb.SBModule objects, one for each module in each SBSymbolContext object in this list.''') + + __swig_getmethods__["compile_units"] = get_compile_unit_array + if _newclass: compile_units = property(get_compile_unit_array, None, doc='''Returns a list() of lldb.SBCompileUnit objects, one for each compile unit in each SBSymbolContext object in this list.''') + + __swig_getmethods__["functions"] = get_function_array + if _newclass: functions = property(get_function_array, None, doc='''Returns a list() of lldb.SBFunction objects, one for each function in each SBSymbolContext object in this list.''') + + __swig_getmethods__["blocks"] = get_block_array + if _newclass: blocks = property(get_block_array, None, doc='''Returns a list() of lldb.SBBlock objects, one for each block in each SBSymbolContext object in this list.''') + + __swig_getmethods__["line_entries"] = get_line_entry_array + if _newclass: line_entries = property(get_line_entry_array, None, doc='''Returns a list() of lldb.SBLineEntry objects, one for each line entry in each SBSymbolContext object in this list.''') + + __swig_getmethods__["symbols"] = get_symbol_array + if _newclass: symbols = property(get_symbol_array, None, doc='''Returns a list() of lldb.SBSymbol objects, one for each symbol in each SBSymbolContext object in this list.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBTarget.i b/scripts/interface/SBTarget.i new file mode 100644 index 0000000000000..74e470d4b3fa1 --- /dev/null +++ b/scripts/interface/SBTarget.i @@ -0,0 +1,899 @@ +//===-- SWIG Interface for SBTarget -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + +%feature("docstring", +"Represents the target program running under the debugger. + +SBTarget supports module, breakpoint, and watchpoint iterations. For example, + + for m in target.module_iter(): + print m + +produces: + +(x86_64) /Volumes/data/lldb/svn/trunk/test/python_api/lldbutil/iter/a.out +(x86_64) /usr/lib/dyld +(x86_64) /usr/lib/libstdc++.6.dylib +(x86_64) /usr/lib/libSystem.B.dylib +(x86_64) /usr/lib/system/libmathCommon.A.dylib +(x86_64) /usr/lib/libSystem.B.dylib(__commpage) + +and, + + for b in target.breakpoint_iter(): + print b + +produces: + +SBBreakpoint: id = 1, file ='main.cpp', line = 66, locations = 1 +SBBreakpoint: id = 2, file ='main.cpp', line = 85, locations = 1 + +and, + + for wp_loc in target.watchpoint_iter(): + print wp_loc + +produces: + +Watchpoint 1: addr = 0x1034ca048 size = 4 state = enabled type = rw + declare @ '/Volumes/data/lldb/svn/trunk/test/python_api/watchpoint/main.c:12' + hw_index = 0 hit_count = 2 ignore_count = 0" +) SBTarget; +class SBTarget +{ +public: + //------------------------------------------------------------------ + // Broadcaster bits. + //------------------------------------------------------------------ + enum + { + eBroadcastBitBreakpointChanged = (1 << 0), + eBroadcastBitModulesLoaded = (1 << 1), + eBroadcastBitModulesUnloaded = (1 << 2), + eBroadcastBitWatchpointChanged = (1 << 3), + eBroadcastBitSymbolsLoaded = (1 << 4) + }; + + //------------------------------------------------------------------ + // Constructors + //------------------------------------------------------------------ + SBTarget (); + + SBTarget (const lldb::SBTarget& rhs); + + //------------------------------------------------------------------ + // Destructor + //------------------------------------------------------------------ + ~SBTarget(); + + static const char * + GetBroadcasterClassName (); + + bool + IsValid() const; + + static bool + EventIsTargetEvent (const lldb::SBEvent &event); + + static lldb::SBTarget + GetTargetFromEvent (const lldb::SBEvent &event); + + static uint32_t + GetNumModulesFromEvent (const lldb::SBEvent &event); + + static lldb::SBModule + GetModuleAtIndexFromEvent (const uint32_t idx, const lldb::SBEvent &event); + + lldb::SBProcess + GetProcess (); + + + %feature("docstring", " + //------------------------------------------------------------------ + /// Return the platform object associated with the target. + /// + /// After return, the platform object should be checked for + /// validity. + /// + /// @return + /// A platform object. + //------------------------------------------------------------------ + ") GetPlatform; + lldb::SBPlatform + GetPlatform (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Install any binaries that need to be installed. + /// + /// This function does nothing when debugging on the host system. + /// When connected to remote platforms, the target's main executable + /// and any modules that have their install path set will be + /// installed on the remote platform. If the main executable doesn't + /// have an install location set, it will be installed in the remote + /// platform's working directory. + /// + /// @return + /// An error describing anything that went wrong during + /// installation. + //------------------------------------------------------------------ + ") Install; + lldb::SBError + Install(); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Launch a new process. + /// + /// Launch a new process by spawning a new process using the + /// target object's executable module's file as the file to launch. + /// Arguments are given in \a argv, and the environment variables + /// are in \a envp. Standard input and output files can be + /// optionally re-directed to \a stdin_path, \a stdout_path, and + /// \a stderr_path. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] argv + /// The argument array. + /// + /// @param[in] envp + /// The environment array. + /// + /// @param[in] launch_flags + /// Flags to modify the launch (@see lldb::LaunchFlags) + /// + /// @param[in] stdin_path + /// The path to use when re-directing the STDIN of the new + /// process. If all stdXX_path arguments are NULL, a pseudo + /// terminal will be used. + /// + /// @param[in] stdout_path + /// The path to use when re-directing the STDOUT of the new + /// process. If all stdXX_path arguments are NULL, a pseudo + /// terminal will be used. + /// + /// @param[in] stderr_path + /// The path to use when re-directing the STDERR of the new + /// process. If all stdXX_path arguments are NULL, a pseudo + /// terminal will be used. + /// + /// @param[in] working_directory + /// The working directory to have the child process run in + /// + /// @param[in] launch_flags + /// Some launch options specified by logical OR'ing + /// lldb::LaunchFlags enumeration values together. + /// + /// @param[in] stop_at_endtry + /// If false do not stop the inferior at the entry point. + /// + /// @param[out] + /// An error object. Contains the reason if there is some failure. + /// + /// @return + /// A process object for the newly created process. + //------------------------------------------------------------------ + + For example, + + process = target.Launch(self.dbg.GetListener(), None, None, + None, '/tmp/stdout.txt', None, + None, 0, False, error) + + launches a new process by passing nothing for both the args and the envs + and redirect the standard output of the inferior to the /tmp/stdout.txt + file. It does not specify a working directory so that the debug server + will use its idea of what the current working directory is for the + inferior. Also, we ask the debugger not to stop the inferior at the + entry point. If no breakpoint is specified for the inferior, it should + run to completion if no user interaction is required. + ") Launch; + lldb::SBProcess + Launch (SBListener &listener, + char const **argv, + char const **envp, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + const char *working_directory, + uint32_t launch_flags, // See LaunchFlags + bool stop_at_entry, + lldb::SBError& error); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Launch a new process with sensible defaults. + /// + /// @param[in] argv + /// The argument array. + /// + /// @param[in] envp + /// The environment array. + /// + /// @param[in] working_directory + /// The working directory to have the child process run in + /// + /// Default: listener + /// Set to the target's debugger (SBTarget::GetDebugger()) + /// + /// Default: launch_flags + /// Empty launch flags + /// + /// Default: stdin_path + /// Default: stdout_path + /// Default: stderr_path + /// A pseudo terminal will be used. + /// + /// @return + /// A process object for the newly created process. + //------------------------------------------------------------------ + + For example, + + process = target.LaunchSimple(['X', 'Y', 'Z'], None, os.getcwd()) + + launches a new process by passing 'X', 'Y', 'Z' as the args to the + executable. + ") LaunchSimple; + lldb::SBProcess + LaunchSimple (const char **argv, + const char **envp, + const char *working_directory); + + lldb::SBProcess + Launch (lldb::SBLaunchInfo &launch_info, lldb::SBError& error); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Load a core file + /// + /// @param[in] core_file + /// File path of the core dump. + /// + /// @return + /// A process object for the newly created core file. + //------------------------------------------------------------------ + + For example, + + process = target.LoadCore('./a.out.core') + + loads a new core file and returns the process object. + ") LoadCore; + lldb::SBProcess + LoadCore(const char *core_file); + + lldb::SBProcess + Attach (lldb::SBAttachInfo &attach_info, lldb::SBError& error); + + + %feature("docstring", " + //------------------------------------------------------------------ + /// Attach to process with pid. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] pid + /// The process ID to attach to. + /// + /// @param[out] + /// An error explaining what went wrong if attach fails. + /// + /// @return + /// A process object for the attached process. + //------------------------------------------------------------------ + ") AttachToProcessWithID; + lldb::SBProcess + AttachToProcessWithID (SBListener &listener, + lldb::pid_t pid, + lldb::SBError& error); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Attach to process with name. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] name + /// Basename of process to attach to. + /// + /// @param[in] wait_for + /// If true wait for a new instance of 'name' to be launched. + /// + /// @param[out] + /// An error explaining what went wrong if attach fails. + /// + /// @return + /// A process object for the attached process. + //------------------------------------------------------------------ + ") AttachToProcessWithName; + lldb::SBProcess + AttachToProcessWithName (SBListener &listener, + const char *name, + bool wait_for, + lldb::SBError& error); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Connect to a remote debug server with url. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] url + /// The url to connect to, e.g., 'connect://localhost:12345'. + /// + /// @param[in] plugin_name + /// The plugin name to be used; can be NULL. + /// + /// @param[out] + /// An error explaining what went wrong if the connect fails. + /// + /// @return + /// A process object for the connected process. + //------------------------------------------------------------------ + ") ConnectRemote; + lldb::SBProcess + ConnectRemote (SBListener &listener, + const char *url, + const char *plugin_name, + SBError& error); + + lldb::SBFileSpec + GetExecutable (); + + bool + AddModule (lldb::SBModule &module); + + lldb::SBModule + AddModule (const char *path, + const char *triple, + const char *uuid); + + lldb::SBModule + AddModule (const char *path, + const char *triple, + const char *uuid_cstr, + const char *symfile); + + lldb::SBModule + AddModule (const SBModuleSpec &module_spec); + + uint32_t + GetNumModules () const; + + lldb::SBModule + GetModuleAtIndex (uint32_t idx); + + bool + RemoveModule (lldb::SBModule module); + + lldb::SBDebugger + GetDebugger() const; + + lldb::SBModule + FindModule (const lldb::SBFileSpec &file_spec); + + lldb::ByteOrder + GetByteOrder (); + + uint32_t + GetAddressByteSize(); + + const char * + GetTriple (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Architecture data byte width accessor + /// + /// @return + /// The size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's data bus + //------------------------------------------------------------------ + ") GetDataByteSize; + uint32_t + GetDataByteSize (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Architecture code byte width accessor + /// + /// @return + /// The size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's code bus + //------------------------------------------------------------------ + ") GetCodeByteSize; + uint32_t + GetCodeByteSize (); + + lldb::SBError + SetSectionLoadAddress (lldb::SBSection section, + lldb::addr_t section_base_addr); + + lldb::SBError + ClearSectionLoadAddress (lldb::SBSection section); + + lldb::SBError + SetModuleLoadAddress (lldb::SBModule module, + int64_t sections_offset); + + lldb::SBError + ClearModuleLoadAddress (lldb::SBModule module); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// @param[in] name + /// The name of the function we are looking for. + /// + /// @param[in] name_type_mask + /// A logical OR of one or more FunctionNameType enum bits that + /// indicate what kind of names should be used when doing the + /// lookup. Bits include fully qualified names, base names, + /// C++ methods, or ObjC selectors. + /// See FunctionNameType for more details. + /// + /// @return + /// A lldb::SBSymbolContextList that gets filled in with all of + /// the symbol contexts for all the matches. + //------------------------------------------------------------------ + ") FindFunctions; + lldb::SBSymbolContextList + FindFunctions (const char *name, + uint32_t name_type_mask = lldb::eFunctionNameTypeAny); + + lldb::SBType + FindFirstType (const char* type); + + lldb::SBTypeList + FindTypes (const char* type); + + lldb::SBType + GetBasicType(lldb::BasicType type); + + lldb::SBSourceManager + GetSourceManager (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find global and static variables by name. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + ") FindGlobalVariables; + lldb::SBValueList + FindGlobalVariables (const char *name, + uint32_t max_matches); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Find the first global (or static) variable by name. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @return + /// An SBValue that gets filled in with the found variable (if any). + //------------------------------------------------------------------ + ") FindFirstGlobalVariable; + lldb::SBValue + FindFirstGlobalVariable (const char* name); + + + lldb::SBValueList + FindGlobalVariables(const char *name, + uint32_t max_matches, + MatchType matchtype); + + lldb::SBSymbolContextList + FindGlobalFunctions(const char *name, + uint32_t max_matches, + MatchType matchtype); + + void + Clear (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Resolve a current file address into a section offset address. + /// + /// @param[in] file_addr + /// + /// @return + /// An SBAddress which will be valid if... + //------------------------------------------------------------------ + ") ResolveFileAddress; + lldb::SBAddress + ResolveFileAddress (lldb::addr_t file_addr); + + lldb::SBAddress + ResolveLoadAddress (lldb::addr_t vm_addr); + + lldb::SBAddress + ResolvePastLoadAddress (uint32_t stop_id, lldb::addr_t vm_addr); + + SBSymbolContext + ResolveSymbolContextForAddress (const SBAddress& addr, + uint32_t resolve_scope); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Read target memory. If a target process is running then memory + /// is read from here. Otherwise the memory is read from the object + /// files. For a target whose bytes are sized as a multiple of host + /// bytes, the data read back will preserve the target's byte order. + /// + /// @param[in] addr + /// A target address to read from. + /// + /// @param[out] buf + /// The buffer to read memory into. + /// + /// @param[in] size + /// The maximum number of host bytes to read in the buffer passed + /// into this call + /// + /// @param[out] error + /// Error information is written here if the memory read fails. + /// + /// @return + /// The amount of data read in host bytes. + //------------------------------------------------------------------ + ") ReadMemory; + size_t + ReadMemory (const SBAddress addr, void *buf, size_t size, lldb::SBError &error); + + lldb::SBBreakpoint + BreakpointCreateByLocation (const char *file, uint32_t line); + + lldb::SBBreakpoint + BreakpointCreateByLocation (const lldb::SBFileSpec &file_spec, uint32_t line); + + lldb::SBBreakpoint + BreakpointCreateByName (const char *symbol_name, const char *module_name = NULL); + + lldb::SBBreakpoint + BreakpointCreateByName (const char *symbol_name, + uint32_t func_name_type, // Logical OR one or more FunctionNameType enum bits + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateByName (const char *symbol_name, + uint32_t func_name_type, // Logical OR one or more FunctionNameType enum bits + lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateByNames (const char *symbol_name[], + uint32_t num_names, + uint32_t name_type_mask, // Logical OR one or more FunctionNameType enum bits + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateByNames (const char *symbol_name[], + uint32_t num_names, + uint32_t name_type_mask, // Logical OR one or more FunctionNameType enum bits + lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name = NULL); + + lldb::SBBreakpoint + BreakpointCreateByRegex (const char *symbol_name_regex, + lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpec &source_file, const char *module_name = NULL); + + lldb::SBBreakpoint + BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpecList &module_list, const lldb::SBFileSpecList &file_list); + + lldb::SBBreakpoint + BreakpointCreateForException (lldb::LanguageType language, + bool catch_bp, + bool throw_bp); + + lldb::SBBreakpoint + BreakpointCreateByAddress (addr_t address); + + lldb::SBBreakpoint + BreakpointCreateBySBAddress (SBAddress &sb_address); + + uint32_t + GetNumBreakpoints () const; + + lldb::SBBreakpoint + GetBreakpointAtIndex (uint32_t idx) const; + + bool + BreakpointDelete (break_id_t break_id); + + lldb::SBBreakpoint + FindBreakpointByID (break_id_t break_id); + + bool + EnableAllBreakpoints (); + + bool + DisableAllBreakpoints (); + + bool + DeleteAllBreakpoints (); + + uint32_t + GetNumWatchpoints () const; + + lldb::SBWatchpoint + GetWatchpointAtIndex (uint32_t idx) const; + + bool + DeleteWatchpoint (lldb::watch_id_t watch_id); + + lldb::SBWatchpoint + FindWatchpointByID (lldb::watch_id_t watch_id); + + bool + EnableAllWatchpoints (); + + bool + DisableAllWatchpoints (); + + bool + DeleteAllWatchpoints (); + + lldb::SBWatchpoint + WatchAddress (lldb::addr_t addr, + size_t size, + bool read, + bool write, + SBError &error); + + + lldb::SBBroadcaster + GetBroadcaster () const; + + %feature("docstring", " + //------------------------------------------------------------------ + /// Create an SBValue with the given name by treating the memory starting at addr as an entity of type. + /// + /// @param[in] name + /// The name of the resultant SBValue + /// + /// @param[in] addr + /// The address of the start of the memory region to be used. + /// + /// @param[in] type + /// The type to use to interpret the memory starting at addr. + /// + /// @return + /// An SBValue of the given type, may be invalid if there was an error reading + /// the underlying memory. + //------------------------------------------------------------------ + ") CreateValueFromAddress; + lldb::SBValue + CreateValueFromAddress (const char *name, lldb::SBAddress addr, lldb::SBType type); + + lldb::SBValue + CreateValueFromData (const char *name, lldb::SBData data, lldb::SBType type); + + lldb::SBValue + CreateValueFromExpression (const char *name, const char* expr); + + %feature("docstring", " + Disassemble a specified number of instructions starting at an address. + Parameters: + base_addr -- the address to start disassembly from + count -- the number of instructions to disassemble + flavor_string -- may be 'intel' or 'att' on x86 targets to specify that style of disassembly + Returns an SBInstructionList.") + ReadInstructions; + lldb::SBInstructionList + ReadInstructions (lldb::SBAddress base_addr, uint32_t count); + + lldb::SBInstructionList + ReadInstructions (lldb::SBAddress base_addr, uint32_t count, const char *flavor_string); + + %feature("docstring", " + Disassemble the bytes in a buffer and return them in an SBInstructionList. + Parameters: + base_addr -- used for symbolicating the offsets in the byte stream when disassembling + buf -- bytes to be disassembled + size -- (C++) size of the buffer + Returns an SBInstructionList.") + GetInstructions; + lldb::SBInstructionList + GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size); + + %feature("docstring", " + Disassemble the bytes in a buffer and return them in an SBInstructionList, with a supplied flavor. + Parameters: + base_addr -- used for symbolicating the offsets in the byte stream when disassembling + flavor -- may be 'intel' or 'att' on x86 targets to specify that style of disassembly + buf -- bytes to be disassembled + size -- (C++) size of the buffer + Returns an SBInstructionList.") + GetInstructionsWithFlavor; + lldb::SBInstructionList + GetInstructionsWithFlavor (lldb::SBAddress base_addr, const char *flavor_string, const void *buf, size_t size); + + lldb::SBSymbolContextList + FindSymbols (const char *name, lldb::SymbolType type = eSymbolTypeAny); + + bool + GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level); + + lldb::addr_t + GetStackRedZoneSize(); + + lldb::SBLaunchInfo + GetLaunchInfo () const; + + void + SetLaunchInfo (const lldb::SBLaunchInfo &launch_info); + + bool + operator == (const lldb::SBTarget &rhs) const; + + bool + operator != (const lldb::SBTarget &rhs) const; + + lldb::SBValue + EvaluateExpression (const char *expr); + + lldb::SBValue + EvaluateExpression (const char *expr, const lldb::SBExpressionOptions &options); + + %pythoncode %{ + class modules_access(object): + '''A helper object that will lazily hand out lldb.SBModule objects for a target when supplied an index, or by full or partial path.''' + def __init__(self, sbtarget): + self.sbtarget = sbtarget + + def __len__(self): + if self.sbtarget: + return int(self.sbtarget.GetNumModules()) + return 0 + + def __getitem__(self, key): + num_modules = self.sbtarget.GetNumModules() + if type(key) is int: + if key < num_modules: + return self.sbtarget.GetModuleAtIndex(key) + elif type(key) is str: + if key.find('/') == -1: + for idx in range(num_modules): + module = self.sbtarget.GetModuleAtIndex(idx) + if module.file.basename == key: + return module + else: + for idx in range(num_modules): + module = self.sbtarget.GetModuleAtIndex(idx) + if module.file.fullpath == key: + return module + # See if the string is a UUID + try: + the_uuid = uuid.UUID(key) + if the_uuid: + for idx in range(num_modules): + module = self.sbtarget.GetModuleAtIndex(idx) + if module.uuid == the_uuid: + return module + except: + return None + elif type(key) is uuid.UUID: + for idx in range(num_modules): + module = self.sbtarget.GetModuleAtIndex(idx) + if module.uuid == key: + return module + elif type(key) is re.SRE_Pattern: + matching_modules = [] + for idx in range(num_modules): + module = self.sbtarget.GetModuleAtIndex(idx) + re_match = key.search(module.path.fullpath) + if re_match: + matching_modules.append(module) + return matching_modules + else: + print("error: unsupported item type: %s" % type(key)) + return None + + def get_modules_access_object(self): + '''An accessor function that returns a modules_access() object which allows lazy module access from a lldb.SBTarget object.''' + return self.modules_access (self) + + def get_modules_array(self): + '''An accessor function that returns a list() that contains all modules in a lldb.SBTarget object.''' + modules = [] + for idx in range(self.GetNumModules()): + modules.append(self.GetModuleAtIndex(idx)) + return modules + + __swig_getmethods__["modules"] = get_modules_array + if _newclass: modules = property(get_modules_array, None, doc='''A read only property that returns a list() of lldb.SBModule objects contained in this target. This list is a list all modules that the target currently is tracking (the main executable and all dependent shared libraries).''') + + __swig_getmethods__["module"] = get_modules_access_object + if _newclass: module = property(get_modules_access_object, None, doc=r'''A read only property that returns an object that implements python operator overloading with the square brackets().\n target.module[<int>] allows array access to any modules.\n target.module[<str>] allows access to modules by basename, full path, or uuid string value.\n target.module[uuid.UUID()] allows module access by UUID.\n target.module[re] allows module access using a regular expression that matches the module full path.''') + + __swig_getmethods__["process"] = GetProcess + if _newclass: process = property(GetProcess, None, doc='''A read only property that returns an lldb object that represents the process (lldb.SBProcess) that this target owns.''') + + __swig_getmethods__["executable"] = GetExecutable + if _newclass: executable = property(GetExecutable, None, doc='''A read only property that returns an lldb object that represents the main executable module (lldb.SBModule) for this target.''') + + __swig_getmethods__["debugger"] = GetDebugger + if _newclass: debugger = property(GetDebugger, None, doc='''A read only property that returns an lldb object that represents the debugger (lldb.SBDebugger) that owns this target.''') + + __swig_getmethods__["num_breakpoints"] = GetNumBreakpoints + if _newclass: num_breakpoints = property(GetNumBreakpoints, None, doc='''A read only property that returns the number of breakpoints that this target has as an integer.''') + + __swig_getmethods__["num_watchpoints"] = GetNumWatchpoints + if _newclass: num_watchpoints = property(GetNumWatchpoints, None, doc='''A read only property that returns the number of watchpoints that this target has as an integer.''') + + __swig_getmethods__["broadcaster"] = GetBroadcaster + if _newclass: broadcaster = property(GetBroadcaster, None, doc='''A read only property that an lldb object that represents the broadcaster (lldb.SBBroadcaster) for this target.''') + + __swig_getmethods__["byte_order"] = GetByteOrder + if _newclass: byte_order = property(GetByteOrder, None, doc='''A read only property that returns an lldb enumeration value (lldb.eByteOrderLittle, lldb.eByteOrderBig, lldb.eByteOrderInvalid) that represents the byte order for this target.''') + + __swig_getmethods__["addr_size"] = GetAddressByteSize + if _newclass: addr_size = property(GetAddressByteSize, None, doc='''A read only property that returns the size in bytes of an address for this target.''') + + __swig_getmethods__["triple"] = GetTriple + if _newclass: triple = property(GetTriple, None, doc='''A read only property that returns the target triple (arch-vendor-os) for this target as a string.''') + + __swig_getmethods__["data_byte_size"] = GetDataByteSize + if _newclass: data_byte_size = property(GetDataByteSize, None, doc='''A read only property that returns the size in host bytes of a byte in the data address space for this target.''') + + __swig_getmethods__["code_byte_size"] = GetCodeByteSize + if _newclass: code_byte_size = property(GetCodeByteSize, None, doc='''A read only property that returns the size in host bytes of a byte in the code address space for this target.''') + + __swig_getmethods__["platform"] = GetPlatform + if _newclass: platform = property(GetPlatform, None, doc='''A read only property that returns the platform associated with with this target.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBThread.i b/scripts/interface/SBThread.i new file mode 100644 index 0000000000000..f2b27565d4899 --- /dev/null +++ b/scripts/interface/SBThread.i @@ -0,0 +1,408 @@ +//===-- SWIG Interface for SBThread -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a thread of execution. SBProcess contains SBThread(s). + +SBThreads can be referred to by their ID, which maps to the system specific thread +identifier, or by IndexID. The ID may or may not be unique depending on whether the +system reuses its thread identifiers. The IndexID is a monotonically increasing identifier +that will always uniquely reference a particular thread, and when that thread goes +away it will not be reused. + +SBThread supports frame iteration. For example (from test/python_api/ +lldbutil/iter/TestLLDBIterator.py), + + from lldbutil import print_stacktrace + stopped_due_to_breakpoint = False + for thread in process: + if self.TraceOn(): + print_stacktrace(thread) + ID = thread.GetThreadID() + if thread.GetStopReason() == lldb.eStopReasonBreakpoint: + stopped_due_to_breakpoint = True + for frame in thread: + self.assertTrue(frame.GetThread().GetThreadID() == ID) + if self.TraceOn(): + print frame + + self.assertTrue(stopped_due_to_breakpoint) + +See also SBProcess and SBFrame." +) SBThread; +class SBThread +{ +public: + //------------------------------------------------------------------ + // Broadcaster bits. + //------------------------------------------------------------------ + enum + { + eBroadcastBitStackChanged = (1 << 0), + eBroadcastBitThreadSuspended = (1 << 1), + eBroadcastBitThreadResumed = (1 << 2), + eBroadcastBitSelectedFrameChanged = (1 << 3), + eBroadcastBitThreadSelected = (1 << 4) + }; + + + SBThread (); + + SBThread (const lldb::SBThread &thread); + + ~SBThread(); + + static const char * + GetBroadcasterClassName (); + + static bool + EventIsThreadEvent (const SBEvent &event); + + static SBFrame + GetStackFrameFromEvent (const SBEvent &event); + + static SBThread + GetThreadFromEvent (const SBEvent &event); + + bool + IsValid() const; + + void + Clear (); + + lldb::StopReason + GetStopReason(); + + %feature("docstring", " + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + ") GetStopReasonDataCount; + size_t + GetStopReasonDataCount(); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + ") GetStopReasonDataAtIndex; + uint64_t + GetStopReasonDataAtIndex(uint32_t idx); + + %feature("autodoc", " + Collects a thread's stop reason extended information dictionary and prints it + into the SBStream in a JSON format. The format of this JSON dictionary depends + on the stop reason and is currently used only for instrumentation plugins. + ") GetStopReasonExtendedInfoAsJSON; + bool + GetStopReasonExtendedInfoAsJSON (lldb::SBStream &stream); + + %feature("autodoc", " + Pass only an (int)length and expect to get a Python string describing the + stop reason. + ") GetStopDescription; + size_t + GetStopDescription (char *dst, size_t dst_len); + + SBValue + GetStopReturnValue (); + + %feature("autodoc", " + Returns a unique thread identifier (type lldb::tid_t, typically a 64-bit type) + for the current SBThread that will remain constant throughout the thread's + lifetime in this process and will not be reused by another thread during this + process lifetime. On Mac OS X systems, this is a system-wide unique thread + identifier; this identifier is also used by other tools like sample which helps + to associate data from those tools with lldb. See related GetIndexID. + ") + GetThreadID; + lldb::tid_t + GetThreadID () const; + + %feature("autodoc", " + Return the index number for this SBThread. The index number is the same thing + that a user gives as an argument to 'thread select' in the command line lldb. + These numbers start at 1 (for the first thread lldb sees in a debug session) + and increments up throughout the process lifetime. An index number will not be + reused for a different thread later in a process - thread 1 will always be + associated with the same thread. See related GetThreadID. + This method returns a uint32_t index number, takes no arguments. + ") + GetIndexID; + uint32_t + GetIndexID () const; + + const char * + GetName () const; + + %feature("autodoc", " + Return the queue name associated with this thread, if any, as a str. + For example, with a libdispatch (aka Grand Central Dispatch) queue. + ") GetQueueName; + + const char * + GetQueueName() const; + + %feature("autodoc", " + Return the dispatch_queue_id for this thread, if any, as a lldb::queue_id_t. + For example, with a libdispatch (aka Grand Central Dispatch) queue. + ") GetQueueID; + + lldb::queue_id_t + GetQueueID() const; + + %feature("autodoc", " + Takes a path string and a SBStream reference as parameters, returns a bool. + Collects the thread's 'info' dictionary from the remote system, uses the path + argument to descend into the dictionary to an item of interest, and prints + it into the SBStream in a natural format. Return bool is to indicate if + anything was printed into the stream (true) or not (false). + ") GetInfoItemByPathAsString; + + bool + GetInfoItemByPathAsString (const char *path, lldb::SBStream &strm); + + %feature("autodoc", " + Return the SBQueue for this thread. If this thread is not currently associated + with a libdispatch queue, the SBQueue object's IsValid() method will return false. + If this SBThread is actually a HistoryThread, we may be able to provide QueueID + and QueueName, but not provide an SBQueue. Those individual attributes may have + been saved for the HistoryThread without enough information to reconstitute the + entire SBQueue at that time. + This method takes no arguments, returns an SBQueue. + ") GetQueue; + + lldb::SBQueue + GetQueue () const; + + void + StepOver (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void + StepInto (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void + StepInto (const char *target_name, lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void + StepOut (); + + void + StepOutOfFrame (lldb::SBFrame &frame); + + void + StepInstruction(bool step_over); + + SBError + StepOverUntil (lldb::SBFrame &frame, + lldb::SBFileSpec &file_spec, + uint32_t line); + + SBError + StepUsingScriptedThreadPlan (const char *script_class_name); + + SBError + JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line); + + void + RunToAddress (lldb::addr_t addr); + + %feature("autodoc", " + Force a return from the frame passed in (and any frames younger than it) + without executing any more code in those frames. If return_value contains + a valid SBValue, that will be set as the return value from frame. Note, at + present only scalar return values are supported. + ") ReturnFromFrame; + + SBError + ReturnFromFrame (SBFrame &frame, SBValue &return_value); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// LLDB currently supports process centric debugging which means when any + /// thread in a process stops, all other threads are stopped. The Suspend() + /// call here tells our process to suspend a thread and not let it run when + /// the other threads in a process are allowed to run. So when + /// SBProcess::Continue() is called, any threads that aren't suspended will + /// be allowed to run. If any of the SBThread functions for stepping are + /// called (StepOver, StepInto, StepOut, StepInstruction, RunToAddres), the + /// thread will now be allowed to run and these functions will simply return. + /// + /// Eventually we plan to add support for thread centric debugging where + /// each thread is controlled individually and each thread would broadcast + /// its state, but we haven't implemented this yet. + /// + /// Likewise the SBThread::Resume() call will again allow the thread to run + /// when the process is continued. + /// + /// Suspend() and Resume() functions are not currently reference counted, if + /// anyone has the need for them to be reference counted, please let us + /// know. + //-------------------------------------------------------------------------- + ") Suspend; + bool + Suspend(); + + bool + Resume (); + + bool + IsSuspended(); + + bool + IsStopped(); + + uint32_t + GetNumFrames (); + + lldb::SBFrame + GetFrameAtIndex (uint32_t idx); + + lldb::SBFrame + GetSelectedFrame (); + + lldb::SBFrame + SetSelectedFrame (uint32_t frame_idx); + + lldb::SBProcess + GetProcess (); + + bool + GetDescription (lldb::SBStream &description) const; + + bool + GetStatus (lldb::SBStream &status) const; + + bool + operator == (const lldb::SBThread &rhs) const; + + bool + operator != (const lldb::SBThread &rhs) const; + + %feature("autodoc"," + Given an argument of str to specify the type of thread-origin extended + backtrace to retrieve, query whether the origin of this thread is + available. An SBThread is retured; SBThread.IsValid will return true + if an extended backtrace was available. The returned SBThread is not + a part of the SBProcess' thread list and it cannot be manipulated like + normal threads -- you cannot step or resume it, for instance -- it is + intended to used primarily for generating a backtrace. You may request + the returned thread's own thread origin in turn. + ") GetExtendedBacktraceThread; + lldb::SBThread + GetExtendedBacktraceThread (const char *type); + + %feature("autodoc"," + Takes no arguments, returns a uint32_t. + If this SBThread is an ExtendedBacktrace thread, get the IndexID of the + original thread that this ExtendedBacktrace thread represents, if + available. The thread that was running this backtrace in the past may + not have been registered with lldb's thread index (if it was created, + did its work, and was destroyed without lldb ever stopping execution). + In that case, this ExtendedBacktrace thread's IndexID will be returned. + ") GetExtendedBacktraceOriginatingIndexID; + uint32_t + GetExtendedBacktraceOriginatingIndexID(); + + %feature("autodoc"," + Takes no arguments, returns a bool. + lldb may be able to detect that function calls should not be executed + on a given thread at a particular point in time. It is recommended that + this is checked before performing an inferior function call on a given + thread. + ") SafeToCallFunctions; + bool + SafeToCallFunctions (); + + %pythoncode %{ + class frames_access(object): + '''A helper object that will lazily hand out frames for a thread when supplied an index.''' + def __init__(self, sbthread): + self.sbthread = sbthread + + def __len__(self): + if self.sbthread: + return int(self.sbthread.GetNumFrames()) + return 0 + + def __getitem__(self, key): + if type(key) is int and key < self.sbthread.GetNumFrames(): + return self.sbthread.GetFrameAtIndex(key) + return None + + def get_frames_access_object(self): + '''An accessor function that returns a frames_access() object which allows lazy frame access from a lldb.SBThread object.''' + return self.frames_access (self) + + def get_thread_frames(self): + '''An accessor function that returns a list() that contains all frames in a lldb.SBThread object.''' + frames = [] + for frame in self: + frames.append(frame) + return frames + + __swig_getmethods__["id"] = GetThreadID + if _newclass: id = property(GetThreadID, None, doc='''A read only property that returns the thread ID as an integer.''') + + __swig_getmethods__["idx"] = GetIndexID + if _newclass: idx = property(GetIndexID, None, doc='''A read only property that returns the thread index ID as an integer. Thread index ID values start at 1 and increment as threads come and go and can be used to uniquely identify threads.''') + + __swig_getmethods__["return_value"] = GetStopReturnValue + if _newclass: return_value = property(GetStopReturnValue, None, doc='''A read only property that returns an lldb object that represents the return value from the last stop (lldb.SBValue) if we just stopped due to stepping out of a function.''') + + __swig_getmethods__["process"] = GetProcess + if _newclass: process = property(GetProcess, None, doc='''A read only property that returns an lldb object that represents the process (lldb.SBProcess) that owns this thread.''') + + __swig_getmethods__["num_frames"] = GetNumFrames + if _newclass: num_frames = property(GetNumFrames, None, doc='''A read only property that returns the number of stack frames in this thread as an integer.''') + + __swig_getmethods__["frames"] = get_thread_frames + if _newclass: frames = property(get_thread_frames, None, doc='''A read only property that returns a list() of lldb.SBFrame objects for all frames in this thread.''') + + __swig_getmethods__["frame"] = get_frames_access_object + if _newclass: frame = property(get_frames_access_object, None, doc='''A read only property that returns an object that can be used to access frames as an array ("frame_12 = lldb.thread.frame[12]").''') + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name of this thread as a string.''') + + __swig_getmethods__["queue"] = GetQueueName + if _newclass: queue = property(GetQueueName, None, doc='''A read only property that returns the dispatch queue name of this thread as a string.''') + + __swig_getmethods__["queue_id"] = GetQueueID + if _newclass: queue_id = property(GetQueueID, None, doc='''A read only property that returns the dispatch queue id of this thread as an integer.''') + + __swig_getmethods__["stop_reason"] = GetStopReason + if _newclass: stop_reason = property(GetStopReason, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eStopReason") that represents the reason this thread stopped.''') + + __swig_getmethods__["is_suspended"] = IsSuspended + if _newclass: is_suspended = property(IsSuspended, None, doc='''A read only property that returns a boolean value that indicates if this thread is suspended.''') + + __swig_getmethods__["is_stopped"] = IsStopped + if _newclass: is_stopped = property(IsStopped, None, doc='''A read only property that returns a boolean value that indicates if this thread is stopped but not exited.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBThreadCollection.i b/scripts/interface/SBThreadCollection.i new file mode 100644 index 0000000000000..824f6923acce9 --- /dev/null +++ b/scripts/interface/SBThreadCollection.i @@ -0,0 +1,38 @@ +//===-- SWIG Interface for SBThreadCollection -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +namespace lldb { + +%feature("docstring", +"Represents a collection of SBThread objects." +) SBThreadCollection; +class SBThreadCollection +{ +public: + + SBThreadCollection (); + + SBThreadCollection (const SBThreadCollection &rhs); + + ~SBThreadCollection (); + + bool + IsValid () const; + + size_t + GetSize (); + + lldb::SBThread + GetThreadAtIndex (size_t idx); + +}; + +} // namespace lldb diff --git a/scripts/interface/SBThreadPlan.i b/scripts/interface/SBThreadPlan.i new file mode 100644 index 0000000000000..785855ec5b942 --- /dev/null +++ b/scripts/interface/SBThreadPlan.i @@ -0,0 +1,123 @@ +//===-- SBThread.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBThreadPlan_h_ +#define LLDB_SBThreadPlan_h_ + +#include "lldb/API/SBDefines.h" + +#include <stdio.h> + +namespace lldb { + +%feature("docstring", +"Represents a plan for the execution control of a given thread. + +See also SBThread and SBFrame." +) SBThread; + +class SBThreadPlan +{ + +friend class lldb_private::ThreadPlan; + +public: + SBThreadPlan (); + + SBThreadPlan (const lldb::SBThreadPlan &threadPlan); + + SBThreadPlan (const lldb::ThreadPlanSP& lldb_object_sp); + + SBThreadPlan (lldb::SBThread &thread, const char *class_name); + + ~SBThreadPlan (); + + bool + IsValid() const; + + void + Clear (); + + lldb::StopReason + GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t + GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t + GetStopReasonDataAtIndex(uint32_t idx); + + SBThread + GetThread () const; + + bool + GetDescription (lldb::SBStream &description) const; + + void + SetPlanComplete (bool success); + + bool + IsPlanComplete(); + + bool + IsValid(); + + // This section allows an SBThreadPlan to push another of the common types of plans... + SBThreadPlan + QueueThreadPlanForStepOverRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepInRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn = false); + + SBThreadPlan + QueueThreadPlanForRunToAddress (SBAddress address); + + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + +private: + lldb::ThreadPlanSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadPlan_h_ diff --git a/scripts/interface/SBType.i b/scripts/interface/SBType.i new file mode 100644 index 0000000000000..76bd3f0352c05 --- /dev/null +++ b/scripts/interface/SBType.i @@ -0,0 +1,500 @@ +//===-- SWIG Interface for SBType -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", +"Represents a member of a type in lldb. +") SBTypeMember; + +class SBTypeMember +{ +public: + SBTypeMember (); + + SBTypeMember (const lldb::SBTypeMember& rhs); + + ~SBTypeMember(); + + bool + IsValid() const; + + const char * + GetName (); + + lldb::SBType + GetType (); + + uint64_t + GetOffsetInBytes(); + + uint64_t + GetOffsetInBits(); + + bool + IsBitfield(); + + uint32_t + GetBitfieldSizeInBits(); + + %pythoncode %{ + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name for this member as a string.''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns an lldb object that represents the type (lldb.SBType) for this member.''') + + __swig_getmethods__["byte_offset"] = GetOffsetInBytes + if _newclass: byte_offset = property(GetOffsetInBytes, None, doc='''A read only property that returns offset in bytes for this member as an integer.''') + + __swig_getmethods__["bit_offset"] = GetOffsetInBits + if _newclass: bit_offset = property(GetOffsetInBits, None, doc='''A read only property that returns offset in bits for this member as an integer.''') + + __swig_getmethods__["is_bitfield"] = IsBitfield + if _newclass: is_bitfield = property(IsBitfield, None, doc='''A read only property that returns true if this member is a bitfield.''') + + __swig_getmethods__["bitfield_bit_size"] = GetBitfieldSizeInBits + if _newclass: bitfield_bit_size = property(GetBitfieldSizeInBits, None, doc='''A read only property that returns the bitfield size in bits for this member as an integer, or zero if this member is not a bitfield.''') + + %} + +protected: + std::unique_ptr<lldb_private::TypeMemberImpl> m_opaque_ap; +}; + +class SBTypeMemberFunction +{ +public: + SBTypeMemberFunction (); + + SBTypeMemberFunction (const lldb::SBTypeMemberFunction& rhs); + + ~SBTypeMemberFunction(); + + bool + IsValid() const; + + const char * + GetName (); + + const char * + GetDemangledName (); + + const char * + GetMangledName (); + + lldb::SBType + GetType (); + + lldb::SBType + GetReturnType (); + + uint32_t + GetNumberOfArguments (); + + lldb::SBType + GetArgumentTypeAtIndex (uint32_t); + + lldb::MemberFunctionKind + GetKind(); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + +protected: + lldb::TypeMemberFunctionImplSP m_opaque_sp; +}; + +%feature("docstring", +"Represents a data type in lldb. The FindFirstType() method of SBTarget/SBModule +returns a SBType. + +SBType supports the eq/ne operator. For example, + +main.cpp: + +class Task { +public: + int id; + Task *next; + Task(int i, Task *n): + id(i), + next(n) + {} +}; + +int main (int argc, char const *argv[]) +{ + Task *task_head = new Task(-1, NULL); + Task *task1 = new Task(1, NULL); + Task *task2 = new Task(2, NULL); + Task *task3 = new Task(3, NULL); // Orphaned. + Task *task4 = new Task(4, NULL); + Task *task5 = new Task(5, NULL); + + task_head->next = task1; + task1->next = task2; + task2->next = task4; + task4->next = task5; + + int total = 0; + Task *t = task_head; + while (t != NULL) { + if (t->id >= 0) + ++total; + t = t->next; + } + printf('We have a total number of %d tasks\\n', total); + + // This corresponds to an empty task list. + Task *empty_task_head = new Task(-1, NULL); + + return 0; // Break at this line +} + +find_type.py: + + # Get the type 'Task'. + task_type = target.FindFirstType('Task') + self.assertTrue(task_type) + + # Get the variable 'task_head'. + frame0.FindVariable('task_head') + task_head_type = task_head.GetType() + self.assertTrue(task_head_type.IsPointerType()) + + # task_head_type is 'Task *'. + task_pointer_type = task_type.GetPointerType() + self.assertTrue(task_head_type == task_pointer_type) + + # Get the child mmember 'id' from 'task_head'. + id = task_head.GetChildMemberWithName('id') + id_type = id.GetType() + + # SBType.GetBasicType() takes an enum 'BasicType' (lldb-enumerations.h). + int_type = id_type.GetBasicType(lldb.eBasicTypeInt) + # id_type and int_type should be the same type! + self.assertTrue(id_type == int_type) + +... +") SBType; +class SBType +{ +public: + SBType (); + + SBType (const lldb::SBType &rhs); + + ~SBType (); + + bool + IsValid(); + + uint64_t + GetByteSize(); + + bool + IsPointerType(); + + bool + IsReferenceType(); + + bool + IsFunctionType (); + + bool + IsPolymorphicClass (); + + bool + IsArrayType (); + + bool + IsVectorType (); + + bool + IsTypedefType (); + + bool + IsAnonymousType (); + + lldb::SBType + GetPointerType(); + + lldb::SBType + GetPointeeType(); + + lldb::SBType + GetReferenceType(); + + lldb::SBType + SBType::GetTypedefedType(); + + lldb::SBType + GetDereferencedType(); + + lldb::SBType + GetUnqualifiedType(); + + lldb::SBType + GetCanonicalType(); + + lldb::SBType + GetArrayElementType (); + + lldb::SBType + GetVectorElementType (); + + lldb::BasicType + GetBasicType(); + + lldb::SBType + GetBasicType (lldb::BasicType type); + + uint32_t + GetNumberOfFields (); + + uint32_t + GetNumberOfDirectBaseClasses (); + + uint32_t + GetNumberOfVirtualBaseClasses (); + + lldb::SBTypeMember + GetFieldAtIndex (uint32_t idx); + + lldb::SBTypeMember + GetDirectBaseClassAtIndex (uint32_t idx); + + lldb::SBTypeMember + GetVirtualBaseClassAtIndex (uint32_t idx); + + lldb::SBTypeEnumMemberList + GetEnumMembers(); + + const char* + GetName(); + + const char * + GetDisplayTypeName (); + + lldb::TypeClass + GetTypeClass (); + + uint32_t + GetNumberOfTemplateArguments (); + + lldb::SBType + GetTemplateArgumentType (uint32_t idx); + + lldb::TemplateArgumentKind + GetTemplateArgumentKind (uint32_t idx); + + lldb::SBType + GetFunctionReturnType (); + + lldb::SBTypeList + GetFunctionArgumentTypes (); + + uint32_t + GetNumberOfMemberFunctions (); + + lldb::SBTypeMemberFunction + GetMemberFunctionAtIndex (uint32_t idx); + + bool + IsTypeComplete (); + + uint32_t + GetTypeFlags (); + + %pythoncode %{ + def template_arg_array(self): + num_args = self.num_template_args + if num_args: + template_args = [] + for i in range(num_args): + template_args.append(self.GetTemplateArgumentType(i)) + return template_args + return None + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name for this type as a string.''') + + __swig_getmethods__["size"] = GetByteSize + if _newclass: size = property(GetByteSize, None, doc='''A read only property that returns size in bytes for this type as an integer.''') + + __swig_getmethods__["is_pointer"] = IsPointerType + if _newclass: is_pointer = property(IsPointerType, None, doc='''A read only property that returns a boolean value that indicates if this type is a pointer type.''') + + __swig_getmethods__["is_reference"] = IsReferenceType + if _newclass: is_reference = property(IsReferenceType, None, doc='''A read only property that returns a boolean value that indicates if this type is a reference type.''') + + __swig_getmethods__["is_function"] = IsFunctionType + if _newclass: is_reference = property(IsReferenceType, None, doc='''A read only property that returns a boolean value that indicates if this type is a function type.''') + + __swig_getmethods__["num_fields"] = GetNumberOfFields + if _newclass: num_fields = property(GetNumberOfFields, None, doc='''A read only property that returns number of fields in this type as an integer.''') + + __swig_getmethods__["num_bases"] = GetNumberOfDirectBaseClasses + if _newclass: num_bases = property(GetNumberOfDirectBaseClasses, None, doc='''A read only property that returns number of direct base classes in this type as an integer.''') + + __swig_getmethods__["num_vbases"] = GetNumberOfVirtualBaseClasses + if _newclass: num_vbases = property(GetNumberOfVirtualBaseClasses, None, doc='''A read only property that returns number of virtual base classes in this type as an integer.''') + + __swig_getmethods__["num_template_args"] = GetNumberOfTemplateArguments + if _newclass: num_template_args = property(GetNumberOfTemplateArguments, None, doc='''A read only property that returns number of template arguments in this type as an integer.''') + + __swig_getmethods__["template_args"] = template_arg_array + if _newclass: template_args = property(template_arg_array, None, doc='''A read only property that returns a list() of lldb.SBType objects that represent all template arguments in this type.''') + + __swig_getmethods__["type"] = GetTypeClass + if _newclass: type = property(GetTypeClass, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eTypeClass") that represents a classification for this type.''') + + __swig_getmethods__["is_complete"] = IsTypeComplete + if _newclass: is_complete = property(IsTypeComplete, None, doc='''A read only property that returns a boolean value that indicates if this type is a complete type (True) or a forward declaration (False).''') + + def get_bases_array(self): + '''An accessor function that returns a list() that contains all direct base classes in a lldb.SBType object.''' + bases = [] + for idx in range(self.GetNumberOfDirectBaseClasses()): + bases.append(self.GetDirectBaseClassAtIndex(idx)) + return bases + + def get_vbases_array(self): + '''An accessor function that returns a list() that contains all fields in a lldb.SBType object.''' + vbases = [] + for idx in range(self.GetNumberOfVirtualBaseClasses()): + vbases.append(self.GetVirtualBaseClassAtIndex(idx)) + return vbases + + def get_fields_array(self): + '''An accessor function that returns a list() that contains all fields in a lldb.SBType object.''' + fields = [] + for idx in range(self.GetNumberOfFields()): + fields.append(self.GetFieldAtIndex(idx)) + return fields + + def get_members_array(self): + '''An accessor function that returns a list() that contains all members (base classes and fields) in a lldb.SBType object in ascending bit offset order.''' + members = [] + bases = self.get_bases_array() + fields = self.get_fields_array() + vbases = self.get_vbases_array() + for base in bases: + bit_offset = base.bit_offset + added = False + for idx, member in enumerate(members): + if member.bit_offset > bit_offset: + members.insert(idx, base) + added = True + break + if not added: + members.append(base) + for vbase in vbases: + bit_offset = vbase.bit_offset + added = False + for idx, member in enumerate(members): + if member.bit_offset > bit_offset: + members.insert(idx, vbase) + added = True + break + if not added: + members.append(vbase) + for field in fields: + bit_offset = field.bit_offset + added = False + for idx, member in enumerate(members): + if member.bit_offset > bit_offset: + members.insert(idx, field) + added = True + break + if not added: + members.append(field) + return members + + def get_enum_members_array(self): + '''An accessor function that returns a list() that contains all enum members in an lldb.SBType object.''' + enum_members_list = [] + sb_enum_members = self.GetEnumMembers() + for idx in range(sb_enum_members.GetSize()): + enum_members_list.append(sb_enum_members.GetTypeEnumMemberAtIndex(idx)) + return enum_members_list + + __swig_getmethods__["bases"] = get_bases_array + if _newclass: bases = property(get_bases_array, None, doc='''A read only property that returns a list() of lldb.SBTypeMember objects that represent all of the direct base classes for this type.''') + + __swig_getmethods__["vbases"] = get_vbases_array + if _newclass: vbases = property(get_vbases_array, None, doc='''A read only property that returns a list() of lldb.SBTypeMember objects that represent all of the virtual base classes for this type.''') + + __swig_getmethods__["fields"] = get_fields_array + if _newclass: fields = property(get_fields_array, None, doc='''A read only property that returns a list() of lldb.SBTypeMember objects that represent all of the fields for this type.''') + + __swig_getmethods__["members"] = get_members_array + if _newclass: members = property(get_members_array, None, doc='''A read only property that returns a list() of all lldb.SBTypeMember objects that represent all of the base classes, virtual base classes and fields for this type in ascending bit offset order.''') + + __swig_getmethods__["enum_members"] = get_enum_members_array + if _newclass: enum_members = property(get_enum_members_array, None, doc='''A read only property that returns a list() of all lldb.SBTypeEnumMember objects that represent the enum members for this type.''') + + %} + +}; + +%feature("docstring", +"Represents a list of SBTypes. The FindTypes() method of SBTarget/SBModule +returns a SBTypeList. + +SBTypeList supports SBType iteration. For example, + +main.cpp: + +class Task { +public: + int id; + Task *next; + Task(int i, Task *n): + id(i), + next(n) + {} +}; + +... + +find_type.py: + + # Get the type 'Task'. + type_list = target.FindTypes('Task') + self.assertTrue(len(type_list) == 1) + # To illustrate the SBType iteration. + for type in type_list: + # do something with type + +... +") SBTypeList; +class SBTypeList +{ +public: + SBTypeList(); + + bool + IsValid(); + + void + Append (lldb::SBType type); + + lldb::SBType + GetTypeAtIndex (uint32_t index); + + uint32_t + GetSize(); + + ~SBTypeList(); +}; + +} // namespace lldb diff --git a/scripts/interface/SBTypeCategory.i b/scripts/interface/SBTypeCategory.i new file mode 100644 index 0000000000000..924c7f6976db7 --- /dev/null +++ b/scripts/interface/SBTypeCategory.i @@ -0,0 +1,246 @@ +//===-- SWIG Interface for SBTypeCategory---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Represents a category that can contain formatters for types. + ") SBTypeCategory; + + class SBTypeCategory + { + public: + + SBTypeCategory(); + + SBTypeCategory (const lldb::SBTypeCategory &rhs); + + ~SBTypeCategory (); + + bool + IsValid() const; + + bool + GetEnabled (); + + void + SetEnabled (bool); + + const char* + GetName(); + + lldb::LanguageType + GetLanguageAtIndex (uint32_t idx); + + uint32_t + GetNumLanguages (); + + void + AddLanguage (lldb::LanguageType language); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + uint32_t + GetNumFormats (); + + uint32_t + GetNumSummaries (); + + uint32_t + GetNumFilters (); + + uint32_t + GetNumSynthetics (); + + lldb::SBTypeNameSpecifier + GetTypeNameSpecifierForFilterAtIndex (uint32_t); + + lldb::SBTypeNameSpecifier + GetTypeNameSpecifierForFormatAtIndex (uint32_t); + + lldb::SBTypeNameSpecifier + GetTypeNameSpecifierForSummaryAtIndex (uint32_t); + + lldb::SBTypeNameSpecifier + GetTypeNameSpecifierForSyntheticAtIndex (uint32_t); + + lldb::SBTypeFilter + GetFilterForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeFormat + GetFormatForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeSummary + GetSummaryForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeSynthetic + GetSyntheticForType (lldb::SBTypeNameSpecifier); + + lldb::SBTypeFilter + GetFilterAtIndex (uint32_t); + + lldb::SBTypeFormat + GetFormatAtIndex (uint32_t); + + lldb::SBTypeSummary + GetSummaryAtIndex (uint32_t); + + lldb::SBTypeSynthetic + GetSyntheticAtIndex (uint32_t); + + bool + AddTypeFormat (lldb::SBTypeNameSpecifier, + lldb::SBTypeFormat); + + bool + DeleteTypeFormat (lldb::SBTypeNameSpecifier); + + bool + AddTypeSummary (lldb::SBTypeNameSpecifier, + lldb::SBTypeSummary); + + bool + DeleteTypeSummary (lldb::SBTypeNameSpecifier); + + bool + AddTypeFilter (lldb::SBTypeNameSpecifier, + lldb::SBTypeFilter); + + bool + DeleteTypeFilter (lldb::SBTypeNameSpecifier); + + bool + AddTypeSynthetic (lldb::SBTypeNameSpecifier, + lldb::SBTypeSynthetic); + + bool + DeleteTypeSynthetic (lldb::SBTypeNameSpecifier); + + %pythoncode %{ + + class formatters_access_class(object): + '''A helper object that will lazily hand out formatters for a specific category.''' + def __init__(self, sbcategory, get_count_function, get_at_index_function, get_by_name_function): + self.sbcategory = sbcategory + self.get_count_function = get_count_function + self.get_at_index_function = get_at_index_function + self.get_by_name_function = get_by_name_function + self.regex_type = type(re.compile('.')) + + + def __len__(self): + if self.sbcategory and self.get_count_function: + return int(self.get_count_function(self.sbcategory)) + return 0 + + def __getitem__(self, key): + num_items = len(self) + if type(key) is int: + if key < num_items: + return self.get_at_index_function(self.sbcategory,key) + elif type(key) is str: + return self.get_by_name_function(self.sbcategory,SBTypeNameSpecifier(key)) + elif isinstance(key,self.regex_type): + return self.get_by_name_function(self.sbcategory,SBTypeNameSpecifier(key.pattern,True)) + else: + print("error: unsupported item type: %s" % type(key)) + return None + + def get_formats_access_object(self): + '''An accessor function that returns an accessor object which allows lazy format access from a lldb.SBTypeCategory object.''' + return self.formatters_access_class (self,self.__class__.GetNumFormats,self.__class__.GetFormatAtIndex,self.__class__.GetFormatForType) + + def get_formats_array(self): + '''An accessor function that returns a list() that contains all formats in a lldb.SBCategory object.''' + formats = [] + for idx in range(self.GetNumFormats()): + formats.append(self.GetFormatAtIndex(idx)) + return formats + + def get_summaries_access_object(self): + '''An accessor function that returns an accessor object which allows lazy summary access from a lldb.SBTypeCategory object.''' + return self.formatters_access_class (self,self.__class__.GetNumSummaries,self.__class__.GetSummaryAtIndex,self.__class__.GetSummaryForType) + + def get_summaries_array(self): + '''An accessor function that returns a list() that contains all summaries in a lldb.SBCategory object.''' + summaries = [] + for idx in range(self.GetNumSummaries()): + summaries.append(self.GetSummaryAtIndex(idx)) + return summaries + + def get_synthetics_access_object(self): + '''An accessor function that returns an accessor object which allows lazy synthetic children provider access from a lldb.SBTypeCategory object.''' + return self.formatters_access_class (self,self.__class__.GetNumSynthetics,self.__class__.GetSyntheticAtIndex,self.__class__.GetSyntheticForType) + + def get_synthetics_array(self): + '''An accessor function that returns a list() that contains all synthetic children providers in a lldb.SBCategory object.''' + synthetics = [] + for idx in range(self.GetNumSynthetics()): + synthetics.append(self.GetSyntheticAtIndex(idx)) + return synthetics + + def get_filters_access_object(self): + '''An accessor function that returns an accessor object which allows lazy filter access from a lldb.SBTypeCategory object.''' + return self.formatters_access_class (self,self.__class__.GetNumFilters,self.__class__.GetFilterAtIndex,self.__class__.GetFilterForType) + + def get_filters_array(self): + '''An accessor function that returns a list() that contains all filters in a lldb.SBCategory object.''' + filters = [] + for idx in range(self.GetNumFilters()): + filters.append(self.GetFilterAtIndex(idx)) + return filters + + __swig_getmethods__["formats"] = get_formats_array + if _newclass: formats = property(get_formats_array, None, doc='''A read only property that returns a list() of lldb.SBTypeFormat objects contained in this category''') + + __swig_getmethods__["format"] = get_formats_access_object + if _newclass: format = property(get_formats_access_object, None, doc=r'''A read only property that returns an object that you can use to look for formats by index or type name.''') + + __swig_getmethods__["summaries"] = get_summaries_array + if _newclass: summaries = property(get_summaries_array, None, doc='''A read only property that returns a list() of lldb.SBTypeSummary objects contained in this category''') + + __swig_getmethods__["summary"] = get_summaries_access_object + if _newclass: summary = property(get_summaries_access_object, None, doc=r'''A read only property that returns an object that you can use to look for summaries by index or type name or regular expression.''') + + __swig_getmethods__["filters"] = get_filters_array + if _newclass: filters = property(get_filters_array, None, doc='''A read only property that returns a list() of lldb.SBTypeFilter objects contained in this category''') + + __swig_getmethods__["filter"] = get_filters_access_object + if _newclass: filter = property(get_filters_access_object, None, doc=r'''A read only property that returns an object that you can use to look for filters by index or type name or regular expression.''') + + __swig_getmethods__["synthetics"] = get_synthetics_array + if _newclass: synthetics = property(get_synthetics_array, None, doc='''A read only property that returns a list() of lldb.SBTypeSynthetic objects contained in this category''') + + __swig_getmethods__["synthetic"] = get_synthetics_access_object + if _newclass: synthetic = property(get_synthetics_access_object, None, doc=r'''A read only property that returns an object that you can use to look for synthetic children provider by index or type name or regular expression.''') + + __swig_getmethods__["num_formats"] = GetNumFormats + if _newclass: num_formats = property(GetNumFormats, None) + __swig_getmethods__["num_summaries"] = GetNumSummaries + if _newclass: num_summaries = property(GetNumSummaries, None) + __swig_getmethods__["num_filters"] = GetNumFilters + if _newclass: num_filters = property(GetNumFilters, None) + __swig_getmethods__["num_synthetics"] = GetNumSynthetics + if _newclass: num_synthetics = property(GetNumSynthetics, None) + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None) + + __swig_getmethods__["enabled"] = GetEnabled + __swig_setmethods__["enabled"] = SetEnabled + if _newclass: enabled = property(GetEnabled, SetEnabled) + %} + + }; + + +} // namespace lldb + diff --git a/scripts/interface/SBTypeEnumMember.i b/scripts/interface/SBTypeEnumMember.i new file mode 100644 index 0000000000000..02d89f17a28b6 --- /dev/null +++ b/scripts/interface/SBTypeEnumMember.i @@ -0,0 +1,108 @@ +//===-- SWIG Interface for SBTypeEnumMember ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature( + "docstring", + "Represents a member of an enum in lldb." +) SBTypeEnumMember; + +class SBTypeEnumMember +{ +public: + SBTypeEnumMember (); + + SBTypeEnumMember (const SBTypeEnumMember& rhs); + + ~SBTypeEnumMember(); + + bool + IsValid() const; + + int64_t + GetValueAsSigned(); + + uint64_t + GetValueAsUnsigned(); + + const char * + GetName (); + + lldb::SBType + GetType (); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + %pythoncode %{ + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name for this enum member as a string.''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns an lldb object that represents the type (lldb.SBType) for this enum member.''') + + __swig_getmethods__["signed"] = GetValueAsSigned + if _newclass: signed = property(GetValueAsSigned, None, doc='''A read only property that returns the value of this enum member as a signed integer.''') + + __swig_getmethods__["unsigned"] = GetValueAsUnsigned + if _newclass: unsigned = property(GetValueAsUnsigned, None, doc='''A read only property that returns the value of this enum member as a unsigned integer.''') + %} + +protected: + friend class SBType; + friend class SBTypeEnumMemberList; + + void + reset (lldb_private::TypeEnumMemberImpl *); + + lldb_private::TypeEnumMemberImpl & + ref (); + + const lldb_private::TypeEnumMemberImpl & + ref () const; + + lldb::TypeEnumMemberImplSP m_opaque_sp; + + SBTypeEnumMember (const lldb::TypeEnumMemberImplSP &); +}; + +%feature( + "docstring", + "Represents a list of SBTypeEnumMembers." +) SBTypeEnumMemberList; + +class SBTypeEnumMemberList +{ +public: + SBTypeEnumMemberList(); + + SBTypeEnumMemberList(const SBTypeEnumMemberList& rhs); + + ~SBTypeEnumMemberList(); + + bool + IsValid(); + + void + Append (SBTypeEnumMember entry); + + SBTypeEnumMember + GetTypeEnumMemberAtIndex (uint32_t index); + + uint32_t + GetSize(); + + +private: + std::unique_ptr<lldb_private::TypeEnumMemberListImpl> m_opaque_ap; +}; + +} // namespace lldb diff --git a/scripts/interface/SBTypeFilter.i b/scripts/interface/SBTypeFilter.i new file mode 100644 index 0000000000000..083dfa8433afd --- /dev/null +++ b/scripts/interface/SBTypeFilter.i @@ -0,0 +1,75 @@ +//===-- SWIG Interface for SBTypeFilter----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Represents a filter that can be associated to one or more types. + ") SBTypeFilter; + + class SBTypeFilter + { + public: + + SBTypeFilter(); + + SBTypeFilter (uint32_t options); + + SBTypeFilter (const lldb::SBTypeFilter &rhs); + + ~SBTypeFilter (); + + bool + IsValid() const; + + bool + IsEqualTo (lldb::SBTypeFilter &rhs); + + uint32_t + GetNumberOfExpressionPaths (); + + const char* + GetExpressionPathAtIndex (uint32_t i); + + bool + ReplaceExpressionPathAtIndex (uint32_t i, const char* item); + + void + AppendExpressionPath (const char* item); + + void + Clear(); + + uint32_t + GetOptions(); + + void + SetOptions (uint32_t); + + bool + GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level); + + bool + operator == (lldb::SBTypeFilter &rhs); + + bool + operator != (lldb::SBTypeFilter &rhs); + + %pythoncode %{ + __swig_getmethods__["options"] = GetOptions + __swig_setmethods__["options"] = SetOptions + if _newclass: options = property(GetOptions, SetOptions) + + __swig_getmethods__["count"] = GetNumberOfExpressionPaths + if _newclass: count = property(GetNumberOfExpressionPaths, None) + %} + + }; + +} // namespace lldb diff --git a/scripts/interface/SBTypeFormat.i b/scripts/interface/SBTypeFormat.i new file mode 100644 index 0000000000000..4e4b69c3f1fcf --- /dev/null +++ b/scripts/interface/SBTypeFormat.i @@ -0,0 +1,78 @@ +//===-- SWIG Interface for SBTypeFormat----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Represents a format that can be associated to one or more types. + ") SBTypeFormat; + + class SBTypeFormat + { + public: + + SBTypeFormat(); + + SBTypeFormat (lldb::Format format, uint32_t options = 0); + + SBTypeFormat (const char* type, uint32_t options = 0); + + SBTypeFormat (const lldb::SBTypeFormat &rhs); + + ~SBTypeFormat (); + + bool + IsValid() const; + + bool + IsEqualTo (lldb::SBTypeFormat &rhs); + + lldb::Format + GetFormat (); + + const char* + GetTypeName (); + + uint32_t + GetOptions(); + + void + SetFormat (lldb::Format); + + void + SetTypeName (const char*); + + void + SetOptions (uint32_t); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + bool + operator == (lldb::SBTypeFormat &rhs); + + bool + operator != (lldb::SBTypeFormat &rhs); + + %pythoncode %{ + __swig_getmethods__["format"] = GetFormat + __swig_setmethods__["format"] = SetFormat + if _newclass: format = property(GetFormat, SetFormat) + + __swig_getmethods__["options"] = GetOptions + __swig_setmethods__["options"] = SetOptions + if _newclass: options = property(GetOptions, SetOptions) + %} + + }; + + +} // namespace lldb + diff --git a/scripts/interface/SBTypeNameSpecifier.i b/scripts/interface/SBTypeNameSpecifier.i new file mode 100644 index 0000000000000..97d23ca172ef0 --- /dev/null +++ b/scripts/interface/SBTypeNameSpecifier.i @@ -0,0 +1,68 @@ +//===-- SWIG Interface for SBTypeNameSpecifier---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Represents a general way to provide a type name to LLDB APIs. + ") SBTypeNameSpecifier; + + class SBTypeNameSpecifier + { + public: + + SBTypeNameSpecifier(); + + SBTypeNameSpecifier (const char* name, + bool is_regex = false); + + SBTypeNameSpecifier (SBType type); + + SBTypeNameSpecifier (const lldb::SBTypeNameSpecifier &rhs); + + ~SBTypeNameSpecifier (); + + bool + IsValid() const; + + bool + IsEqualTo (lldb::SBTypeNameSpecifier &rhs); + + const char* + GetName(); + + lldb::SBType + GetType (); + + bool + IsRegex(); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + bool + operator == (lldb::SBTypeNameSpecifier &rhs); + + bool + operator != (lldb::SBTypeNameSpecifier &rhs); + + %pythoncode %{ + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None) + + __swig_getmethods__["is_regex"] = IsRegex + if _newclass: is_regex = property(IsRegex, None) + %} + + + }; + +} // namespace lldb + diff --git a/scripts/interface/SBTypeSummary.i b/scripts/interface/SBTypeSummary.i new file mode 100644 index 0000000000000..924256111aeed --- /dev/null +++ b/scripts/interface/SBTypeSummary.i @@ -0,0 +1,123 @@ +//===-- SWIG Interface for SBTypeSummary---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + class SBTypeSummaryOptions + { + public: + SBTypeSummaryOptions(); + + SBTypeSummaryOptions (const lldb::SBTypeSummaryOptions &rhs); + + ~SBTypeSummaryOptions (); + + bool + IsValid (); + + lldb::LanguageType + GetLanguage (); + + lldb::TypeSummaryCapping + GetCapping (); + + void + SetLanguage (lldb::LanguageType); + + void + SetCapping (lldb::TypeSummaryCapping); + }; + + %feature("docstring", + "Represents a summary that can be associated to one or more types. + ") SBTypeSummary; + + class SBTypeSummary + { + public: + + SBTypeSummary(); + + static SBTypeSummary + CreateWithSummaryString (const char* data, uint32_t options = 0); + + static SBTypeSummary + CreateWithFunctionName (const char* data, uint32_t options = 0); + + static SBTypeSummary + CreateWithScriptCode (const char* data, uint32_t options = 0); + + SBTypeSummary (const lldb::SBTypeSummary &rhs); + + ~SBTypeSummary (); + + bool + IsValid() const; + + bool + IsEqualTo (lldb::SBTypeSummary &rhs); + + bool + IsFunctionCode(); + + bool + IsFunctionName(); + + bool + IsSummaryString(); + + const char* + GetData (); + + void + SetSummaryString (const char* data); + + void + SetFunctionName (const char* data); + + void + SetFunctionCode (const char* data); + + uint32_t + GetOptions (); + + void + SetOptions (uint32_t); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + bool + operator == (lldb::SBTypeSummary &rhs); + + bool + operator != (lldb::SBTypeSummary &rhs); + + %pythoncode %{ + __swig_getmethods__["options"] = GetOptions + __swig_setmethods__["options"] = SetOptions + if _newclass: options = property(GetOptions, SetOptions) + + __swig_getmethods__["is_summary_string"] = IsSummaryString + if _newclass: is_summary_string = property(IsSummaryString, None) + + __swig_getmethods__["is_function_name"] = IsFunctionName + if _newclass: is_function_name = property(IsFunctionName, None) + + __swig_getmethods__["is_function_name"] = IsFunctionCode + if _newclass: is_function_name = property(IsFunctionCode, None) + + __swig_getmethods__["summary_data"] = GetData + if _newclass: summary_data = property(GetData, None) + %} + + }; + +} // namespace lldb + diff --git a/scripts/interface/SBTypeSynthetic.i b/scripts/interface/SBTypeSynthetic.i new file mode 100644 index 0000000000000..e040cd55c975d --- /dev/null +++ b/scripts/interface/SBTypeSynthetic.i @@ -0,0 +1,80 @@ +//===-- SWIG Interface for SBTypeSynthetic-------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + + %feature("docstring", + "Represents a summary that can be associated to one or more types. + ") SBTypeSynthetic; + + class SBTypeSynthetic + { + public: + + SBTypeSynthetic(); + + static lldb::SBTypeSynthetic + CreateWithClassName (const char* data, uint32_t options = 0); + + static lldb::SBTypeSynthetic + CreateWithScriptCode (const char* data, uint32_t options = 0); + + SBTypeSynthetic (const lldb::SBTypeSynthetic &rhs); + + ~SBTypeSynthetic (); + + bool + IsValid() const; + + bool + IsEqualTo (lldb::SBTypeSynthetic &rhs); + + bool + IsClassCode(); + + const char* + GetData (); + + void + SetClassName (const char* data); + + void + SetClassCode (const char* data); + + uint32_t + GetOptions (); + + void + SetOptions (uint32_t); + + bool + GetDescription (lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + bool + operator == (lldb::SBTypeSynthetic &rhs); + + bool + operator != (lldb::SBTypeSynthetic &rhs); + + %pythoncode %{ + __swig_getmethods__["options"] = GetOptions + __swig_setmethods__["options"] = SetOptions + if _newclass: options = property(GetOptions, SetOptions) + + __swig_getmethods__["contains_code"] = IsClassCode + if _newclass: contains_code = property(IsClassCode, None) + + __swig_getmethods__["synthetic_data"] = GetData + if _newclass: synthetic_data = property(GetData, None) + %} + + }; + +} // namespace lldb diff --git a/scripts/interface/SBUnixSignals.i b/scripts/interface/SBUnixSignals.i new file mode 100644 index 0000000000000..2cb45371070b8 --- /dev/null +++ b/scripts/interface/SBUnixSignals.i @@ -0,0 +1,74 @@ +//===-- SWIG Interface for SBUnixSignals ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Allows you to manipulate LLDB's signal disposition" +) SBUnixSignals; +class SBUnixSignals +{ +public: + SBUnixSignals (); + + SBUnixSignals (const lldb::SBUnixSignals &rhs); + + ~SBUnixSignals(); + + void + Clear (); + + bool + IsValid () const; + + const char * + GetSignalAsCString (int32_t signo) const; + + int32_t + GetSignalNumberFromName (const char *name) const; + + bool + GetShouldSuppress (int32_t signo) const; + + bool + SetShouldSuppress (int32_t signo, + bool value); + + bool + GetShouldStop (int32_t signo) const; + + bool + SetShouldStop (int32_t signo, + bool value); + + bool + GetShouldNotify (int32_t signo) const; + + bool + SetShouldNotify (int32_t signo, bool value); + + int32_t + GetNumSignals () const; + + int32_t + GetSignalAtIndex (int32_t index) const; + + %pythoncode %{ + def get_unix_signals_list(self): + signals = [] + for idx in range(0, self.GetNumSignals()): + signals.append(self.GetSignalAtIndex(sig)) + return signals + + __swig_getmethods__["signals"] = get_unix_signals_list + if _newclass: threads = property(get_unix_signals_list, None, doc='''A read only property that returns a list() of valid signal numbers for this platform.''') + %} +}; + +} // namespace lldb diff --git a/scripts/interface/SBValue.i b/scripts/interface/SBValue.i new file mode 100644 index 0000000000000..5049fd05794d5 --- /dev/null +++ b/scripts/interface/SBValue.i @@ -0,0 +1,540 @@ +//===-- SWIG Interface for SBValue ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents the value of a variable, a register, or an expression. + +SBValue supports iteration through its child, which in turn is represented +as an SBValue. For example, we can get the general purpose registers of a +frame as an SBValue, and iterate through all the registers, + + registerSet = frame.GetRegisters() # Returns an SBValueList. + for regs in registerSet: + if 'general purpose registers' in regs.getName().lower(): + GPRs = regs + break + + print('%s (number of children = %d):' % (GPRs.GetName(), GPRs.GetNumChildren())) + for reg in GPRs: + print('Name: ', reg.GetName(), ' Value: ', reg.GetValue()) + +produces the output: + +General Purpose Registers (number of children = 21): +Name: rax Value: 0x0000000100000c5c +Name: rbx Value: 0x0000000000000000 +Name: rcx Value: 0x00007fff5fbffec0 +Name: rdx Value: 0x00007fff5fbffeb8 +Name: rdi Value: 0x0000000000000001 +Name: rsi Value: 0x00007fff5fbffea8 +Name: rbp Value: 0x00007fff5fbffe80 +Name: rsp Value: 0x00007fff5fbffe60 +Name: r8 Value: 0x0000000008668682 +Name: r9 Value: 0x0000000000000000 +Name: r10 Value: 0x0000000000001200 +Name: r11 Value: 0x0000000000000206 +Name: r12 Value: 0x0000000000000000 +Name: r13 Value: 0x0000000000000000 +Name: r14 Value: 0x0000000000000000 +Name: r15 Value: 0x0000000000000000 +Name: rip Value: 0x0000000100000dae +Name: rflags Value: 0x0000000000000206 +Name: cs Value: 0x0000000000000027 +Name: fs Value: 0x0000000000000010 +Name: gs Value: 0x0000000000000048 + +See also linked_list_iter() for another perspective on how to iterate through an +SBValue instance which interprets the value object as representing the head of a +linked list." +) SBValue; +class SBValue +{ +public: + SBValue (); + + SBValue (const SBValue &rhs); + + ~SBValue (); + + bool + IsValid(); + + void + Clear(); + + SBError + GetError(); + + lldb::user_id_t + GetID (); + + const char * + GetName(); + + const char * + GetTypeName (); + + const char * + GetDisplayTypeName (); + + size_t + GetByteSize (); + + bool + IsInScope (); + + lldb::Format + GetFormat (); + + void + SetFormat (lldb::Format format); + + const char * + GetValue (); + + int64_t + GetValueAsSigned(SBError& error, int64_t fail_value=0); + + uint64_t + GetValueAsUnsigned(SBError& error, uint64_t fail_value=0); + + int64_t + GetValueAsSigned(int64_t fail_value=0); + + uint64_t + GetValueAsUnsigned(uint64_t fail_value=0); + + ValueType + GetValueType (); + + bool + GetValueDidChange (); + + const char * + GetSummary (); + + const char * + GetSummary (lldb::SBStream& stream, + lldb::SBTypeSummaryOptions& options); + + const char * + GetObjectDescription (); + + const char * + GetTypeValidatorResult (); + + lldb::SBValue + GetDynamicValue (lldb::DynamicValueType use_dynamic); + + lldb::SBValue + GetStaticValue (); + + lldb::SBValue + GetNonSyntheticValue (); + + lldb::DynamicValueType + GetPreferDynamicValue (); + + void + SetPreferDynamicValue (lldb::DynamicValueType use_dynamic); + + bool + GetPreferSyntheticValue (); + + void + SetPreferSyntheticValue (bool use_synthetic); + + bool + IsDynamic(); + + bool + IsSynthetic (); + + const char * + GetLocation (); + + bool + SetValueFromCString (const char *value_str); + + bool + SetValueFromCString (const char *value_str, lldb::SBError& error); + + lldb::SBTypeFormat + GetTypeFormat (); + + lldb::SBTypeSummary + GetTypeSummary (); + + lldb::SBTypeFilter + GetTypeFilter (); + + lldb::SBTypeSynthetic + GetTypeSynthetic (); + + lldb::SBValue + GetChildAtIndex (uint32_t idx); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get a child value by index from a value. + /// + /// Structs, unions, classes, arrays and pointers have child + /// values that can be access by index. + /// + /// Structs and unions access child members using a zero based index + /// for each child member. For + /// + /// Classes reserve the first indexes for base classes that have + /// members (empty base classes are omitted), and all members of the + /// current class will then follow the base classes. + /// + /// Pointers differ depending on what they point to. If the pointer + /// points to a simple type, the child at index zero + /// is the only child value available, unless \a synthetic_allowed + /// is \b true, in which case the pointer will be used as an array + /// and can create 'synthetic' child values using positive or + /// negative indexes. If the pointer points to an aggregate type + /// (an array, class, union, struct), then the pointee is + /// transparently skipped and any children are going to be the indexes + /// of the child values within the aggregate type. For example if + /// we have a 'Point' type and we have a SBValue that contains a + /// pointer to a 'Point' type, then the child at index zero will be + /// the 'x' member, and the child at index 1 will be the 'y' member + /// (the child at index zero won't be a 'Point' instance). + /// + /// If you actually need an SBValue that represents the type pointed + /// to by a SBValue for which GetType().IsPointeeType() returns true, + /// regardless of the pointee type, you can do that with the SBValue.Dereference + /// method (or the equivalent deref property). + /// + /// Arrays have a preset number of children that can be accessed by + /// index and will returns invalid child values for indexes that are + /// out of bounds unless the \a synthetic_allowed is \b true. In this + /// case the array can create 'synthetic' child values for indexes + /// that aren't in the array bounds using positive or negative + /// indexes. + /// + /// @param[in] idx + /// The index of the child value to get + /// + /// @param[in] use_dynamic + /// An enumeration that specifies whether to get dynamic values, + /// and also if the target can be run to figure out the dynamic + /// type of the child value. + /// + /// @param[in] synthetic_allowed + /// If \b true, then allow child values to be created by index + /// for pointers and arrays for indexes that normally wouldn't + /// be allowed. + /// + /// @return + /// A new SBValue object that represents the child member value. + //------------------------------------------------------------------ + ") GetChildAtIndex; + lldb::SBValue + GetChildAtIndex (uint32_t idx, + lldb::DynamicValueType use_dynamic, + bool can_create_synthetic); + + lldb::SBValue + CreateChildAtOffset (const char *name, uint32_t offset, lldb::SBType type); + + lldb::SBValue + SBValue::Cast (lldb::SBType type); + + lldb::SBValue + CreateValueFromExpression (const char *name, const char* expression); + + lldb::SBValue + CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options); + + lldb::SBValue + CreateValueFromAddress(const char* name, lldb::addr_t address, lldb::SBType type); + + lldb::SBValue + CreateValueFromData (const char* name, + lldb::SBData data, + lldb::SBType type); + + lldb::SBType + GetType(); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Returns the child member index. + /// + /// Matches children of this object only and will match base classes and + /// member names if this is a clang typed object. + /// + /// @param[in] name + /// The name of the child value to get + /// + /// @return + /// An index to the child member value. + //------------------------------------------------------------------ + ") GetIndexOfChildWithName; + uint32_t + GetIndexOfChildWithName (const char *name); + + lldb::SBValue + GetChildMemberWithName (const char *name); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Returns the child member value. + /// + /// Matches child members of this object and child members of any base + /// classes. + /// + /// @param[in] name + /// The name of the child value to get + /// + /// @param[in] use_dynamic + /// An enumeration that specifies whether to get dynamic values, + /// and also if the target can be run to figure out the dynamic + /// type of the child value. + /// + /// @return + /// A new SBValue object that represents the child member value. + //------------------------------------------------------------------ + ") GetChildMemberWithName; + lldb::SBValue + GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dynamic); + + %feature("docstring", "Expands nested expressions like .a->b[0].c[1]->d." + ) GetValueForExpressionPath; + lldb::SBValue + GetValueForExpressionPath(const char* expr_path); + + lldb::SBDeclaration + GetDeclaration (); + + bool + MightHaveChildren (); + + bool + IsRuntimeSupportValue (); + + uint32_t + GetNumChildren (); + + %feature("doctstring", " + //------------------------------------------------------------------ + /// Returns the number for children. + /// + /// @param[in] max + /// If max is less the lldb.UINT32_MAX, then the returned value is + /// capped to max. + /// + /// @return + /// An integer value capped to the argument max. + //------------------------------------------------------------------ + ") GetNumChildren; + uint32_t + GetNumChildren (uint32_t max); + + void * + GetOpaqueType(); + + lldb::SBValue + Dereference (); + + lldb::SBValue + AddressOf(); + + bool + TypeIsPointerType (); + + lldb::SBTarget + GetTarget(); + + lldb::SBProcess + GetProcess(); + + lldb::SBThread + GetThread(); + + lldb::SBFrame + GetFrame(); + + %feature("docstring", " + /// Find and watch a variable. + /// It returns an SBWatchpoint, which may be invalid. + ") Watch; + lldb::SBWatchpoint + Watch (bool resolve_location, bool read, bool write, SBError &error); + + %feature("docstring", " + /// Find and watch the location pointed to by a variable. + /// It returns an SBWatchpoint, which may be invalid. + ") WatchPointee; + lldb::SBWatchpoint + WatchPointee (bool resolve_location, bool read, bool write, SBError &error); + + bool + GetDescription (lldb::SBStream &description); + + bool + GetExpressionPath (lldb::SBStream &description); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get an SBData wrapping what this SBValue points to. + /// + /// This method will dereference the current SBValue, if its + /// data type is a T* or T[], and extract item_count elements + /// of type T from it, copying their contents in an SBData. + /// + /// @param[in] item_idx + /// The index of the first item to retrieve. For an array + /// this is equivalent to array[item_idx], for a pointer + /// to *(pointer + item_idx). In either case, the measurement + /// unit for item_idx is the sizeof(T) rather than the byte + /// + /// @param[in] item_count + /// How many items should be copied into the output. By default + /// only one item is copied, but more can be asked for. + /// + /// @return + /// An SBData with the contents of the copied items, on success. + /// An empty SBData otherwise. + //------------------------------------------------------------------ + ") GetPointeeData; + lldb::SBData + GetPointeeData (uint32_t item_idx = 0, + uint32_t item_count = 1); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get an SBData wrapping the contents of this SBValue. + /// + /// This method will read the contents of this object in memory + /// and copy them into an SBData for future use. + /// + /// @return + /// An SBData with the contents of this SBValue, on success. + /// An empty SBData otherwise. + //------------------------------------------------------------------ + ") GetData; + lldb::SBData + GetData (); + + bool + SetData (lldb::SBData &data, lldb::SBError& error); + + lldb::addr_t + GetLoadAddress(); + + lldb::SBAddress + GetAddress(); + + lldb::SBValue + Persist (); + + %feature("docstring", "Returns an expression path for this value." + ) GetExpressionPath; + bool + GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes); + + %pythoncode %{ + def __get_dynamic__ (self): + '''Helper function for the "SBValue.dynamic" property.''' + return self.GetDynamicValue (eDynamicCanRunTarget) + + __swig_getmethods__["name"] = GetName + if _newclass: name = property(GetName, None, doc='''A read only property that returns the name of this value as a string.''') + + __swig_getmethods__["type"] = GetType + if _newclass: type = property(GetType, None, doc='''A read only property that returns a lldb.SBType object that represents the type for this value.''') + + __swig_getmethods__["size"] = GetByteSize + if _newclass: size = property(GetByteSize, None, doc='''A read only property that returns the size in bytes of this value.''') + + __swig_getmethods__["is_in_scope"] = IsInScope + if _newclass: is_in_scope = property(IsInScope, None, doc='''A read only property that returns a boolean value that indicates whether this value is currently lexically in scope.''') + + __swig_getmethods__["format"] = GetFormat + __swig_setmethods__["format"] = SetFormat + if _newclass: format = property(GetName, SetFormat, doc='''A read/write property that gets/sets the format used for lldb.SBValue().GetValue() for this value. See enumerations that start with "lldb.eFormat".''') + + __swig_getmethods__["value"] = GetValue + __swig_setmethods__["value"] = SetValueFromCString + if _newclass: value = property(GetValue, SetValueFromCString, doc='''A read/write property that gets/sets value from a string.''') + + __swig_getmethods__["value_type"] = GetValueType + if _newclass: value_type = property(GetValueType, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eValueType") that represents the type of this value (local, argument, global, register, etc.).''') + + __swig_getmethods__["changed"] = GetValueDidChange + if _newclass: changed = property(GetValueDidChange, None, doc='''A read only property that returns a boolean value that indicates if this value has changed since it was last updated.''') + + __swig_getmethods__["data"] = GetData + if _newclass: data = property(GetData, None, doc='''A read only property that returns an lldb object (lldb.SBData) that represents the bytes that make up the value for this object.''') + + __swig_getmethods__["load_addr"] = GetLoadAddress + if _newclass: load_addr = property(GetLoadAddress, None, doc='''A read only property that returns the load address of this value as an integer.''') + + __swig_getmethods__["addr"] = GetAddress + if _newclass: addr = property(GetAddress, None, doc='''A read only property that returns an lldb.SBAddress that represents the address of this value if it is in memory.''') + + __swig_getmethods__["deref"] = Dereference + if _newclass: deref = property(Dereference, None, doc='''A read only property that returns an lldb.SBValue that is created by dereferencing this value.''') + + __swig_getmethods__["address_of"] = AddressOf + if _newclass: address_of = property(AddressOf, None, doc='''A read only property that returns an lldb.SBValue that represents the address-of this value.''') + + __swig_getmethods__["error"] = GetError + if _newclass: error = property(GetError, None, doc='''A read only property that returns the lldb.SBError that represents the error from the last time the variable value was calculated.''') + + __swig_getmethods__["summary"] = GetSummary + if _newclass: summary = property(GetSummary, None, doc='''A read only property that returns the summary for this value as a string''') + + __swig_getmethods__["description"] = GetObjectDescription + if _newclass: description = property(GetObjectDescription, None, doc='''A read only property that returns the language-specific description of this value as a string''') + + __swig_getmethods__["dynamic"] = __get_dynamic__ + if _newclass: dynamic = property(__get_dynamic__, None, doc='''A read only property that returns an lldb.SBValue that is created by finding the dynamic type of this value.''') + + __swig_getmethods__["location"] = GetLocation + if _newclass: location = property(GetLocation, None, doc='''A read only property that returns the location of this value as a string.''') + + __swig_getmethods__["target"] = GetTarget + if _newclass: target = property(GetTarget, None, doc='''A read only property that returns the lldb.SBTarget that this value is associated with.''') + + __swig_getmethods__["process"] = GetProcess + if _newclass: process = property(GetProcess, None, doc='''A read only property that returns the lldb.SBProcess that this value is associated with, the returned value might be invalid and should be tested.''') + + __swig_getmethods__["thread"] = GetThread + if _newclass: thread = property(GetThread, None, doc='''A read only property that returns the lldb.SBThread that this value is associated with, the returned value might be invalid and should be tested.''') + + __swig_getmethods__["frame"] = GetFrame + if _newclass: frame = property(GetFrame, None, doc='''A read only property that returns the lldb.SBFrame that this value is associated with, the returned value might be invalid and should be tested.''') + + __swig_getmethods__["num_children"] = GetNumChildren + if _newclass: num_children = property(GetNumChildren, None, doc='''A read only property that returns the number of child lldb.SBValues that this value has.''') + + __swig_getmethods__["unsigned"] = GetValueAsUnsigned + if _newclass: unsigned = property(GetValueAsUnsigned, None, doc='''A read only property that returns the value of this SBValue as an usigned integer.''') + + __swig_getmethods__["signed"] = GetValueAsSigned + if _newclass: signed = property(GetValueAsSigned, None, doc='''A read only property that returns the value of this SBValue as a signed integer.''') + + def get_expr_path(self): + s = SBStream() + self.GetExpressionPath (s) + return s.GetData() + + __swig_getmethods__["path"] = get_expr_path + if _newclass: path = property(get_expr_path, None, doc='''A read only property that returns the expression path that one can use to reach this value in an expression.''') + %} + +}; + +} // namespace lldb diff --git a/scripts/interface/SBValueList.i b/scripts/interface/SBValueList.i new file mode 100644 index 0000000000000..80e8f0ec999ea --- /dev/null +++ b/scripts/interface/SBValueList.i @@ -0,0 +1,142 @@ +//===-- SWIG Interface for SBValueList --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents a collection of SBValues. Both SBFrame's GetVariables() and +GetRegisters() return a SBValueList. + +SBValueList supports SBValue iteration. For example (from test/lldbutil.py), + +def get_registers(frame, kind): + '''Returns the registers given the frame and the kind of registers desired. + + Returns None if there's no such kind. + ''' + registerSet = frame.GetRegisters() # Return type of SBValueList. + for value in registerSet: + if kind.lower() in value.GetName().lower(): + return value + + return None + +def get_GPRs(frame): + '''Returns the general purpose registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_GPRs + regs = get_GPRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'general purpose') + +def get_FPRs(frame): + '''Returns the floating point registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_FPRs + regs = get_FPRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'floating point') + +def get_ESRs(frame): + '''Returns the exception state registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_ESRs + regs = get_ESRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'exception state')" +) SBValueList; +class SBValueList +{ +public: + + SBValueList (); + + SBValueList (const lldb::SBValueList &rhs); + + ~SBValueList(); + + bool + IsValid() const; + + void + Clear(); + + void + Append (const lldb::SBValue &val_obj); + + void + Append (const lldb::SBValueList& value_list); + + uint32_t + GetSize() const; + + lldb::SBValue + GetValueAtIndex (uint32_t idx) const; + + lldb::SBValue + FindValueObjectByUID (lldb::user_id_t uid); + + lldb::SBValue + GetFirstValueByName (const char* name) const; + + %pythoncode %{ + def __len__(self): + return int(self.GetSize()) + + def __getitem__(self, key): + count = len(self) + #------------------------------------------------------------ + # Access with "int" to get Nth item in the list + #------------------------------------------------------------ + if type(key) is int: + if key < count: + return self.GetValueAtIndex(key) + #------------------------------------------------------------ + # Access with "str" to get values by name + #------------------------------------------------------------ + elif type(key) is str: + matches = [] + for idx in range(count): + value = self.GetValueAtIndex(idx) + if value.name == key: + matches.append(value) + return matches + #------------------------------------------------------------ + # Match with regex + #------------------------------------------------------------ + elif isinstance(key, type(re.compile('.'))): + matches = [] + for idx in range(count): + value = self.GetValueAtIndex(idx) + re_match = key.search(value.name) + if re_match: + matches.append(value) + return matches + + %} + + +}; + +} // namespace lldb diff --git a/scripts/interface/SBVariablesOptions.i b/scripts/interface/SBVariablesOptions.i new file mode 100644 index 0000000000000..3941a58d7bc95 --- /dev/null +++ b/scripts/interface/SBVariablesOptions.i @@ -0,0 +1,61 @@ +//===-- SWIG Interface for SBVariablesOptions ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +class SBVariablesOptions +{ +public: + SBVariablesOptions (); + + SBVariablesOptions (const SBVariablesOptions& options); + + ~SBVariablesOptions (); + + bool + IsValid () const; + + bool + GetIncludeArguments () const; + + void + SetIncludeArguments (bool); + + bool + GetIncludeLocals () const; + + void + SetIncludeLocals (bool); + + bool + GetIncludeStatics () const; + + void + SetIncludeStatics (bool); + + bool + GetInScopeOnly () const; + + void + SetInScopeOnly (bool); + + bool + GetIncludeRuntimeSupportValues () const; + + void + SetIncludeRuntimeSupportValues (bool); + + lldb::DynamicValueType + GetUseDynamic () const; + + void + SetUseDynamic (lldb::DynamicValueType); +}; + +} // namespace lldb diff --git a/scripts/interface/SBWatchpoint.i b/scripts/interface/SBWatchpoint.i new file mode 100644 index 0000000000000..9a40131f51863 --- /dev/null +++ b/scripts/interface/SBWatchpoint.i @@ -0,0 +1,99 @@ +//===-- SWIG Interface for SBWatchpoint -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents an instance of watchpoint for a specific target program. + +A watchpoint is determined by the address and the byte size that resulted in +this particular instantiation. Each watchpoint has its settable options. + +See also SBTarget.watchpoint_iter() for example usage of iterating through the +watchpoints of the target." +) SBWatchpoint; +class SBWatchpoint +{ +public: + + SBWatchpoint (); + + SBWatchpoint (const lldb::SBWatchpoint &rhs); + + ~SBWatchpoint (); + + bool + IsValid(); + + SBError + GetError(); + + watch_id_t + GetID (); + + %feature("docstring", " + //------------------------------------------------------------------ + /// With -1 representing an invalid hardware index. + //------------------------------------------------------------------ + ") GetHardwareIndex; + int32_t + GetHardwareIndex (); + + lldb::addr_t + GetWatchAddress (); + + size_t + GetWatchSize(); + + void + SetEnabled(bool enabled); + + bool + IsEnabled (); + + uint32_t + GetHitCount (); + + uint32_t + GetIgnoreCount (); + + void + SetIgnoreCount (uint32_t n); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Get the condition expression for the watchpoint. + //------------------------------------------------------------------ + ") GetCondition; + const char * + GetCondition (); + + %feature("docstring", " + //-------------------------------------------------------------------------- + /// The watchpoint stops only if the condition expression evaluates to true. + //-------------------------------------------------------------------------- + ") SetCondition; + void + SetCondition (const char *condition); + + bool + GetDescription (lldb::SBStream &description, DescriptionLevel level); + + static bool + EventIsWatchpointEvent (const lldb::SBEvent &event); + + static lldb::WatchpointEventType + GetWatchpointEventTypeFromEvent (const lldb::SBEvent& event); + + static lldb::SBWatchpoint + GetWatchpointFromEvent (const lldb::SBEvent& event); + +}; + +} // namespace lldb diff --git a/scripts/lldb.swig b/scripts/lldb.swig new file mode 100644 index 0000000000000..1d333540728cc --- /dev/null +++ b/scripts/lldb.swig @@ -0,0 +1,199 @@ +/* + lldb.swig + + This is the input file for SWIG, to create the appropriate C++ wrappers and + functions for various scripting languages, to enable them to call the + liblldb Script Bridge functions. +*/ + +/* Define our module docstring. */ +%define DOCSTRING +"The lldb module contains the public APIs for Python binding. + +Some of the important classes are described here: + +o SBTarget: Represents the target program running under the debugger. +o SBProcess: Represents the process associated with the target program. +o SBThread: Represents a thread of execution. SBProcess contains SBThread(s). +o SBFrame: Represents one of the stack frames associated with a thread. SBThread + contains SBFrame(s). +o SBSymbolContext: A container that stores various debugger related info. +o SBValue: Represents the value of a variable, a register, or an expression. +o SBModule: Represents an executable image and its associated object and symbol + files. SBTarget contains SBModule(s). +o SBBreakpoint: Represents a logical breakpoint and its associated settings. + SBTarget contains SBBreakpoint(s). +o SBSymbol: Represents the symbol possibly associated with a stack frame. +o SBCompileUnit: Represents a compilation unit, or compiled source file. +o SBFunction: Represents a generic function, which can be inlined or not. +o SBBlock: Represents a lexical block. SBFunction contains SBBlock(s). +o SBLineEntry: Specifies an association with a contiguous range of instructions + and a source file location. SBCompileUnit contains SBLineEntry(s)." +%enddef + +// The name of the module to be created. +%module(docstring=DOCSTRING) lldb + +// Parameter types will be used in the autodoc string. +%feature("autodoc", "1"); + +%pythoncode%{ +import uuid +import re +import os + +import six +%} +%include "./Python/python-typemaps.swig" + +/* C++ headers to be included. */ +%{ +#include <algorithm> +#include <string> +%} + +/* The liblldb header files to be included. */ +%{ +#include "lldb/lldb-public.h" +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBAttachInfo.h" +#include "lldb/API/SBBlock.h" +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBBroadcaster.h" +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBCommunication.h" +#include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBData.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBDeclaration.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBEvent.h" +#include "lldb/API/SBExecutionContext.h" +#include "lldb/API/SBExpressionOptions.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBFileSpecList.h" +#include "lldb/API/SBFrame.h" +#include "lldb/API/SBFunction.h" +#include "lldb/API/SBHostOS.h" +#include "lldb/API/SBInstruction.h" +#include "lldb/API/SBInstructionList.h" +#include "lldb/API/SBLanguageRuntime.h" +#include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBLineEntry.h" +#include "lldb/API/SBListener.h" +#include "lldb/API/SBModule.h" +#include "lldb/API/SBModuleSpec.h" +#include "lldb/API/SBPlatform.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBQueue.h" +#include "lldb/API/SBQueueItem.h" +#include "lldb/API/SBSection.h" +#include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" +#include "lldb/API/SBSymbol.h" +#include "lldb/API/SBSymbolContext.h" +#include "lldb/API/SBSymbolContextList.h" +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBThread.h" +#include "lldb/API/SBThreadCollection.h" +#include "lldb/API/SBThreadPlan.h" +#include "lldb/API/SBType.h" +#include "lldb/API/SBTypeCategory.h" +#include "lldb/API/SBTypeEnumMember.h" +#include "lldb/API/SBTypeFilter.h" +#include "lldb/API/SBTypeFormat.h" +#include "lldb/API/SBTypeNameSpecifier.h" +#include "lldb/API/SBTypeSummary.h" +#include "lldb/API/SBTypeSynthetic.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "lldb/API/SBVariablesOptions.h" +#include "lldb/API/SBWatchpoint.h" +#include "lldb/API/SBUnixSignals.h" + +#include "../source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h" + +#include "../scripts/Python/python-swigsafecast.swig" +%} + +/* Various liblldb typedefs that SWIG needs to know about. */ +#define __extension__ /* Undefine GCC keyword to make Swig happy when processing glibc's stdint.h. */ +/* The ISO C99 standard specifies that in C++ implementations limit macros such + as INT32_MAX should only be defined if __STDC_LIMIT_MACROS is. */ +#define __STDC_LIMIT_MACROS +%include "stdint.i" + +%include "lldb/lldb-defines.h" +%include "lldb/lldb-enumerations.h" +%include "lldb/lldb-forward.h" +%include "lldb/lldb-types.h" + +/* Forward declaration of SB classes. */ +%include "lldb/API/SBDefines.h" + +/* Python interface files with docstrings. */ +%include "./interface/SBAddress.i" +%include "./interface/SBAttachInfo.i" +%include "./interface/SBBlock.i" +%include "./interface/SBBreakpoint.i" +%include "./interface/SBBreakpointLocation.i" +%include "./interface/SBBroadcaster.i" +%include "./interface/SBCommandInterpreter.i" +%include "./interface/SBCommandReturnObject.i" +%include "./interface/SBCommunication.i" +%include "./interface/SBCompileUnit.i" +%include "./interface/SBData.i" +%include "./interface/SBDebugger.i" +%include "./interface/SBDeclaration.i" +%include "./interface/SBError.i" +%include "./interface/SBEvent.i" +%include "./interface/SBExecutionContext.i" +%include "./interface/SBExpressionOptions.i" +%include "./interface/SBFileSpec.i" +%include "./interface/SBFileSpecList.i" +%include "./interface/SBFrame.i" +%include "./interface/SBFunction.i" +%include "./interface/SBHostOS.i" +%include "./interface/SBInstruction.i" +%include "./interface/SBInstructionList.i" +%include "./interface/SBLanguageRuntime.i" +%include "./interface/SBLaunchInfo.i" +%include "./interface/SBLineEntry.i" +%include "./interface/SBListener.i" +%include "./interface/SBModule.i" +%include "./interface/SBModuleSpec.i" +%include "./interface/SBPlatform.i" +%include "./interface/SBProcess.i" +%include "./interface/SBQueue.i" +%include "./interface/SBQueueItem.i" +%include "./interface/SBSection.i" +%include "./interface/SBSourceManager.i" +%include "./interface/SBStream.i" +%include "./interface/SBStringList.i" +%include "./interface/SBSymbol.i" +%include "./interface/SBSymbolContext.i" +%include "./interface/SBSymbolContextList.i" +%include "./interface/SBTarget.i" +%include "./interface/SBThread.i" +%include "./interface/SBThreadCollection.i" +%include "./interface/SBThreadPlan.i" +%include "./interface/SBType.i" +%include "./interface/SBTypeCategory.i" +%include "./interface/SBTypeEnumMember.i" +%include "./interface/SBTypeFilter.i" +%include "./interface/SBTypeFormat.i" +%include "./interface/SBTypeNameSpecifier.i" +%include "./interface/SBTypeSummary.i" +%include "./interface/SBTypeSynthetic.i" +%include "./interface/SBValue.i" +%include "./interface/SBValueList.i" +%include "./interface/SBVariablesOptions.i" +%include "./interface/SBWatchpoint.i" +%include "./interface/SBUnixSignals.i" + +%include "./Python/python-extensions.swig" + +%include "./Python/python-wrapper.swig" diff --git a/scripts/package-clang-headers.py b/scripts/package-clang-headers.py new file mode 100644 index 0000000000000..b28ad0d343eca --- /dev/null +++ b/scripts/package-clang-headers.py @@ -0,0 +1,80 @@ +#! /usr/bin/env python + +# package-clang-headers.py +# +# The Clang module loader depends on built-in headers for the Clang compiler. +# We grab these from the Clang build and move them into the LLDB module. + +# TARGET_DIR is where the lldb framework/shared library gets put. +# LLVM_BUILD_DIR is where LLVM and Clang got built +# LLVM_BUILD_DIR/lib/clang should exist and contain headers + +import os +import re +import shutil +import sys + +if len(sys.argv) != 3: + print "usage: " + sys.argv[0] + " TARGET_DIR LLVM_BUILD_DIR" + sys.exit(1) + +target_dir = sys.argv[1] +llvm_build_dir = sys.argv[2] + +if not os.path.isdir(target_dir): + print target_dir + " doesn't exist" + sys.exit(1) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-macosx-", "-iphoneos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-iphoneos-", "-appletvos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + llvm_build_dir = re.sub ("-appletvos-", "-watchos-", llvm_build_dir) + +if not os.path.isdir(llvm_build_dir): + print llvm_build_dir + " doesn't exist" + sys.exit(1) + +resources = os.path.join(target_dir, "LLDB.framework", "Resources") + +if not os.path.isdir(resources): + print resources + " must exist" + sys.exit(1) + +clang_dir = os.path.join(llvm_build_dir, "lib", "clang") + +if not os.path.isdir(clang_dir): + print clang_dir + " must exist" + sys.exit(1) + +version_dir = None + +for subdir in os.listdir(clang_dir): + if (re.match("^[0-9]+(\.[0-9]+)*$", subdir)): + version_dir = os.path.join(clang_dir, subdir) + break + +if version_dir == None: + print "Couldn't find a subdirectory of the form #(.#)... in " + clang_dir + sys.exit(1) + +if not os.path.isdir(version_dir): + print version_dir + " is not a directory" + sys.exit(1) + +# Just checking... we're actually going to copy all of version_dir +include_dir = os.path.join(version_dir, "include") + +if not os.path.isdir(include_dir): + print version_dir + " is not a directory" + sys.exit(1) + +clang_resources = os.path.join(resources, "Clang") + +if os.path.isdir(clang_resources): + shutil.rmtree(clang_resources) + +shutil.copytree(version_dir, clang_resources) diff --git a/scripts/prepare_bindings.py b/scripts/prepare_bindings.py new file mode 100755 index 0000000000000..3165f232e5eca --- /dev/null +++ b/scripts/prepare_bindings.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +""" + The LLVM Compiler Infrastructure + +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. + +Prepares language bindings for LLDB build process. Run with --help +to see a description of the supported command line arguments. +""" + +# Python modules: +import argparse +import logging +import os +import platform +import sys + +# LLDB modules: +import use_lldb_suite +from lldbsuite.support import fs + + +def prepare_binding_for_language(scripts_dir, script_lang, options): + """Prepares the binding for a specific language. + + @param scripts_dir the full path to the scripts source directory. + @param script_lang the name of the script language. Should be a child + directory within the scripts dir, and should contain a + prepare_scripts_{script_lang}.py script file in it. + @param options the dictionary of parsed command line options. + + There is no return value. If it returns, the process succeeded; otherwise, + the process will exit where it fails. + """ + # Ensure the language-specific prepare module exists. + script_name = "prepare_binding_{}.py".format(script_lang) + lang_path = os.path.join(scripts_dir, script_lang) + script_path = os.path.join(lang_path, script_name) + if not os.path.exists(script_path): + logging.error( + "failed to find prepare script for language '%s' at '%s'", + script_lang, + script_path) + sys.exit(-9) + + # Include this language-specific directory in the Python search + # path. + sys.path.append(os.path.normcase(lang_path)) + + # Execute the specific language script + module_name = os.path.splitext(script_name)[0] + module = __import__(module_name) + module.main(options) + + # Remove the language-specific directory from the Python search path. + sys.path.remove(os.path.normcase(lang_path)) + + +def prepare_all_bindings(options): + """Prepares bindings for each of the languages supported. + + @param options the parsed arguments from the command line + + @return the exit value for the program. 0 is success, all othes + indicate some kind of failure. + """ + # Check for the existence of the SWIG scripts folder + scripts_dir = os.path.join(options.src_root, "scripts") + if not os.path.exists(scripts_dir): + logging.error("failed to find scripts dir: '%s'", scripts_dir) + sys.exit(-8) + + child_dirs = ["Python"] + + # Iterate script directory find any script language directories + for script_lang in child_dirs: + logging.info("executing language script for: '%s'", script_lang) + prepare_binding_for_language(scripts_dir, script_lang, options) + + +def process_args(args): + """Returns options processed from the provided command line. + + @param args the command line to process. + """ + + # Setup the parser arguments that are accepted. + parser = argparse.ArgumentParser( + description="Prepare language bindings for LLDB build.") + + # Arguments to control logging verbosity. + parser.add_argument( + "--debug", "-d", + action="store_true", + help="Set program logging level to DEBUG.") + parser.add_argument( + "--verbose", "-v", + action="count", + default=0, + help=( + "Increase logging verbosity level. Default: only error and " + "higher are displayed. Each -v increases level of verbosity.")) + + # Arguments to control whether we're building an OS X-style + # framework. This is the opposite of the older "-m" (makefile) + # option. + parser.add_argument( + "--config-build-dir", + "--cfgBldDir", + help=( + "Configuration build dir, will use python module path " + "if unspecified.")) + parser.add_argument( + "--find-swig", + action="store_true", + help=( + "Indicates the swig executable should be searched for " + "if not eplicitly provided. Either this or the explicit " + "swig executable option must be provided.")) + parser.add_argument( + "--framework", + action="store_true", + help="Prepare as OS X-style framework.") + parser.add_argument( + "--generate-dependency-file", + "-M", + action="store_true", + help="Make the dependency (.d) file for the wrappers.") + parser.add_argument( + "--prefix", + help="Override path where the LLDB module is placed.") + parser.add_argument( + "--src-root", + "--srcRoot", + "-s", + # Default to the parent directory of this script's directory. + default=os.path.abspath( + os.path.join( + os.path.dirname(os.path.realpath(__file__)), + os.path.pardir)), + help="Specifies the LLDB source root directory.") + parser.add_argument( + "--swig-executable", + "--swigExecutable", + help="Path to the swig executable.") + parser.add_argument( + "--target-dir", + "--targetDir", + required=True, + help=( + "Specifies the build dir where the language binding " + "should be placed")) + + # Process args. + options = parser.parse_args(args) + + # Set logging level based on verbosity count. + if options.debug: + log_level = logging.DEBUG + else: + # See logging documentation for error levels. We'll default + # to showing ERROR or higher error messages. For each -v + # specified, we'll shift to the next lower-priority log level. + log_level = logging.ERROR - 10 * options.verbose + if log_level < logging.NOTSET: + # Displays all logged messages. + log_level = logging.NOTSET + logging.basicConfig(level=log_level) + logging.info("logging is using level: %d", log_level) + + return options + + +def main(args): + """Drives the main script preparation steps. + + @param args list of command line arguments. + """ + # Process command line arguments. + options = process_args(args) + logging.debug("Processed args: options=%s", options) + + # Ensure we have a swig executable. + if not options.swig_executable or len(options.swig_executable) == 0: + if options.find_swig: + try: + options.swig_executable = fs.find_executable("swig") + except Exception as e: + logging.error("Unable to find swig executable: %s" % e.message) + sys.exit(-6) + else: + logging.error( + "The --find-swig option must be specified " + "when the swig executable location is not " + "explicitly provided.") + sys.exit(-12) + + # Check if the swig file exists. + swig_path = os.path.normcase( + os.path.join(options.src_root, "scripts", "lldb.swig")) + if not os.path.isfile(swig_path): + logging.error("swig file not found at '%s'", swig_path) + sys.exit(-3) + + # Prepare bindings for each supported language binding. + # This will error out if it doesn't succeed. + prepare_all_bindings(options) + sys.exit(0) + +if __name__ == "__main__": + # Run the main driver loop. + main(sys.argv[1:]) diff --git a/scripts/sed-sources b/scripts/sed-sources new file mode 100755 index 0000000000000..c67fb3319adb1 --- /dev/null +++ b/scripts/sed-sources @@ -0,0 +1,251 @@ +#!/usr/bin/perl + +use strict; +use File::Find; +use File::Temp qw/ tempfile tempdir /; +use Getopt::Std; +use Pod::Usage; +use Text::Tabs; + +=head1 NAME + +B<sed-sources> -- Performs multiple sed commands on files with the ability to expand or unexpand tabs. + +=head1 SYNOPSIS + +B<sed-sources> [options] [file dir ...] + +=head1 DESCRIPTION + +Performs multiple sed commands (modify builtin %seds hash) on source files +or any sources in directories. If no arguments are given, STDIN will be used +as the source. If source files or directories are specified as arguments, +all files will be transformed and overwritten with new versions. Use the B<-p> +option to preview changes to STDOUT, or use the B<-b> option to make a backup +or the original files. + +=head1 OPTIONS + +=over + +=item B<-b> + +Backup original source file by appending ".bak" before overwriting with the +newly transformed file. + +=item B<-g> + +Display verbose debug logging. + +=item B<-e> + +Expand tabs to spaces (in addition to doing sed substitutions). + +=item B<-u> + +Unexpand spaces to tabs (in addition to doing sed substitutions). + +=item B<-p> + +Preview changes to STDOUT without modifying original source files. + +=item B<-r> + +Skip variants when doing multiple files (no _profile or _debug variants). + +=item B<-t N> + +Set the number of spaces per tab (default is 4) to use when expanding or +unexpanding. + +=back + +=head1 EXAMPLES + +# Recursively process all source files in the current working directory +# and subdirectories and also expand tabs to spaces. All source files +# will be overwritten with the newly transformed source files. + +% sed-sources -e $cwd + +# Recursively process all source files in the current working directory +# and subdirectories and also unexpand spaces to tabs and preview the +# results to STDOUT + +% sed-sources -p -u $cwd + +# Same as above except use 8 spaces per tab. + +% sed-sources -p -u -t8 $cwd + +=cut + + +our $opt_b = 0; # Backup original file? +our $opt_g = 0; # Verbose debug output? +our $opt_e = 0; # Expand tabs to spaces? +our $opt_h = 0; # Show help? +our $opt_m = 0; # Show help manpage style? +our $opt_p = 0; # Preview changes to STDOUT? +our $opt_t = 4; # Number of spaces per tab? +our $opt_u = 0; # Unexpand spaces to tabs? +getopts('eghmpt:u'); + +$opt_m and show_manpage(); +$opt_h and help(); + +our %seds = ( + '\s+$' => "\n", # Get rid of spaces at the end of a line + '^\s+$' => "\n", # Get rid spaces on lines that are all spaces +); + + +sub show_manpage { exit pod2usage( verbose => 2 ); }; +sub help { exit pod2usage( verbose => 3, noperldoc => 1 ); }; + + +#---------------------------------------------------------------------- +# process_opened_file_handle +#---------------------------------------------------------------------- +sub process_opened_file_handle +{ + my $in_fh = shift; + my $out_fh = shift; + + # Set the number of spaces per tab for expand/unexpand + $tabstop = $opt_t; + + while (my $line = <$in_fh>) + { + foreach my $key (keys %seds) + { + my $value = $seds{"$key"}; + $line =~ s/$key/$value/g; + } + if ($opt_e) { + print $out_fh expand $line; + } elsif ($opt_u) { + print $out_fh unexpand $line; + } else { + print $out_fh $line; + } + } +} + +#---------------------------------------------------------------------- +# process_file +#---------------------------------------------------------------------- +sub process_file +{ + my $in_path = shift; + if (-T $in_path) + { + my $out_fh; + my $out_path; + if ($opt_p) + { + # Preview to STDOUT + $out_fh = *STDOUT; + print "#---------------------------------------------------------------------- \n"; + print "# BEGIN: '$in_path'\n"; + print "#---------------------------------------------------------------------- \n"; + } + else + { + ($out_fh, $out_path) = tempfile(); + $opt_g and print "temporary for '$in_path' is '$out_path'\n"; + } + open (IN, "<$in_path") or die "error: can't open '$in_path' for reading: $!"; + process_opened_file_handle (*IN, $out_fh); + + + # Close our input file + close (IN); + + if ($opt_p) + { + print "#---------------------------------------------------------------------- \n"; + print "# END: '$in_path'\n"; + print "#---------------------------------------------------------------------- \n"; + print "\n\n"; + } + else + { + # Close the output file if it wasn't STDOUT + close ($out_fh); + + # Backup file if requested + if ($opt_b) + { + my $backup_command = "cp '$in_path' '$in_path.bak'"; + $opt_g and print "\% $backup_command\n"; + system ($backup_command); + } + + # Copy temp file over original + my $copy_command = "cp '$out_path' '$in_path'"; + $opt_g and print "\% $copy_command\n"; + system ($copy_command); + } + } +} + +our @valid_extensions = ( "h", "cpp", "c", "m", "mm" ); + +#---------------------------------------------------------------------- +# find_callback +#---------------------------------------------------------------------- +sub find_callback +{ + my $file = $_; + my $fullpath = $File::Find::name; + + foreach my $ext (@valid_extensions) + { + my $ext_regex = "\\.$ext\$"; + if ($fullpath =~ /$ext_regex/i) + { + print "processing: '$fullpath'\n"; + process_file ($fullpath); + return; + } + } + print " ignoring: '$fullpath'\n"; +} + + +#---------------------------------------------------------------------- +# main +#---------------------------------------------------------------------- +sub main +{ + if (@ARGV == 0) + { + # no args, take from STDIN and put to STDOUT + process_opened_file_handle (*STDIN, *STDOUT); + } + else + { + # Got args, any files we run into parse them, any directories + # we run into, search them for files + my $path; + foreach $path (@ARGV) + { + if (-f $path) + { + print "processing: '$path'\n"; + process_file ($path); + } + else + { + print " searching: '$path'\n"; + find(\&find_callback, $path); + } + } + } +} + + + +# call the main function +main(); diff --git a/scripts/shush b/scripts/shush new file mode 100755 index 0000000000000..a2dd6c8c58d02 --- /dev/null +++ b/scripts/shush @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +import sys +import subprocess +import tempfile +import time +import os + +class Printer(object): + def __init__(self): + pass + + @classmethod + def write(self, message): + sys.stdout.write("%s\n" % message) + sys.stdout.flush() + +def command(): + return ' '.join(sys.argv[1:]) + +def tmpfile(suffix=None): + if suffix is None: suffix = "" + return tempfile.NamedTemporaryFile(prefix='shush', suffix=suffix, delete=False) + +def launch(cmd="/bin/ls", sin=None, sout=None): + class Process(object): + def __init__(self, p, i, o): + self.p = p + self.stdin = i + self.stdout = o + + def poll(self): + self.returncode = self.p.poll() + return self.returncode + + return Process(subprocess.Popen(cmd, shell=True, stdin=sin, stdout=sout, stderr=subprocess.STDOUT), sin, sout) + +def wait(p): + while p.poll() is None: + time.sleep(5) + Printer.write("still running @ %s..." % time.strftime("%Y%m%d%H%M%S")) # fool Xcode into thinking that I am doing something... + return p + +def exit(p): + code = p.returncode + if code != 0: + Printer.write("error: sucks to be you") + Printer.write("error: shushed process failed - go check %s for details" % (p.stdout.name)) + else: + Printer.write("shush: success - output is going away") + try: + os.remove(p.stdout.name) + finally: + pass + sys.exit(code) + +def main(): + out = tmpfile() + cmd = command() + Printer.write("shush: launching '%s' - std{out|err}=%s" % (cmd, out.name)) + p = wait(launch(cmd=cmd, sout=out)) + exit(p) + +main() diff --git a/scripts/swig_bot.py b/scripts/swig_bot.py new file mode 100644 index 0000000000000..95f4eb8d71b10 --- /dev/null +++ b/scripts/swig_bot.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python + +""" +SWIG generation top-level script. Supports both local and remote generation +of SWIG bindings for multiple languages. +""" + +# Python modules +import argparse +import logging +import sys +import traceback + +# LLDB modules +import use_lldb_suite + +# swig_bot modules +from swig_bot_lib import client +from swig_bot_lib import server + +def process_args(args): + parser = argparse.ArgumentParser( + description='Run swig-bot client or server.') + + # Create and populate subparser arguments for when swig_bot is + # run in client or server mode + subparsers = parser.add_subparsers( + help="Pass --help to a sub-command to print detailed usage") + client_parser = subparsers.add_parser("client", + help="Run SWIG generation client") + client.add_subparser_args(client_parser) + client_parser.set_defaults(func=run_client) + + server_parser = subparsers.add_parser("server", + help="Run SWIG generation server") + server.add_subparser_args(server_parser) + server_parser.set_defaults(func=run_server) + + # Arguments to control logging verbosity. + parser.add_argument( + "--verbose", "-v", + action="store_true", + default=False, + help="Increase logging verbosity level.") + + options = parser.parse_args(args) + # Set logging level. + if options.verbose: + log_level = logging.DEBUG + else: + log_level = logging.NOTSET + logging.basicConfig(level=log_level) + logging.info("logging is using level: %d", log_level) + + return options + +def run_client(options): + logging.info("Running swig_bot in client mode") + client.finalize_subparser_options(options) + client.run(options) + +def run_server(options): + logging.info("Running swig_bot in server mode") + server.finalize_subparser_options(options) + server.run(options) + +if __name__ == "__main__": + options = process_args(sys.argv[1:]) + try: + if options.func is None: + logging.error("Unknown mode specified. Expected client or server.") + sys.exit(-1) + else: + options.func(options) + except KeyboardInterrupt as e: + logging.info("Ctrl+C received. Shutting down...") + sys.exit(-1) + except Exception as e: + error = traceback.format_exc() + logging.error("An error occurred running swig-bot.") + logging.error(error) diff --git a/scripts/swig_bot_lib/__init__.py b/scripts/swig_bot_lib/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d --- /dev/null +++ b/scripts/swig_bot_lib/__init__.py diff --git a/scripts/swig_bot_lib/client.py b/scripts/swig_bot_lib/client.py new file mode 100644 index 0000000000000..9bf55b42b666e --- /dev/null +++ b/scripts/swig_bot_lib/client.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python + +""" +SWIG generation client. Supports both local and remote generation of SWIG +bindings for multiple languages. +""" + +# Future imports +from __future__ import absolute_import +from __future__ import print_function + +# Python modules +import argparse +import io +import logging +import os +import socket +import struct +import sys + +# LLDB modules +import use_lldb_suite +from lldbsuite.support import fs +from lldbsuite.support import sockutil + +# package imports +from . import local +from . import remote + +default_ip = "127.0.0.1" +default_port = 8537 + +def add_subparser_args(parser): + """Returns options processed from the provided command line. + + @param args the command line to process. + """ + + # A custom action used by the --local command line option. It can be + # used with either 0 or 1 argument. If used with 0 arguments, it + # searches for a copy of swig located on the physical machine. If + # used with 1 argument, the argument is the path to a swig executable. + class FindLocalSwigAction(argparse.Action): + def __init__(self, option_strings, dest, **kwargs): + super(FindLocalSwigAction, self).__init__( + option_strings, dest, nargs='?', **kwargs) + def __call__(self, parser, namespace, values, option_string=None): + swig_exe = None + if values is None: + swig_exe = fs.find_executable('swig') + else: + swig_exe = values + setattr(namespace, self.dest, os.path.normpath(swig_exe)) + + # A custom action used by the --remote command line option. It can be + # used with either 0 or 1 arguments. If used with 0 arguments it chooses + # a default connection string. If used with one argument it is a string + # of the form `ip_address[:port]`. If the port is unspecified, the + # default port is used. + class RemoteIpAction(argparse.Action): + def __init__(self, option_strings, dest, **kwargs): + super(RemoteIpAction, self).__init__( + option_strings, dest, nargs='?', **kwargs) + def __call__(self, parser, namespace, values, option_string=None): + ip_port = None + if values is None: + ip_port = (default_ip, default_port) + else: + result = values.split(':') + if len(result)==1: + ip_port = (result[0], default_port) + elif len(result)==2: + ip_port = (result[0], int(result[1])) + else: + raise ValueError("Invalid connection string") + setattr(namespace, self.dest, ip_port) + + parser.add_argument( + "--local", + action=FindLocalSwigAction, + dest="swig_executable", + help=( + "Run the copy of swig at the specified location, or search PATH" + "if the location is omitted")) + + parser.add_argument( + "--remote", + action=RemoteIpAction, + help=( + "Use the given connection string to connect to a remote " + "generation service")) + + parser.add_argument( + "--src-root", + required=True, + help="The root folder of the LLDB source tree.") + + parser.add_argument( + "--target-dir", + default=os.getcwd(), + help=( + "Specifies the build dir where the language binding " + "should be placed")) + + parser.add_argument( + "--language", + dest="languages", + action="append", + help="Specifies the language to generate bindings for") + +def finalize_subparser_options(options): + if options.languages is None: + options.languages = ['python'] + + if options.remote is None and options.swig_executable is None: + logging.error("Must specify either --local or --remote") + sys.exit(-3) + + return options + +def establish_remote_connection(ip_port): + logging.debug("Creating socket...") + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + logging.info("Connecting to server {} on port {}" + .format(ip_port[0], ip_port[1])) + s.connect(ip_port) + logging.info("Connection established...") + return s + +def transmit_request(connection, packed_input): + logging.info("Sending {} bytes of compressed data." + .format(len(packed_input))) + connection.sendall(struct.pack("!I", len(packed_input))) + connection.sendall(packed_input) + logging.info("Awaiting response.") + response_len = struct.unpack("!I", sockutil.recvall(connection, 4))[0] + logging.debug("Expecting {} byte response".format(response_len)) + response = sockutil.recvall(connection, response_len) + return response + +def handle_response(options, connection, response): + logging.debug("Received {} byte response.".format(len(response))) + logging.debug("Creating output directory {}" + .format(options.target_dir)) + os.makedirs(options.target_dir, exist_ok=True) + + logging.info("Unpacking response archive into {}" + .format(options.target_dir)) + local.unpack_archive(options.target_dir, response) + response_file_path = os.path.normpath( + os.path.join(options.target_dir, "swig_output.json")) + if not os.path.isfile(response_file_path): + logging.error("Response file '{}' does not exist." + .format(response_file_path)) + return + try: + response = remote.deserialize_response_status( + io.open(response_file_path)) + if response[0] != 0: + logging.error("An error occurred during generation. Status={}" + .format(response[0])) + logging.error(response[1]) + else: + logging.info("SWIG generation successful.") + if len(response[1]) > 0: + logging.info(response[1]) + finally: + os.unlink(response_file_path) + +def run(options): + if options.remote is None: + logging.info("swig bot client using local swig installation at '{}'" + .format(options.swig_executable)) + if not os.path.isfile(options.swig_executable): + logging.error("Swig executable '{}' does not exist." + .format(options.swig_executable)) + config = local.LocalConfig() + config.languages = options.languages + config.src_root = options.src_root + config.target_dir = options.target_dir + config.swig_executable = options.swig_executable + local.generate(config) + else: + logging.info("swig bot client using remote generation with server '{}'" + .format(options.remote)) + connection = None + try: + config = remote.generate_config(options.languages) + logging.debug("Generated config json {}".format(config)) + inputs = [("include/lldb", ".h"), + ("include/lldb/API", ".h"), + ("scripts", ".swig"), + ("scripts/Python", ".swig"), + ("scripts/interface", ".i")] + zip_data = io.BytesIO() + packed_input = local.pack_archive(zip_data, options.src_root, inputs) + logging.info("(null) -> config.json") + packed_input.writestr("config.json", config) + packed_input.close() + connection = establish_remote_connection(options.remote) + response = transmit_request(connection, zip_data.getvalue()) + handle_response(options, connection, response) + finally: + if connection is not None: + connection.close()
\ No newline at end of file diff --git a/scripts/swig_bot_lib/local.py b/scripts/swig_bot_lib/local.py new file mode 100644 index 0000000000000..7cca0b3cabbb8 --- /dev/null +++ b/scripts/swig_bot_lib/local.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +""" +Shared functionality used by `client` and `server` when generating or preparing +to generate SWIG on the local machine. +""" + +# Future imports +from __future__ import absolute_import +from __future__ import print_function + +# Python modules +import argparse +import imp +import io +import logging +import os +import subprocess +import sys +import tempfile +import zipfile + +# LLDB modules +import use_lldb_suite + +# Package imports +from lldbsuite.support import fs + +class LocalConfig(object): + src_root = None + target_dir = None + languages = None + swig_executable = None + +def pack_archive(bytes_io, src_root, filters): + logging.info("Creating input file package...") + zip_file = None + try: + # It's possible that a custom-built interpreter will not have the + # standard zlib module. If so, we can only store, not compress. By + # try to compress since we usually have a standard Python distribution. + zip_file = zipfile.ZipFile(bytes_io, mode='w', + compression=zipfile.ZIP_DEFLATED) + except RuntimeError: + zip_file = zipfile.ZipFile(bytes_io, mode='w', + compression=zipfile.ZIP_STORED) + archive_entries = [] + if filters is not None: + def filter_func(t): + subfolder = t[0] + ext = t[1] + full_path = os.path.normpath(os.path.join(src_root, subfolder)) + candidates = [os.path.normpath(os.path.join(full_path, f)) + for f in os.listdir(full_path)] + actual = filter( + lambda f : os.path.isfile(f) and os.path.splitext(f)[1] == ext, + candidates) + return (subfolder, map(lambda f : os.path.basename(f), actual)) + archive_entries = map(filter_func, filters) + else: + for (root, dirs, files) in os.walk(src_root): + logging.debug("Adding files {} from directory {} to output package" + .format(files, root)) + if len(files) > 0: + rel_root = os.path.relpath(root, src_root) + archive_entries.append((rel_root, files)) + + archive_entries = list(archive_entries) + for entry in archive_entries: + subfolder = entry[0] + files = list(entry[1]) + for file in files: + rel_path = os.path.normpath(os.path.join(subfolder, file)) + full_path = os.path.join(src_root, rel_path) + logging.info("{} -> {}".format(full_path, rel_path)) + zip_file.write(full_path, rel_path) + + return zip_file + +def unpack_archive(folder, archive_bytes): + zip_data = io.BytesIO(archive_bytes) + logging.debug("Opening zip archive...") + zip_file = zipfile.ZipFile(zip_data, mode='r') + zip_file.extractall(folder) + zip_file.close() + +def generate(options): + include_folder = os.path.join(options.src_root, "include") + in_file = os.path.join(options.src_root, "scripts", "lldb.swig") + include_folder = os.path.normcase(include_folder) + + for lang in options.languages: + lang = lang.lower() + out_dir = os.path.join(options.target_dir, lang.title()) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + out_file = os.path.join(out_dir, "LLDBWrap{}.cpp".format(lang.title())) + swig_command = [ + options.swig_executable, + "-c++", + ] + swig_command.append("-" + lang) + if lang == "python": + swig_command.append("-threads") + + swig_command.extend([ + "-I" + include_folder, + "-D__STDC_LIMIT_MACROS", + "-D__STDC_CONSTANT_MACROS", + "-outdir", out_dir, + "-o", out_file, + in_file + ]) + + logging.info("generating swig {} bindings into {}" + .format(lang, out_dir)) + logging.debug("swig command line: {}".format(swig_command)) + try: + # Execute swig + swig_output = subprocess.check_output( + swig_command, stderr=subprocess.STDOUT, universal_newlines=True) + + logging.info("swig generation succeeded") + if swig_output is not None and len(swig_output) > 0: + logging.info("swig output: %s", swig_output) + return (0, swig_output) + except subprocess.CalledProcessError as e: + logging.error("An error occurred executing swig. returncode={}" + .format(e.returncode)) + logging.error(e.output) + return (e.returncode, e.output)
\ No newline at end of file diff --git a/scripts/swig_bot_lib/remote.py b/scripts/swig_bot_lib/remote.py new file mode 100644 index 0000000000000..590a873d62704 --- /dev/null +++ b/scripts/swig_bot_lib/remote.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +Shared functionality used by `client` and `server` when dealing with +remote transmission +""" + +# Future imports +from __future__ import absolute_import +from __future__ import print_function + +# Python modules +import json +import logging +import os +import socket +import struct +import sys + +# LLDB modules +import use_lldb_suite + +def generate_config(languages): + config = {"languages": languages} + return json.dumps(config) + +def parse_config(json_reader): + json_data = json_reader.read() + options_dict = json.loads(json_data) + return options_dict + +def serialize_response_status(status): + status = {"retcode": status[0], "output": status[1]} + return json.dumps(status) + +def deserialize_response_status(json_reader): + json_data = json_reader.read() + response_dict = json.loads(json_data) + return (response_dict["retcode"], response_dict["output"]) diff --git a/scripts/swig_bot_lib/server.py b/scripts/swig_bot_lib/server.py new file mode 100644 index 0000000000000..cc25cee4d4b1a --- /dev/null +++ b/scripts/swig_bot_lib/server.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +""" +SWIG generation server. Listens for connections from swig generation clients +and runs swig in the requested fashion, sending back the results. +""" + +# Future imports +from __future__ import absolute_import +from __future__ import print_function + +# Python modules +import argparse +import io +import logging +import os +import select +import shutil +import socket +import struct +import sys +import tempfile +import traceback + +# LLDB modules +import use_lldb_suite +from lldbsuite.support import fs +from lldbsuite.support import sockutil + +# package imports +from . import local +from . import remote + +default_port = 8537 + +def add_subparser_args(parser): + parser.add_argument( + "--port", + action="store", + default=default_port, + help=("The local port to bind to")) + + parser.add_argument( + "--swig-executable", + action="store", + default=fs.find_executable("swig"), + dest="swig_executable") + +def finalize_subparser_options(options): + pass + +def initialize_listening_socket(options): + logging.debug("Creating socket...") + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + logging.info("Binding to ip address '', port {}".format(options.port)) + s.bind(('', options.port)) + + logging.debug("Putting socket in listen mode...") + s.listen() + return s + +def accept_once(sock, options): + logging.debug("Waiting for connection...") + while True: + rlist, wlist, xlist = select.select([sock], [], [], 0.5) + if not rlist: + continue + + client, addr = sock.accept() + logging.info("Received connection from {}".format(addr)) + data_size = struct.unpack("!I", sockutil.recvall(client, 4))[0] + logging.debug("Expecting {} bytes of data from client" + .format(data_size)) + data = sockutil.recvall(client, data_size) + logging.info("Received {} bytes of data from client" + .format(len(data))) + + pack_location = None + try: + tempfolder = os.path.join(tempfile.gettempdir(), "swig-bot") + os.makedirs(tempfolder, exist_ok=True) + + pack_location = tempfile.mkdtemp(dir=tempfolder) + logging.debug("Extracting archive to {}".format(pack_location)) + + local.unpack_archive(pack_location, data) + logging.debug("Successfully unpacked archive...") + + config_file = os.path.normpath(os.path.join(pack_location, + "config.json")) + parsed_config = remote.parse_config(io.open(config_file)) + config = local.LocalConfig() + config.languages = parsed_config["languages"] + config.swig_executable = options.swig_executable + config.src_root = pack_location + config.target_dir = os.path.normpath( + os.path.join(config.src_root, "output")) + logging.info( + "Running swig. languages={}, swig={}, src_root={}, target={}" + .format(config.languages, config.swig_executable, + config.src_root, config.target_dir)) + + status = local.generate(config) + logging.debug("Finished running swig. Packaging up files {}" + .format(os.listdir(config.target_dir))) + zip_data = io.BytesIO() + zip_file = local.pack_archive(zip_data, config.target_dir, None) + response_status = remote.serialize_response_status(status) + logging.debug("Sending response status {}".format(response_status)) + logging.info("(swig output) -> swig_output.json") + zip_file.writestr("swig_output.json", response_status) + + zip_file.close() + response_data = zip_data.getvalue() + logging.info("Sending {} byte response".format(len(response_data))) + client.sendall(struct.pack("!I", len(response_data))) + client.sendall(response_data) + finally: + if pack_location is not None: + logging.debug("Removing temporary folder {}" + .format(pack_location)) + shutil.rmtree(pack_location) + +def accept_loop(sock, options): + while True: + try: + accept_once(sock, options) + except Exception as e: + error = traceback.format_exc() + logging.error("An error occurred while processing the connection.") + logging.error(error) + +def run(options): + print(options) + sock = initialize_listening_socket(options) + accept_loop(sock, options) + return options diff --git a/scripts/use_lldb_suite.py b/scripts/use_lldb_suite.py new file mode 100644 index 0000000000000..63a098cea220f --- /dev/null +++ b/scripts/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) diff --git a/scripts/utilsArgsParse.py b/scripts/utilsArgsParse.py new file mode 100644 index 0000000000000..e762edccc30d5 --- /dev/null +++ b/scripts/utilsArgsParse.py @@ -0,0 +1,139 @@ +""" Utility module handle program args and give help + + -------------------------------------------------------------------------- + File: utilsArgsParse.py + + Overview: Python module to parse and validate program parameters + against those required by the program whether mandatory + or optional. + Also give help information on arguments required by the + program. + + Gotchas: None. + + Copyright: None. + -------------------------------------------------------------------------- + +""" + +# Python modules: +import getopt # Parse command line arguments + +# Third party modules: + +# In-house modules: + +# Instantiations: + +# User facing text: +strMsgErrorInvalidParameters = "Invalid parameters entered, -h for help. \nYou entered:\n" +strMsgErrorInvalidNoParams = "No parameters entered, -h for help\n" +strMsgErrorNumberParameters = "Number of parameters entered incorrect, %d parameters required. You entered:\n" +strMsgArgFileNotImplemented = "Sorry the --argFile is not implemented" + +#++--------------------------------------------------------------------------- +# Details: Validate the arguments passed in against the mandatory and +# optional arguments specified. The argument format for the parameters +# is required to work with the module getopt function getopt(). +# Parameter vDictArgReq specifies which parameters are mandatory and +# which are optional. The format is for example: +# dictArgReq = {"-h": "o", # o = optional, m = mandatory +# "-m": "m", +# "--targetDir": "m", +# "--cfgBldDir": "o" } +# Args: vArgv - (R) List of arguments and values. +# vstrListArgs - (R) List of small arguments. +# vListLongArgs - (R) List of long arguments. +# vDictArgReq - (R) Map of arguments required. +# vstrHelpInfo - (R) Formatted help text. +# Returns: Int - 0 success. +# 1 success display information, do nothing else. +# -1 error invalid parameters. +# -2 error incorrect number of mandatory parameters. +# Dict - Map of arguments names to argument values +# Str - Error message. +# Throws: None. +#-- +def parse(vArgv, vstrListArgs, vListLongArgs, vDictArgReq, vstrHelpInfo): + dictArgs = {} + dictDummy = {} + strDummy = "" + + # Validate parameters above and error on not recognised + try: + dictOptsNeeded, dictArgsLeftOver = getopt.getopt(vArgv, + vstrListArgs, + vListLongArgs) + except getopt.GetoptError: + strMsg = strMsgErrorInvalidParameters + strMsg += str(vArgv) + return (-1, dictDummy, strMsg) + + if len(dictOptsNeeded) == 0: + strMsg = strMsgErrorInvalidNoParams + return (-1, dictDummy, strMsg) + + # Look for help -h before anything else + for opt, arg in dictOptsNeeded: + if opt == '-h': + return (1, dictDummy, vstrHelpInfo) + + # Look for the --argFile if found ignore other command line arguments + for opt, arg in dictOptsNeeded: + if opt == '--argsFile': + return (1, dictDummy, strMsgArgFileNotImplemented) + + # Count the number of mandatory args required (if any one found) + countMandatory = 0 + for opt, man in list(vDictArgReq.items()): + if man == "m": + countMandatory = countMandatory + 1 + + # Extract short args + listArgs = [] + for arg in vstrListArgs: + if (arg == '-h') or (arg == ':'): + continue + listArgs.append(arg) + + # Append to arg dictionary the option and its value + bFoundNoInputValue = False + countMandatoryOpts = 0 + for opt, val in dictOptsNeeded: + match = 0 + for arg in listArgs: + argg = "-" + arg + if opt == argg: + if "m" == vDictArgReq[opt]: + countMandatoryOpts = countMandatoryOpts + 1 + dictArgs[opt] = val + match = 1 + break + if match == 0: + for arg in vListLongArgs: + argg = "--" + arg[:arg.__len__() - 1] + if opt == argg: + if "m" == vDictArgReq[opt]: + countMandatoryOpts = countMandatoryOpts + 1 + dictArgs[opt] = val + if val.__len__() == 0: + bFoundNoInputValue = True + break + + # Do any of the long arguments not have a value attached + if bFoundNoInputValue: + strMsg = strMsgErrorInvalidParameters + strMsg += str(vArgv) + return (-1, dictDummy, strMsg) + + # Debug only + #print countMandatoryOpts + #print countMandatory + + # Do we have the exact number of mandatory arguments + if (countMandatoryOpts > 0) and (countMandatory != countMandatoryOpts): + strMsg = strMsgErrorNumberParameters % countMandatory + strMsg += str(vArgv) + return (-2, dictDummy, strMsg) + + return (0, dictArgs, strDummy) diff --git a/scripts/utilsDebug.py b/scripts/utilsDebug.py new file mode 100644 index 0000000000000..4b5eb7fa3e706 --- /dev/null +++ b/scripts/utilsDebug.py @@ -0,0 +1,120 @@ +""" Utility module to help debug Python scripts + + -------------------------------------------------------------------------- + File: utilsDebug.py + + Overview: Python module to supply functions to help debug Python + scripts. + Gotchas: None. + Copyright: None. + -------------------------------------------------------------------------- +""" + +# Python modules: +import sys + +# Third party modules: + +# In-house modules: + +# Instantiations: + +#----------------------------------------------------------------------------- +# Details: Class to implement simple stack function trace. Instantiation the +# class as the first function you want to trace. Example: +# obj = utilsDebug.CDebugFnVerbose("validate_arguments()") +# Gotchas: This class will not work in properly in a multi-threaded +# environment. +# Authors: Illya Rudkin 28/11/2013. +# Changes: None. +#-- +class CDebugFnVerbose(object): + # Public static properties: + bVerboseOn = False # True = turn on function tracing, False = turn off. + + # Public: + #++------------------------------------------------------------------------ + # Details: CDebugFnVerbose constructor. + # Type: Method. + # Args: vstrFnName - (R) Text description i.e. a function name. + # Return: None. + # Throws: None. + #-- + # CDebugFnVerbose(vstrFnName) + + #++------------------------------------------------------------------------ + # Details: Print out information on the object specified. + # Type: Method. + # Args: vstrText - (R) Some helper text description. + # vObject - (R) Some Python type object. + # Return: None. + # Throws: None. + #-- + def dump_object(self, vstrText, vObject): + if CDebugFnVerbose.bVerboseOn == False: + return + sys.stdout.write("%d%s> Dp: %s" % (CDebugFnVerbose.__nLevel, self.__get_dots(), + vstrText)) + print(vObject) + + #++------------------------------------------------------------------------ + # Details: Print out some progress text given by the client. + # Type: Method. + # Args: vstrText - (R) Some helper text description. + # Return: None. + # Throws: None. + #-- + def dump_text(self, vstrText): + if CDebugFnVerbose.bVerboseOn == False: + return + print(("%d%s> Dp: %s" % (CDebugFnVerbose.__nLevel, self.__get_dots(), + vstrText))) + + # Private methods: + def __init__(self, vstrFnName): + self.__indent_out(vstrFnName) + + #++------------------------------------------------------------------------ + # Details: Build an indentation string of dots based on the __nLevel. + # Type: Method. + # Args: None. + # Return: Str - variable length string. + # Throws: None. + #-- + def __get_dots(self): + return "".join("." for i in range(0, CDebugFnVerbose.__nLevel)) + + #++------------------------------------------------------------------------ + # Details: Build and print out debug verbosity text indicating the function + # just exited from. + # Type: Method. + # Args: None. + # Return: None. + # Throws: None. + #-- + def __indent_back(self): + if CDebugFnVerbose.bVerboseOn: + print(("%d%s< fn: %s" % (CDebugFnVerbose.__nLevel, self.__get_dots(), + self.__strFnName))) + CDebugFnVerbose.__nLevel -= 1 + + #++------------------------------------------------------------------------ + # Details: Build and print out debug verbosity text indicating the function + # just entered. + # Type: Method. + # Args: vstrFnName - (R) Name of the function entered. + # Return: None. + # Throws: None. + #-- + def __indent_out(self, vstrFnName): + CDebugFnVerbose.__nLevel += 1 + self.__strFnName = vstrFnName + if CDebugFnVerbose.bVerboseOn: + print(("%d%s> fn: %s" % (CDebugFnVerbose.__nLevel, self.__get_dots(), + self.__strFnName))) + + # Private statics attributes: + __nLevel = 0 # Indentation level counter + + # Private attributes: + __strFnName = "" diff --git a/scripts/utilsOsType.py b/scripts/utilsOsType.py new file mode 100644 index 0000000000000..a2f0563bf8951 --- /dev/null +++ b/scripts/utilsOsType.py @@ -0,0 +1,90 @@ +""" Utility module to determine the OS Python running on + + -------------------------------------------------------------------------- + File: utilsOsType.py + + Overview: Python module to supply functions and an enumeration to + help determine the platform type, bit size and OS currently + being used. + -------------------------------------------------------------------------- + +""" + +# Python modules: +import sys # Provide system information + +# Third party modules: + +# In-house modules: + +# Instantiations: + +# Enumerations: +#----------------------------------------------------------------------------- +# Details: Class to implement a 'C' style enumeration type. +# Gotchas: None. +# Authors: Illya Rudkin 28/11/2013. +# Changes: None. +#-- +if sys.version_info.major >= 3: + from enum import Enum + class EnumOsType(Enum): + Unknown = 0 + Darwin = 1 + FreeBSD = 2 + Linux = 3 + NetBSD = 4 + Windows = 5 +else: + class EnumOsType(object): + values = ["Unknown", + "Darwin", + "FreeBSD", + "Linux", + "NetBSD", + "Windows"] + class __metaclass__(type): +#++--------------------------------------------------------------------------- +# Details: Fn acts as an enumeration. +# Args: vName - (R) Enumeration to match. +# Returns: Int - Matching enumeration/index. +# Throws: None. +#-- + def __getattr__(cls, vName): + return cls.values.index(vName) + +#++--------------------------------------------------------------------------- +# Details: Reverse fast lookup of the values list. +# Args: vI - (R) Index / enumeration. +# Returns: Str - text description matching enumeration. +# Throws: None. +#-- + def name_of(cls, vI): + return EnumOsType.values[vI] + +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- + +#++--------------------------------------------------------------------------- +# Details: Determine what operating system is currently running on. +# Args: None. +# Returns: EnumOsType - The OS type being used ATM. +# Throws: None. +#-- +def determine_os_type(): + eOSType = EnumOsType.Unknown + + strOS = sys.platform + if strOS == "darwin": + eOSType = EnumOsType.Darwin + elif strOS.startswith("freebsd"): + eOSType = EnumOsType.FreeBSD + elif strOS.startswith("linux"): + eOSType = EnumOsType.Linux + elif strOS.startswith("netbsd"): + eOSType = EnumOsType.NetBSD + elif strOS == "win32": + eOSType = EnumOsType.Windows + + return eOSType diff --git a/scripts/verify_api.py b/scripts/verify_api.py new file mode 100755 index 0000000000000..e636cdda6498d --- /dev/null +++ b/scripts/verify_api.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +import commands +import optparse +import os +import os.path +import re +import sys + +def extract_exe_symbol_names (arch, exe_path, match_str): + command = 'dsymutil --arch %s -s "%s" | grep "%s" | colrm 1 69' % (arch, exe_path, match_str) + (command_exit_status, command_output) = commands.getstatusoutput(command) + if command_exit_status == 0: + if command_output: + return command_output[0:-1].split("'\n") + else: + print 'error: command returned no output' + else: + print 'error: command failed with exit status %i\n command: %s' % (command_exit_status, command) + return list() + +def verify_api(all_args): + '''Verify the API in the specified library is valid given one or more binaries.''' + usage = "usage: verify_api --library <path> [ --library <path> ...] executable1 [executable2 ...]" + description='''Verify the API in the specified library is valid given one or more binaries. + + Example: + + verify_api.py --library ~/Documents/src/lldb/build/Debug/LLDB.framework/LLDB --arch x86_64 /Applications/Xcode.app/Contents/PlugIns/DebuggerLLDB.ideplugin/Contents/MacOS/DebuggerLLDB --api-regex lldb + ''' + parser = optparse.OptionParser(description=description, prog='verify_api',usage=usage) + parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) + parser.add_option('-a', '--arch', type='string', action='append', dest='archs', help='architecure to use when checking the api') + parser.add_option('-r', '--api-regex', type='string', dest='api_regex_str', help='Exclude any undefined symbols that do not match this regular expression when searching for missing APIs.') + parser.add_option('-l', '--library', type='string', action='append', dest='libraries', help='Specify one or more libraries that will contain all needed APIs for the executables.') + (options, args) = parser.parse_args(all_args) + + api_external_symbols = list() + if options.archs: + for arch in options.archs: + for library in options.libraries: + external_symbols = extract_exe_symbol_names(arch, library, "( SECT EXT)"); + if external_symbols: + for external_symbol in external_symbols: + api_external_symbols.append(external_symbol) + else: + sys.exit(1) + else: + print 'error: must specify one or more architectures with the --arch option' + sys.exit(4) + if options.verbose: + print "API symbols:" + for (i, external_symbol) in enumerate(api_external_symbols): + print "[%u] %s" % (i, external_symbol) + + api_regex = None + if options.api_regex_str: + api_regex = re.compile(options.api_regex_str) + + for arch in options.archs: + for exe_path in args: + print 'Verifying (%s) "%s"...' % (arch, exe_path) + exe_errors = 0 + undefined_symbols = extract_exe_symbol_names(arch, exe_path, "( UNDF EXT)"); + for undefined_symbol in undefined_symbols: + if api_regex: + match = api_regex.search(undefined_symbol) + if not match: + if options.verbose: + print 'ignoring symbol: %s' % (undefined_symbol) + continue + if undefined_symbol in api_external_symbols: + if options.verbose: + print 'verified symbol: %s' % (undefined_symbol) + else: + print 'missing symbol: %s' % (undefined_symbol) + exe_errors += 1 + if exe_errors: + print 'error: missing %u API symbols from %s' % (exe_errors, options.libraries) + else: + print 'success' + +if __name__ == '__main__': + verify_api(sys.argv[1:])
\ No newline at end of file |