diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/utils | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/utils')
32 files changed, 4627 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/utils/TableGen/CMakeLists.txt b/gnu/llvm/lldb/utils/TableGen/CMakeLists.txt new file mode 100644 index 00000000000..47a6400b428 --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/CMakeLists.txt @@ -0,0 +1,18 @@ +# tablegen targets get exported via llvm for LLVMConfig.cmake. So standalone +# builds of lldb can potentially import this via LLVMConfig and also attempt to +# build it in tree. So only build it if it doesn't exist. +if (NOT DEFINED LLDB_TABLEGEN_EXE) + if (TARGET lldb-tblgen) + set(LLDB_TABLEGEN_EXE $<TARGET_FILE:lldb-tblgen> CACHE STRING "") + else() + set(LLVM_LINK_COMPONENTS Support) + + add_tablegen(lldb-tblgen LLDB + LLDBOptionDefEmitter.cpp + LLDBPropertyDefEmitter.cpp + LLDBTableGen.cpp + LLDBTableGenUtils.cpp + ) + set_target_properties(lldb-tblgen PROPERTIES FOLDER "LLDB tablegenning") + endif() +endif() diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp b/gnu/llvm/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp new file mode 100644 index 00000000000..6e73d0c53de --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBOptionDefEmitter.cpp @@ -0,0 +1,185 @@ +//===- LLDBOptionDefEmitter.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emits LLDB's OptionDefinition values for different +// LLDB commands. +// +//===----------------------------------------------------------------------===// + +#include "LLDBTableGenBackends.h" +#include "LLDBTableGenUtils.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> + +using namespace llvm; +using namespace lldb_private; + +namespace { +struct CommandOption { + std::vector<std::string> GroupsArg; + bool Required = false; + std::string FullName; + std::string ShortName; + std::string ArgType; + bool OptionalArg = false; + std::string Validator; + std::string ArgEnum; + std::vector<StringRef> Completions; + std::string Description; + + CommandOption() = default; + CommandOption(Record *Option) { + if (Option->getValue("Groups")) { + // The user specified a list of groups. + auto Groups = Option->getValueAsListOfInts("Groups"); + for (int Group : Groups) + GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(Group)); + } else if (Option->getValue("GroupStart")) { + // The user specified a range of groups (with potentially only one + // element). + int GroupStart = Option->getValueAsInt("GroupStart"); + int GroupEnd = Option->getValueAsInt("GroupEnd"); + for (int i = GroupStart; i <= GroupEnd; ++i) + GroupsArg.push_back("LLDB_OPT_SET_" + std::to_string(i)); + } + + // Check if this option is required. + Required = Option->getValue("Required"); + + // Add the full and short name for this option. + FullName = Option->getValueAsString("FullName"); + ShortName = Option->getValueAsString("ShortName"); + + if (auto A = Option->getValue("ArgType")) + ArgType = A->getValue()->getAsUnquotedString(); + OptionalArg = Option->getValue("OptionalArg") != nullptr; + + if (Option->getValue("Validator")) + Validator = Option->getValueAsString("Validator"); + + if (Option->getValue("ArgEnum")) + ArgEnum = Option->getValueAsString("ArgEnum"); + + if (Option->getValue("Completions")) + Completions = Option->getValueAsListOfStrings("Completions"); + + if (auto D = Option->getValue("Description")) + Description = D->getValue()->getAsUnquotedString(); + } +}; +} // namespace + +static void emitOption(const CommandOption &O, raw_ostream &OS) { + OS << " {"; + + // If we have any groups, we merge them. Otherwise we move this option into + // the all group. + if (O.GroupsArg.empty()) + OS << "LLDB_OPT_SET_ALL"; + else + OS << llvm::join(O.GroupsArg.begin(), O.GroupsArg.end(), " | "); + + OS << ", "; + + // Check if this option is required. + OS << (O.Required ? "true" : "false"); + + // Add the full and short name for this option. + OS << ", \"" << O.FullName << "\", "; + OS << '\'' << O.ShortName << "'"; + + // Decide if we have either an option, required or no argument for this + // option. + OS << ", OptionParser::"; + if (!O.ArgType.empty()) { + if (O.OptionalArg) + OS << "eOptionalArgument"; + else + OS << "eRequiredArgument"; + } else + OS << "eNoArgument"; + OS << ", "; + + if (!O.Validator.empty()) + OS << O.Validator; + else + OS << "nullptr"; + OS << ", "; + + if (!O.ArgEnum.empty()) + OS << O.ArgEnum; + else + OS << "{}"; + OS << ", "; + + // Read the tab completions we offer for this option (if there are any) + if (!O.Completions.empty()) { + std::vector<std::string> CompletionArgs; + for (llvm::StringRef Completion : O.Completions) + CompletionArgs.push_back("CommandCompletions::e" + Completion.str() + + "Completion"); + + OS << llvm::join(CompletionArgs.begin(), CompletionArgs.end(), " | "); + } else + OS << "CommandCompletions::eNoCompletion"; + + // Add the argument type. + OS << ", eArgType"; + if (!O.ArgType.empty()) { + OS << O.ArgType; + } else + OS << "None"; + OS << ", "; + + // Add the description if there is any. + if (!O.Description.empty()) { + OS << "\""; + llvm::printEscapedString(O.Description, OS); + OS << "\""; + } else + OS << "\"\""; + OS << "},\n"; +} + +/// Emits all option initializers to the raw_ostream. +static void emitOptions(std::string Command, std::vector<Record *> Records, + raw_ostream &OS) { + std::vector<CommandOption> Options; + for (Record *R : Records) + Options.emplace_back(R); + + std::string ID = Command; + std::replace(ID.begin(), ID.end(), ' ', '_'); + // Generate the macro that the user needs to define before including the + // *.inc file. + std::string NeededMacro = "LLDB_OPTIONS_" + ID; + + // All options are in one file, so we need put them behind macros and ask the + // user to define the macro for the options that are needed. + OS << "// Options for " << Command << "\n"; + OS << "#ifdef " << NeededMacro << "\n"; + OS << "constexpr static OptionDefinition g_" + ID + "_options[] = {\n"; + for (CommandOption &CO : Options) + emitOption(CO, OS); + // We undefine the macro for the user like Clang's include files are doing it. + OS << "};\n"; + OS << "#undef " << NeededMacro << "\n"; + OS << "#endif // " << Command << " command\n\n"; +} + +void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Options for LLDB command line commands.", OS); + + std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option"); + for (auto &CommandRecordPair : getRecordsByName(Options, "Command")) { + emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS); + } +} diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp b/gnu/llvm/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp new file mode 100644 index 00000000000..f36deeebf90 --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp @@ -0,0 +1,180 @@ +//===- LLDBPropertyDefEmitter.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// These tablegen backends emits LLDB's PropertyDefinition values. +// +//===----------------------------------------------------------------------===// + +#include "LLDBTableGenBackends.h" +#include "LLDBTableGenUtils.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringMatcher.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <vector> + +using namespace llvm; +using namespace lldb_private; + +static void emitPropertyEnum(Record *Property, raw_ostream &OS) { + OS << "eProperty"; + OS << Property->getName(); + OS << ",\n"; +} + +static void emitProperty(Record *Property, raw_ostream &OS) { + OS << " {"; + + // Emit the property name. + OS << "\"" << Property->getValueAsString("Name") << "\""; + OS << ", "; + + // Emit the property type. + OS << "OptionValue::eType"; + OS << Property->getValueAsString("Type"); + OS << ", "; + + // Emit the property's global value. + OS << (Property->getValue("Global") ? "true" : "false"); + OS << ", "; + + bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue"); + bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue"); + bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue"); + + // Guarantee that every property has a default value. + assert((hasDefaultUnsignedValue || hasDefaultEnumValue || + hasDefaultStringValue) && + "Property must have a default value"); + + // Guarantee that no property has both a default unsigned value and a default + // enum value, since they're bothed stored in the same field. + assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) && + "Property cannot have both a unsigned and enum default value."); + + // Guarantee that every boolean property has a boolean default value. + assert(!(Property->getValueAsString("Type") == "Boolean" && + !Property->getValue("HasDefaultBooleanValue")) && + "Boolean property must have a boolean default value."); + + // Guarantee that every string property has a string default value. + assert(!(Property->getValueAsString("Type") == "String" && + !hasDefaultStringValue) && + "String property must have a string default value."); + + // Guarantee that every enum property has an enum default value. + assert( + !(Property->getValueAsString("Type") == "Enum" && !hasDefaultEnumValue) && + "Enum property must have a enum default value."); + + // Emit the default uint value. + if (hasDefaultUnsignedValue) { + OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue")); + } else if (hasDefaultEnumValue) { + OS << Property->getValueAsString("DefaultEnumValue"); + } else { + OS << "0"; + } + OS << ", "; + + // Emit the default string value. + if (hasDefaultStringValue) { + if (auto D = Property->getValue("DefaultStringValue")) { + OS << "\""; + OS << D->getValue()->getAsUnquotedString(); + OS << "\""; + } else { + OS << "\"\""; + } + } else { + OS << "nullptr"; + } + OS << ", "; + + // Emit the enum values value. + if (Property->getValue("EnumValues")) + OS << Property->getValueAsString("EnumValues"); + else + OS << "{}"; + OS << ", "; + + // Emit the property description. + if (auto D = Property->getValue("Description")) { + OS << "\""; + OS << D->getValue()->getAsUnquotedString(); + OS << "\""; + } else { + OS << "\"\""; + } + + OS << "},\n"; +} + +/// Emits all property initializers to the raw_ostream. +static void emityProperties(std::string PropertyName, + std::vector<Record *> PropertyRecords, + raw_ostream &OS) { + // Generate the macro that the user needs to define before including the + // *.inc file. + std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; + std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + + // All options are in one file, so we need put them behind macros and ask the + // user to define the macro for the options that are needed. + OS << "// Property definitions for " << PropertyName << "\n"; + OS << "#ifdef " << NeededMacro << "\n"; + OS << "static constexpr PropertyDefinition g_" << PropertyName + << "_properties[] = {\n"; + for (Record *R : PropertyRecords) + emitProperty(R, OS); + OS << "};\n"; + // We undefine the macro for the user like Clang's include files are doing it. + OS << "#undef " << NeededMacro << "\n"; + OS << "#endif // " << PropertyName << " Property\n\n"; +} + +/// Emits all property initializers to the raw_ostream. +static void emitPropertyEnum(std::string PropertyName, + std::vector<Record *> PropertyRecords, + raw_ostream &OS) { + // Generate the macro that the user needs to define before including the + // *.inc file. + std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName; + std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_'); + + // All options are in one file, so we need put them behind macros and ask the + // user to define the macro for the options that are needed. + OS << "// Property enum cases for " << PropertyName << "\n"; + OS << "#ifdef " << NeededMacro << "\n"; + for (Record *R : PropertyRecords) + emitPropertyEnum(R, OS); + // We undefine the macro for the user like Clang's include files are doing it. + OS << "#undef " << NeededMacro << "\n"; + OS << "#endif // " << PropertyName << " Property\n\n"; +} + +void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Property definitions for LLDB.", OS); + + std::vector<Record *> Properties = + Records.getAllDerivedDefinitions("Property"); + for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) { + emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS); + } +} + +void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records, + raw_ostream &OS) { + emitSourceFileHeader("Property definition enum for LLDB.", OS); + + std::vector<Record *> Properties = + Records.getAllDerivedDefinitions("Property"); + for (auto &PropertyRecordPair : getRecordsByName(Properties, "Definition")) { + emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS); + } +} diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBTableGen.cpp b/gnu/llvm/lldb/utils/TableGen/LLDBTableGen.cpp new file mode 100644 index 00000000000..abb6589f0ca --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBTableGen.cpp @@ -0,0 +1,83 @@ +//===- LLDBTableGen.cpp - Top-Level TableGen implementation for LLDB ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the main function for LLDB's TableGen. +// +//===----------------------------------------------------------------------===// + +#include "LLDBTableGenBackends.h" // Declares all backends. +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Main.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; +using namespace lldb_private; + +enum ActionType { + PrintRecords, + DumpJSON, + GenOptionDefs, + GenPropertyDefs, + GenPropertyEnumDefs, +}; + +static cl::opt<ActionType> Action( + cl::desc("Action to perform:"), + cl::values(clEnumValN(PrintRecords, "print-records", + "Print all records to stdout (default)"), + clEnumValN(DumpJSON, "dump-json", + "Dump all records as machine-readable JSON"), + clEnumValN(GenOptionDefs, "gen-lldb-option-defs", + "Generate lldb option definitions"), + clEnumValN(GenPropertyDefs, "gen-lldb-property-defs", + "Generate lldb property definitions"), + clEnumValN(GenPropertyEnumDefs, "gen-lldb-property-enum-defs", + "Generate lldb property enum definitions"))); + +static bool LLDBTableGenMain(raw_ostream &OS, RecordKeeper &Records) { + switch (Action) { + case PrintRecords: + OS << Records; // No argument, dump all contents + break; + case DumpJSON: + EmitJSON(Records, OS); + break; + case GenOptionDefs: + EmitOptionDefs(Records, OS); + break; + case GenPropertyDefs: + EmitPropertyDefs(Records, OS); + break; + case GenPropertyEnumDefs: + EmitPropertyEnumDefs(Records, OS); + break; + } + return false; +} + +int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + PrettyStackTraceProgram X(argc, argv); + cl::ParseCommandLineOptions(argc, argv); + + llvm_shutdown_obj Y; + + return TableGenMain(argv[0], &LLDBTableGenMain); +} + +#ifdef __has_feature +#if __has_feature(address_sanitizer) +#include <sanitizer/lsan_interface.h> +// Disable LeakSanitizer for this binary as it has too many leaks that are not +// very interesting to fix. See compiler-rt/include/sanitizer/lsan_interface.h . +int __lsan_is_turned_off() { return 1; } +#endif // __has_feature(address_sanitizer) +#endif // defined(__has_feature) diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBTableGenBackends.h b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenBackends.h new file mode 100644 index 00000000000..b424abfce9a --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenBackends.h @@ -0,0 +1,38 @@ +//===- LLDBTableGenBackends.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations for all of the LLDB TableGen +// backends. A "TableGen backend" is just a function. +// +// See "$LLVM_ROOT/utils/TableGen/TableGenBackends.h" for more info. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LLDB_UTILS_TABLEGEN_TABLEGENBACKENDS_H +#define LLVM_LLDB_UTILS_TABLEGEN_TABLEGENBACKENDS_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class raw_ostream; +class RecordKeeper; +class Record; +} // namespace llvm + +using llvm::raw_ostream; +using llvm::RecordKeeper; + +namespace lldb_private { + +void EmitOptionDefs(RecordKeeper &RK, raw_ostream &OS); +void EmitPropertyDefs(RecordKeeper &RK, raw_ostream &OS); +void EmitPropertyEnumDefs(RecordKeeper &RK, raw_ostream &OS); + +} // namespace lldb_private + +#endif diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.cpp b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.cpp new file mode 100644 index 00000000000..8b4c7581c98 --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.cpp @@ -0,0 +1,21 @@ +//===- LLDBTableGenUtils.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LLDBTableGenUtils.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; +using namespace lldb_private; + +RecordsByName lldb_private::getRecordsByName(std::vector<Record *> Records, + StringRef Name) { + RecordsByName Result; + for (Record *R : Records) + Result[R->getValueAsString(Name).str()].push_back(R); + return Result; +} diff --git a/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.h b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.h new file mode 100644 index 00000000000..5553cecafb1 --- /dev/null +++ b/gnu/llvm/lldb/utils/TableGen/LLDBTableGenUtils.h @@ -0,0 +1,34 @@ +//===- LLDBTableGenUtils.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LLDB_UTILS_TABLEGEN_TABLEGENUTILS_H +#define LLVM_LLDB_UTILS_TABLEGEN_TABLEGENUTILS_H + +#include "llvm/ADT/StringRef.h" +#include <map> +#include <string> +#include <vector> + +namespace llvm { +class RecordKeeper; +class Record; +} // namespace llvm + +namespace lldb_private { + +/// Map of names to their associated records. This map also ensures that our +/// records are sorted in a deterministic way. +typedef std::map<std::string, std::vector<llvm::Record *>> RecordsByName; + +/// Return records grouped by name. +RecordsByName getRecordsByName(std::vector<llvm::Record *> Records, + llvm::StringRef); + +} // namespace lldb_private + +#endif diff --git a/gnu/llvm/lldb/utils/lit-cpuid/CMakeLists.txt b/gnu/llvm/lldb/utils/lit-cpuid/CMakeLists.txt new file mode 100644 index 00000000000..f365447dd27 --- /dev/null +++ b/gnu/llvm/lldb/utils/lit-cpuid/CMakeLists.txt @@ -0,0 +1,6 @@ +add_lldb_executable(lit-cpuid + lit-cpuid.cpp + ) + +target_link_libraries(lit-cpuid PRIVATE LLVMSupport) +set_target_properties(lit-cpuid PROPERTIES FOLDER "lldb utils") diff --git a/gnu/llvm/lldb/utils/lit-cpuid/lit-cpuid.cpp b/gnu/llvm/lldb/utils/lit-cpuid/lit-cpuid.cpp new file mode 100644 index 00000000000..3ec9241ff88 --- /dev/null +++ b/gnu/llvm/lldb/utils/lit-cpuid/lit-cpuid.cpp @@ -0,0 +1,37 @@ +//===- lit-cpuid.cpp - Get CPU feature flags for lit exported features ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// lit-cpuid obtains the feature list for the currently running CPU, and outputs +// those flags that are interesting for LLDB lit tests. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +int main(int argc, char **argv) { +#if defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64__) || defined(_M_X64) + StringMap<bool> features; + + if (!sys::getHostCPUFeatures(features)) + return 1; + + if (features["sse"]) + outs() << "sse\n"; + if (features["avx"]) + outs() << "avx\n"; + if (features["avx512f"]) + outs() << "avx512f\n"; +#endif + + return 0; +} diff --git a/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt b/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt new file mode 100644 index 00000000000..4f1bd7304ab --- /dev/null +++ b/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt @@ -0,0 +1,47 @@ +# Make lldb-dotest a custom target. +add_custom_target(lldb-dotest) +add_dependencies(lldb-dotest lldb-test-deps) +set_target_properties(lldb-dotest PROPERTIES FOLDER "lldb utils") + +get_property(LLDB_DOTEST_ARGS GLOBAL PROPERTY LLDB_DOTEST_ARGS_PROPERTY) + +# Generate lldb-dotest Python driver script for each build mode. +if(LLDB_BUILT_STANDALONE) + set(config_types ".") + if(CMAKE_CONFIGURATION_TYPES) + set(config_types ${CMAKE_CONFIGURATION_TYPES}) + endif() + foreach(config_type ${config_types}) + # In paths to our build-tree, replace CMAKE_CFG_INTDIR with our actual configuration names. + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} config_runtime_output_dir ${LLVM_RUNTIME_OUTPUT_INTDIR}) + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") + + # Remaining ones must be paths to the provided LLVM build-tree. + if(${config_type} IN_LIST LLVM_CONFIGURATION_TYPES) + # Multi-configuration generator like Xcode (with a matching config). + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") + else() + # Single-configuration generator like Ninja. + string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") + endif() + + configure_file( + lldb-dotest.in + ${config_runtime_output_dir}/lldb-dotest @ONLY + ) + endforeach() +elseif(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") + foreach(LLVM_BUILD_MODE ${CMAKE_CONFIGURATION_TYPES}) + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_ARGS "${LLDB_DOTEST_ARGS}") + configure_file( + lldb-dotest.in + ${LLDB_DOTEST_DIR}/lldb-dotest + ) + endforeach() +else() + configure_file( + lldb-dotest.in + ${LLVM_RUNTIME_OUTPUT_INTDIR}/lldb-dotest + ) +endif() diff --git a/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in b/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in new file mode 100755 index 00000000000..bab3f8baa98 --- /dev/null +++ b/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in @@ -0,0 +1,29 @@ +#!/usr/bin/env python +import subprocess +import sys + +dotest_path = '@LLDB_SOURCE_DIR@/test/API/dotest.py' +build_dir = '@LLDB_TEST_BUILD_DIRECTORY@' +dotest_args_str = '@LLDB_DOTEST_ARGS@' +arch = '@LLDB_TEST_ARCH@' +executable = '@LLDB_TEST_EXECUTABLE@' +compiler = '@LLDB_TEST_COMPILER@' +dsymutil = '@LLDB_TEST_DSYMUTIL@' +filecheck = '@LLDB_TEST_FILECHECK@' + +if __name__ == '__main__': + wrapper_args = sys.argv[1:] + dotest_args = dotest_args_str.split(';') + # Build dotest.py command. + cmd = [sys.executable, dotest_path] + cmd.extend(['--arch', arch]) + cmd.extend(dotest_args) + cmd.extend(['--build-dir', build_dir]) + cmd.extend(['--executable', executable]) + cmd.extend(['--compiler', compiler]) + cmd.extend(['--dsymutil', dsymutil]) + cmd.extend(['--filecheck', filecheck]) + cmd.extend(wrapper_args) + # Invoke dotest.py and return exit code. + print(' '.join(cmd)) + sys.exit(subprocess.call(cmd)) diff --git a/gnu/llvm/lldb/utils/lui/Readme b/gnu/llvm/lldb/utils/lui/Readme new file mode 100644 index 00000000000..7ba51ce8110 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/Readme @@ -0,0 +1,36 @@ + +LLDB (Terminal) User Interface +------------------------------ + +This directory contains the curses user interface for LLDB. To use it, ensure Python can find your lldb module. You may have to modify PYTHONPATH for that purpose: + +$ export PYTHONPATH=/path/to/lldb/module + +Then, run the lui.py. To load a core file: +$ ./lui.py --core core + +To create a target from an executable: +$ ./lui.py /bin/echo "hello world" + +To attach to a running process: +$ ./lui.py --attach <pid> + + +Known Issues +------------ +1. Resizing the terminal will most likely cause lui to crash. +2. Missing paging in command-window +3. Only minimal testing (on Ubuntu Linux x86_64) + +Missing Features +---------------- +- stdin/stdout/stderr windows +- memory window +- backtrace window +- threads window +- tab-completion +- syntax-highlighting (via pygments library) +- (local) variables window +- registers window +- disassembly window +- custom layout diff --git a/gnu/llvm/lldb/utils/lui/breakwin.py b/gnu/llvm/lldb/utils/lui/breakwin.py new file mode 100644 index 00000000000..a12b3a96fe4 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/breakwin.py @@ -0,0 +1,93 @@ +##===-- breakwin.py ------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import cui +import curses +import lldb +import lldbutil +import re + + +class BreakWin(cui.ListWin): + + def __init__(self, driver, x, y, w, h): + super(BreakWin, self).__init__(x, y, w, h) + self.driver = driver + self.update() + self.showDetails = {} + + def handleEvent(self, event): + if isinstance(event, lldb.SBEvent): + if lldb.SBBreakpoint.EventIsBreakpointEvent(event): + self.update() + if isinstance(event, int): + if event == ord('d'): + self.deleteSelected() + if event == curses.ascii.NL or event == curses.ascii.SP: + self.toggleSelected() + elif event == curses.ascii.TAB: + if self.getSelected() != -1: + target = self.driver.getTarget() + if not target.IsValid(): + return + i = target.GetBreakpointAtIndex(self.getSelected()).id + self.showDetails[i] = not self.showDetails[i] + self.update() + super(BreakWin, self).handleEvent(event) + + def toggleSelected(self): + if self.getSelected() == -1: + return + target = self.driver.getTarget() + if not target.IsValid(): + return + bp = target.GetBreakpointAtIndex(self.getSelected()) + bp.SetEnabled(not bp.IsEnabled()) + + def deleteSelected(self): + if self.getSelected() == -1: + return + target = self.driver.getTarget() + if not target.IsValid(): + return + bp = target.GetBreakpointAtIndex(self.getSelected()) + target.BreakpointDelete(bp.id) + + def update(self): + target = self.driver.getTarget() + if not target.IsValid(): + self.win.erase() + self.win.noutrefresh() + return + selected = self.getSelected() + self.clearItems() + for i in range(0, target.GetNumBreakpoints()): + bp = target.GetBreakpointAtIndex(i) + if bp.IsInternal(): + continue + text = lldbutil.get_description(bp) + # FIXME: Use an API for this, not parsing the description. + match = re.search('SBBreakpoint: id = ([^,]+), (.*)', text) + try: + id = match.group(1) + desc = match.group(2).strip() + if bp.IsEnabled(): + text = '%s: %s' % (id, desc) + else: + text = '%s: (disabled) %s' % (id, desc) + except ValueError as e: + # bp unparsable + pass + + if self.showDetails.setdefault(bp.id, False): + for location in bp: + desc = lldbutil.get_description( + location, lldb.eDescriptionLevelFull) + text += '\n ' + desc + self.addItem(text) + self.setSelected(selected) diff --git a/gnu/llvm/lldb/utils/lui/commandwin.py b/gnu/llvm/lldb/utils/lui/commandwin.py new file mode 100644 index 00000000000..7b2fdc1c09e --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/commandwin.py @@ -0,0 +1,130 @@ +##===-- commandwin.py ----------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import cui +import curses +import lldb +from itertools import islice + + +class History(object): + + def __init__(self): + self.data = {} + self.pos = 0 + self.tempEntry = '' + + def previous(self, curr): + if self.pos == len(self.data): + self.tempEntry = curr + + if self.pos < 0: + return '' + if self.pos == 0: + self.pos -= 1 + return '' + if self.pos > 0: + self.pos -= 1 + return self.data[self.pos] + + def next(self): + if self.pos < len(self.data): + self.pos += 1 + + if self.pos < len(self.data): + return self.data[self.pos] + elif self.tempEntry != '': + return self.tempEntry + else: + return '' + + def add(self, c): + self.tempEntry = '' + self.pos = len(self.data) + if self.pos == 0 or self.data[self.pos - 1] != c: + self.data[self.pos] = c + self.pos += 1 + + +class CommandWin(cui.TitledWin): + + def __init__(self, driver, x, y, w, h): + super(CommandWin, self).__init__(x, y, w, h, "Commands") + self.command = "" + self.data = "" + driver.setSize(w, h) + + self.win.scrollok(1) + + self.driver = driver + self.history = History() + + def enterCallback(content): + self.handleCommand(content) + + def tabCompleteCallback(content): + self.data = content + matches = lldb.SBStringList() + commandinterpreter = self.getCommandInterpreter() + commandinterpreter.HandleCompletion( + self.data, self.el.index, 0, -1, matches) + if matches.GetSize() == 2: + self.el.content += matches.GetStringAtIndex(0) + self.el.index = len(self.el.content) + self.el.draw() + else: + self.win.move(self.el.starty, self.el.startx) + self.win.scroll(1) + self.win.addstr("Available Completions:") + self.win.scroll(1) + for m in islice(matches, 1, None): + self.win.addstr(self.win.getyx()[0], 0, m) + self.win.scroll(1) + self.el.draw() + + self.startline = self.win.getmaxyx()[0] - 2 + + self.el = cui.CursesEditLine( + self.win, + self.history, + enterCallback, + tabCompleteCallback) + self.el.prompt = self.driver.getPrompt() + self.el.showPrompt(self.startline, 0) + + def handleCommand(self, cmd): + # enter! + self.win.scroll(1) # TODO: scroll more for longer commands + if cmd == '': + cmd = self.history.previous('') + elif cmd in ('q', 'quit'): + self.driver.terminate() + return + + self.history.add(cmd) + ret = self.driver.handleCommand(cmd) + if ret.Succeeded(): + out = ret.GetOutput() + attr = curses.A_NORMAL + else: + out = ret.GetError() + attr = curses.color_pair(3) # red on black + self.win.addstr(self.startline, 0, out + '\n', attr) + self.win.scroll(1) + self.el.showPrompt(self.startline, 0) + + def handleEvent(self, event): + if isinstance(event, int): + if event == curses.ascii.EOT and self.el.content == '': + # When the command is empty, treat CTRL-D as EOF. + self.driver.terminate() + return + self.el.handleEvent(event) + + def getCommandInterpreter(self): + return self.driver.getCommandInterpreter() diff --git a/gnu/llvm/lldb/utils/lui/cui.py b/gnu/llvm/lldb/utils/lui/cui.py new file mode 100755 index 00000000000..fffb812fbb9 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/cui.py @@ -0,0 +1,338 @@ +##===-- cui.py -----------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import curses +import curses.ascii +import threading + + +class CursesWin(object): + + def __init__(self, x, y, w, h): + self.win = curses.newwin(h, w, y, x) + self.focus = False + + def setFocus(self, focus): + self.focus = focus + + def getFocus(self): + return self.focus + + def canFocus(self): + return True + + def handleEvent(self, event): + return + + def draw(self): + return + + +class TextWin(CursesWin): + + def __init__(self, x, y, w): + super(TextWin, self).__init__(x, y, w, 1) + self.win.bkgd(curses.color_pair(1)) + self.text = '' + self.reverse = False + + def canFocus(self): + return False + + def draw(self): + w = self.win.getmaxyx()[1] + text = self.text + if len(text) > w: + #trunc_length = len(text) - w + text = text[-w + 1:] + if self.reverse: + self.win.addstr(0, 0, text, curses.A_REVERSE) + else: + self.win.addstr(0, 0, text) + self.win.noutrefresh() + + def setReverse(self, reverse): + self.reverse = reverse + + def setText(self, text): + self.text = text + + +class TitledWin(CursesWin): + + def __init__(self, x, y, w, h, title): + super(TitledWin, self).__init__(x, y + 1, w, h - 1) + self.title = title + self.title_win = TextWin(x, y, w) + self.title_win.setText(title) + self.draw() + + def setTitle(self, title): + self.title_win.setText(title) + + def draw(self): + self.title_win.setReverse(self.getFocus()) + self.title_win.draw() + self.win.noutrefresh() + + +class ListWin(CursesWin): + + def __init__(self, x, y, w, h): + super(ListWin, self).__init__(x, y, w, h) + self.items = [] + self.selected = 0 + self.first_drawn = 0 + self.win.leaveok(True) + + def draw(self): + if len(self.items) == 0: + self.win.erase() + return + + h, w = self.win.getmaxyx() + + allLines = [] + firstSelected = -1 + lastSelected = -1 + for i, item in enumerate(self.items): + lines = self.items[i].split('\n') + lines = lines if lines[len(lines) - 1] != '' else lines[:-1] + if len(lines) == 0: + lines = [''] + + if i == self.getSelected(): + firstSelected = len(allLines) + allLines.extend(lines) + if i == self.selected: + lastSelected = len(allLines) - 1 + + if firstSelected < self.first_drawn: + self.first_drawn = firstSelected + elif lastSelected >= self.first_drawn + h: + self.first_drawn = lastSelected - h + 1 + + self.win.erase() + + begin = self.first_drawn + end = begin + h + + y = 0 + for i, line in list(enumerate(allLines))[begin:end]: + attr = curses.A_NORMAL + if i >= firstSelected and i <= lastSelected: + attr = curses.A_REVERSE + line = '{0:{width}}'.format(line, width=w - 1) + + # Ignore the error we get from drawing over the bottom-right char. + try: + self.win.addstr(y, 0, line[:w], attr) + except curses.error: + pass + y += 1 + self.win.noutrefresh() + + def getSelected(self): + if self.items: + return self.selected + return -1 + + def setSelected(self, selected): + self.selected = selected + if self.selected < 0: + self.selected = 0 + elif self.selected >= len(self.items): + self.selected = len(self.items) - 1 + + def handleEvent(self, event): + if isinstance(event, int): + if len(self.items) > 0: + if event == curses.KEY_UP: + self.setSelected(self.selected - 1) + if event == curses.KEY_DOWN: + self.setSelected(self.selected + 1) + if event == curses.ascii.NL: + self.handleSelect(self.selected) + + def addItem(self, item): + self.items.append(item) + + def clearItems(self): + self.items = [] + + def handleSelect(self, index): + return + + +class InputHandler(threading.Thread): + + def __init__(self, screen, queue): + super(InputHandler, self).__init__() + self.screen = screen + self.queue = queue + + def run(self): + while True: + c = self.screen.getch() + self.queue.put(c) + + +class CursesUI(object): + """ Responsible for updating the console UI with curses. """ + + def __init__(self, screen, event_queue): + self.screen = screen + self.event_queue = event_queue + + curses.start_color() + curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE) + curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK) + curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) + self.screen.bkgd(curses.color_pair(1)) + self.screen.clear() + + self.input_handler = InputHandler(self.screen, self.event_queue) + self.input_handler.daemon = True + + self.focus = 0 + + self.screen.refresh() + + def focusNext(self): + self.wins[self.focus].setFocus(False) + old = self.focus + while True: + self.focus += 1 + if self.focus >= len(self.wins): + self.focus = 0 + if self.wins[self.focus].canFocus(): + break + self.wins[self.focus].setFocus(True) + + def handleEvent(self, event): + if isinstance(event, int): + if event == curses.KEY_F3: + self.focusNext() + + def eventLoop(self): + + self.input_handler.start() + self.wins[self.focus].setFocus(True) + + while True: + self.screen.noutrefresh() + + for i, win in enumerate(self.wins): + if i != self.focus: + win.draw() + # Draw the focused window last so that the cursor shows up. + if self.wins: + self.wins[self.focus].draw() + curses.doupdate() # redraw the physical screen + + event = self.event_queue.get() + + for win in self.wins: + if isinstance(event, int): + if win.getFocus() or not win.canFocus(): + win.handleEvent(event) + else: + win.handleEvent(event) + self.handleEvent(event) + + +class CursesEditLine(object): + """ Embed an 'editline'-compatible prompt inside a CursesWin. """ + + def __init__(self, win, history, enterCallback, tabCompleteCallback): + self.win = win + self.history = history + self.enterCallback = enterCallback + self.tabCompleteCallback = tabCompleteCallback + + self.prompt = '' + self.content = '' + self.index = 0 + self.startx = -1 + self.starty = -1 + + def draw(self, prompt=None): + if not prompt: + prompt = self.prompt + (h, w) = self.win.getmaxyx() + if (len(prompt) + len(self.content)) / w + self.starty >= h - 1: + self.win.scroll(1) + self.starty -= 1 + if self.starty < 0: + raise RuntimeError('Input too long; aborting') + (y, x) = (self.starty, self.startx) + + self.win.move(y, x) + self.win.clrtobot() + self.win.addstr(y, x, prompt) + remain = self.content + self.win.addstr(remain[:w - len(prompt)]) + remain = remain[w - len(prompt):] + while remain != '': + y += 1 + self.win.addstr(y, 0, remain[:w]) + remain = remain[w:] + + length = self.index + len(prompt) + self.win.move(self.starty + length / w, length % w) + + def showPrompt(self, y, x, prompt=None): + self.content = '' + self.index = 0 + self.startx = x + self.starty = y + self.draw(prompt) + + def handleEvent(self, event): + if not isinstance(event, int): + return # not handled + key = event + + if self.startx == -1: + raise RuntimeError('Trying to handle input without prompt') + + if key == curses.ascii.NL: + self.enterCallback(self.content) + elif key == curses.ascii.TAB: + self.tabCompleteCallback(self.content) + elif curses.ascii.isprint(key): + self.content = self.content[:self.index] + \ + chr(key) + self.content[self.index:] + self.index += 1 + elif key == curses.KEY_BACKSPACE or key == curses.ascii.BS: + if self.index > 0: + self.index -= 1 + self.content = self.content[ + :self.index] + self.content[self.index + 1:] + elif key == curses.KEY_DC or key == curses.ascii.DEL or key == curses.ascii.EOT: + self.content = self.content[ + :self.index] + self.content[self.index + 1:] + elif key == curses.ascii.VT: # CTRL-K + self.content = self.content[:self.index] + elif key == curses.KEY_LEFT or key == curses.ascii.STX: # left or CTRL-B + if self.index > 0: + self.index -= 1 + elif key == curses.KEY_RIGHT or key == curses.ascii.ACK: # right or CTRL-F + if self.index < len(self.content): + self.index += 1 + elif key == curses.ascii.SOH: # CTRL-A + self.index = 0 + elif key == curses.ascii.ENQ: # CTRL-E + self.index = len(self.content) + elif key == curses.KEY_UP or key == curses.ascii.DLE: # up or CTRL-P + self.content = self.history.previous(self.content) + self.index = len(self.content) + elif key == curses.KEY_DOWN or key == curses.ascii.SO: # down or CTRL-N + self.content = self.history.next() + self.index = len(self.content) + self.draw() diff --git a/gnu/llvm/lldb/utils/lui/debuggerdriver.py b/gnu/llvm/lldb/utils/lui/debuggerdriver.py new file mode 100644 index 00000000000..f94ce5face7 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/debuggerdriver.py @@ -0,0 +1,142 @@ +##===-- debuggerdriver.py ------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + + +import lldb +import lldbutil +import sys +from threading import Thread + + +class DebuggerDriver(Thread): + """ Drives the debugger and responds to events. """ + + def __init__(self, debugger, event_queue): + Thread.__init__(self) + self.event_queue = event_queue + # This is probably not great because it does not give liblldb a chance + # to clean up + self.daemon = True + self.initialize(debugger) + + def initialize(self, debugger): + self.done = False + self.debugger = debugger + self.listener = debugger.GetListener() + if not self.listener.IsValid(): + raise "Invalid listener" + + self.listener.StartListeningForEventClass(self.debugger, + lldb.SBTarget.GetBroadcasterClassName(), + lldb.SBTarget.eBroadcastBitBreakpointChanged + #| lldb.SBTarget.eBroadcastBitModuleLoaded + #| lldb.SBTarget.eBroadcastBitModuleUnloaded + | lldb.SBTarget.eBroadcastBitWatchpointChanged + #| lldb.SBTarget.eBroadcastBitSymbolLoaded + ) + + self.listener.StartListeningForEventClass(self.debugger, + lldb.SBThread.GetBroadcasterClassName(), + lldb.SBThread.eBroadcastBitStackChanged + # lldb.SBThread.eBroadcastBitBreakpointChanged + | lldb.SBThread.eBroadcastBitThreadSuspended + | lldb.SBThread.eBroadcastBitThreadResumed + | lldb.SBThread.eBroadcastBitSelectedFrameChanged + | lldb.SBThread.eBroadcastBitThreadSelected + ) + + self.listener.StartListeningForEventClass(self.debugger, + lldb.SBProcess.GetBroadcasterClassName(), + lldb.SBProcess.eBroadcastBitStateChanged + | lldb.SBProcess.eBroadcastBitInterrupt + | lldb.SBProcess.eBroadcastBitSTDOUT + | lldb.SBProcess.eBroadcastBitSTDERR + | lldb.SBProcess.eBroadcastBitProfileData + ) + self.listener.StartListeningForEventClass(self.debugger, + lldb.SBCommandInterpreter.GetBroadcasterClass(), + lldb.SBCommandInterpreter.eBroadcastBitThreadShouldExit + | lldb.SBCommandInterpreter.eBroadcastBitResetPrompt + | lldb.SBCommandInterpreter.eBroadcastBitQuitCommandReceived + | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousOutputData + | lldb.SBCommandInterpreter.eBroadcastBitAsynchronousErrorData + ) + + def createTarget(self, target_image, args=None): + self.handleCommand("target create %s" % target_image) + if args is not None: + self.handleCommand("settings set target.run-args %s" % args) + + def attachProcess(self, pid): + self.handleCommand("process attach -p %d" % pid) + pass + + def loadCore(self, corefile): + self.handleCommand("target create -c %s" % corefile) + pass + + def setDone(self): + self.done = True + + def isDone(self): + return self.done + + def getPrompt(self): + return self.debugger.GetPrompt() + + def getCommandInterpreter(self): + return self.debugger.GetCommandInterpreter() + + def getSourceManager(self): + return self.debugger.GetSourceManager() + + def setSize(self, width, height): + # FIXME: respect height + self.debugger.SetTerminalWidth(width) + + def getTarget(self): + return self.debugger.GetTargetAtIndex(0) + + def handleCommand(self, cmd): + ret = lldb.SBCommandReturnObject() + self.getCommandInterpreter().HandleCommand(cmd, ret) + return ret + + def eventLoop(self): + while not self.isDone(): + event = lldb.SBEvent() + got_event = self.listener.WaitForEvent(lldb.UINT32_MAX, event) + if got_event and not event.IsValid(): + self.winAddStr("Warning: Invalid or no event...") + continue + elif not event.GetBroadcaster().IsValid(): + continue + + self.event_queue.put(event) + + def run(self): + self.eventLoop() + + def terminate(self): + lldb.SBDebugger.Terminate() + sys.exit(0) + + +def createDriver(debugger, event_queue): + driver = DebuggerDriver(debugger, event_queue) + # driver.start() + # if pid specified: + # - attach to pid + # else if core file specified + # - create target from corefile + # else + # - create target from file + # - settings append target.run-args <args-from-cmdline> + # source .lldbinit file + + return driver diff --git a/gnu/llvm/lldb/utils/lui/eventwin.py b/gnu/llvm/lldb/utils/lui/eventwin.py new file mode 100644 index 00000000000..c8d14d7aeb0 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/eventwin.py @@ -0,0 +1,26 @@ +##===-- eventwin.py ------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import cui +import lldb +import lldbutil + + +class EventWin(cui.TitledWin): + + def __init__(self, x, y, w, h): + super(EventWin, self).__init__(x, y, w, h, 'LLDB Event Log') + self.win.scrollok(1) + super(EventWin, self).draw() + + def handleEvent(self, event): + if isinstance(event, lldb.SBEvent): + self.win.scroll() + h = self.win.getmaxyx()[0] + self.win.addstr(h - 1, 0, lldbutil.get_description(event)) + return diff --git a/gnu/llvm/lldb/utils/lui/lldbutil.py b/gnu/llvm/lldb/utils/lui/lldbutil.py new file mode 100644 index 00000000000..6bfaaecab4b --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/lldbutil.py @@ -0,0 +1,1040 @@ +##===-- lldbutil.py ------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +""" +This LLDB module contains miscellaneous utilities. +Some of the test suite takes advantage of the utility functions defined here. +They can also be useful for general purpose lldb scripting. +""" + +from __future__ import print_function + +import lldb +import os +import sys +import io + +# =================================================== +# Utilities for locating/checking executable programs +# =================================================== + + +def is_exe(fpath): + """Returns True if fpath is an executable.""" + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + +def which(program): + """Returns the full path to a program; None otherwise.""" + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + return None + +# =================================================== +# Disassembly for an SBFunction or an SBSymbol object +# =================================================== + + +def disassemble(target, function_or_symbol): + """Disassemble the function or symbol given a target. + + It returns the disassembly content in a string object. + """ + buf = io.StringIO() + insts = function_or_symbol.GetInstructions(target) + for i in insts: + print(i, file=buf) + return buf.getvalue() + +# ========================================================== +# Integer (byte size 1, 2, 4, and 8) to bytearray conversion +# ========================================================== + + +def int_to_bytearray(val, bytesize): + """Utility function to convert an integer into a bytearray. + + It returns the bytearray in the little endian format. It is easy to get the + big endian format, just do ba.reverse() on the returned object. + """ + import struct + + if bytesize == 1: + return bytearray([val]) + + # Little endian followed by a format character. + template = "<%c" + if bytesize == 2: + fmt = template % 'h' + elif bytesize == 4: + fmt = template % 'i' + elif bytesize == 4: + fmt = template % 'q' + else: + return None + + packed = struct.pack(fmt, val) + return bytearray(ord(x) for x in packed) + + +def bytearray_to_int(bytes, bytesize): + """Utility function to convert a bytearray into an integer. + + It interprets the bytearray in the little endian format. For a big endian + bytearray, just do ba.reverse() on the object before passing it in. + """ + import struct + + if bytesize == 1: + return bytes[0] + + # Little endian followed by a format character. + template = "<%c" + if bytesize == 2: + fmt = template % 'h' + elif bytesize == 4: + fmt = template % 'i' + elif bytesize == 4: + fmt = template % 'q' + else: + return None + + unpacked = struct.unpack(fmt, str(bytes)) + return unpacked[0] + + +# ============================================================== +# Get the description of an lldb object or None if not available +# ============================================================== +def get_description(obj, option=None): + """Calls lldb_obj.GetDescription() and returns a string, or None. + + For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra + option can be passed in to describe the detailed level of description + desired: + o lldb.eDescriptionLevelBrief + o lldb.eDescriptionLevelFull + o lldb.eDescriptionLevelVerbose + """ + method = getattr(obj, 'GetDescription') + if not method: + return None + tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) + if isinstance(obj, tuple): + if option is None: + option = lldb.eDescriptionLevelBrief + + stream = lldb.SBStream() + if option is None: + success = method(stream) + else: + success = method(stream, option) + if not success: + return None + return stream.GetData() + + +# ================================================= +# Convert some enum value to its string counterpart +# ================================================= + +def state_type_to_str(enum): + """Returns the stateType string given an enum.""" + if enum == lldb.eStateInvalid: + return "invalid" + elif enum == lldb.eStateUnloaded: + return "unloaded" + elif enum == lldb.eStateConnected: + return "connected" + elif enum == lldb.eStateAttaching: + return "attaching" + elif enum == lldb.eStateLaunching: + return "launching" + elif enum == lldb.eStateStopped: + return "stopped" + elif enum == lldb.eStateRunning: + return "running" + elif enum == lldb.eStateStepping: + return "stepping" + elif enum == lldb.eStateCrashed: + return "crashed" + elif enum == lldb.eStateDetached: + return "detached" + elif enum == lldb.eStateExited: + return "exited" + elif enum == lldb.eStateSuspended: + return "suspended" + else: + raise Exception("Unknown StateType enum") + + +def stop_reason_to_str(enum): + """Returns the stopReason string given an enum.""" + if enum == lldb.eStopReasonInvalid: + return "invalid" + elif enum == lldb.eStopReasonNone: + return "none" + elif enum == lldb.eStopReasonTrace: + return "trace" + elif enum == lldb.eStopReasonBreakpoint: + return "breakpoint" + elif enum == lldb.eStopReasonWatchpoint: + return "watchpoint" + elif enum == lldb.eStopReasonSignal: + return "signal" + elif enum == lldb.eStopReasonException: + return "exception" + elif enum == lldb.eStopReasonPlanComplete: + return "plancomplete" + elif enum == lldb.eStopReasonThreadExiting: + return "threadexiting" + else: + raise Exception("Unknown StopReason enum") + + +def symbol_type_to_str(enum): + """Returns the symbolType string given an enum.""" + if enum == lldb.eSymbolTypeInvalid: + return "invalid" + elif enum == lldb.eSymbolTypeAbsolute: + return "absolute" + elif enum == lldb.eSymbolTypeCode: + return "code" + elif enum == lldb.eSymbolTypeData: + return "data" + elif enum == lldb.eSymbolTypeTrampoline: + return "trampoline" + elif enum == lldb.eSymbolTypeRuntime: + return "runtime" + elif enum == lldb.eSymbolTypeException: + return "exception" + elif enum == lldb.eSymbolTypeSourceFile: + return "sourcefile" + elif enum == lldb.eSymbolTypeHeaderFile: + return "headerfile" + elif enum == lldb.eSymbolTypeObjectFile: + return "objectfile" + elif enum == lldb.eSymbolTypeCommonBlock: + return "commonblock" + elif enum == lldb.eSymbolTypeBlock: + return "block" + elif enum == lldb.eSymbolTypeLocal: + return "local" + elif enum == lldb.eSymbolTypeParam: + return "param" + elif enum == lldb.eSymbolTypeVariable: + return "variable" + elif enum == lldb.eSymbolTypeVariableType: + return "variabletype" + elif enum == lldb.eSymbolTypeLineEntry: + return "lineentry" + elif enum == lldb.eSymbolTypeLineHeader: + return "lineheader" + elif enum == lldb.eSymbolTypeScopeBegin: + return "scopebegin" + elif enum == lldb.eSymbolTypeScopeEnd: + return "scopeend" + elif enum == lldb.eSymbolTypeAdditional: + return "additional" + elif enum == lldb.eSymbolTypeCompiler: + return "compiler" + elif enum == lldb.eSymbolTypeInstrumentation: + return "instrumentation" + elif enum == lldb.eSymbolTypeUndefined: + return "undefined" + + +def value_type_to_str(enum): + """Returns the valueType string given an enum.""" + if enum == lldb.eValueTypeInvalid: + return "invalid" + elif enum == lldb.eValueTypeVariableGlobal: + return "global_variable" + elif enum == lldb.eValueTypeVariableStatic: + return "static_variable" + elif enum == lldb.eValueTypeVariableArgument: + return "argument_variable" + elif enum == lldb.eValueTypeVariableLocal: + return "local_variable" + elif enum == lldb.eValueTypeRegister: + return "register" + elif enum == lldb.eValueTypeRegisterSet: + return "register_set" + elif enum == lldb.eValueTypeConstResult: + return "constant_result" + else: + raise Exception("Unknown ValueType enum") + + +# ================================================== +# Get stopped threads due to each stop reason. +# ================================================== + +def sort_stopped_threads(process, + breakpoint_threads=None, + crashed_threads=None, + watchpoint_threads=None, + signal_threads=None, + exiting_threads=None, + other_threads=None): + """ Fills array *_threads with threads stopped for the corresponding stop + reason. + """ + for lst in [breakpoint_threads, + watchpoint_threads, + signal_threads, + exiting_threads, + other_threads]: + if lst is not None: + lst[:] = [] + + for thread in process: + dispatched = False + for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads), + (lldb.eStopReasonException, crashed_threads), + (lldb.eStopReasonWatchpoint, watchpoint_threads), + (lldb.eStopReasonSignal, signal_threads), + (lldb.eStopReasonThreadExiting, exiting_threads), + (None, other_threads)]: + if not dispatched and list is not None: + if thread.GetStopReason() == reason or reason is None: + list.append(thread) + dispatched = True + +# ================================================== +# Utility functions for setting breakpoints +# ================================================== + + +def run_break_set_by_file_and_line( + test, + file_name, + line_number, + extra_options=None, + num_expected_locations=1, + loc_exact=False, + module_name=None): + """Set a breakpoint by file and line, returning the breakpoint number. + + If extra_options is not None, then we append it to the breakpoint set command. + + If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations. + + If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.""" + + if file_name is None: + command = 'breakpoint set -l %d' % (line_number) + else: + command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) + + if module_name: + command += " --shlib '%s'" % (module_name) + + if extra_options: + command += " " + extra_options + + break_results = run_break_set_command(test, command) + + if num_expected_locations == 1 and loc_exact: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + file_name=file_name, + line_number=line_number, + module_name=module_name) + else: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) + + +def run_break_set_by_symbol( + test, + symbol, + extra_options=None, + num_expected_locations=-1, + sym_exact=False, + module_name=None): + """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. + + If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.""" + command = 'breakpoint set -n "%s"' % (symbol) + + if module_name: + command += " --shlib '%s'" % (module_name) + + if extra_options: + command += " " + extra_options + + break_results = run_break_set_command(test, command) + + if num_expected_locations == 1 and sym_exact: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + symbol_name=symbol, + module_name=module_name) + else: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) + + +def run_break_set_by_selector( + test, + selector, + extra_options=None, + num_expected_locations=-1, + module_name=None): + """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" + + command = 'breakpoint set -S "%s"' % (selector) + + if module_name: + command += ' --shlib "%s"' % (module_name) + + if extra_options: + command += " " + extra_options + + break_results = run_break_set_command(test, command) + + if num_expected_locations == 1: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations, + symbol_name=selector, + symbol_match_exact=False, + module_name=module_name) + else: + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) + + +def run_break_set_by_regexp( + test, + regexp, + extra_options=None, + num_expected_locations=-1): + """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" + + command = 'breakpoint set -r "%s"' % (regexp) + if extra_options: + command += " " + extra_options + + break_results = run_break_set_command(test, command) + + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) + + +def run_break_set_by_source_regexp( + test, + regexp, + extra_options=None, + num_expected_locations=-1): + """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" + command = 'breakpoint set -p "%s"' % (regexp) + if extra_options: + command += " " + extra_options + + break_results = run_break_set_command(test, command) + + check_breakpoint_result( + test, + break_results, + num_locations=num_expected_locations) + + return get_bpno_from_match(break_results) + + +def run_break_set_command(test, command): + """Run the command passed in - it must be some break set variant - and analyze the result. + Returns a dictionary of information gleaned from the command-line results. + Will assert if the breakpoint setting fails altogether. + + Dictionary will contain: + bpno - breakpoint of the newly created breakpoint, -1 on error. + num_locations - number of locations set for the breakpoint. + + If there is only one location, the dictionary MAY contain: + file - source file name + line_no - source line number + symbol - symbol name + inline_symbol - inlined symbol name + offset - offset from the original symbol + module - module + address - address at which the breakpoint was set.""" + + patterns = [ + r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", + r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", + r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$", + r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"] + match_object = test.match(command, patterns) + break_results = match_object.groupdict() + + # We always insert the breakpoint number, setting it to -1 if we couldn't find it + # Also, make sure it gets stored as an integer. + if not 'bpno' in break_results: + break_results['bpno'] = -1 + else: + break_results['bpno'] = int(break_results['bpno']) + + # We always insert the number of locations + # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... + # We also make sure it is an integer. + + if not 'num_locations' in break_results: + num_locations = 1 + else: + num_locations = break_results['num_locations'] + if num_locations == 'no': + num_locations = 0 + else: + num_locations = int(break_results['num_locations']) + + break_results['num_locations'] = num_locations + + if 'line_no' in break_results: + break_results['line_no'] = int(break_results['line_no']) + + return break_results + + +def get_bpno_from_match(break_results): + return int(break_results['bpno']) + + +def check_breakpoint_result( + test, + break_results, + file_name=None, + line_number=-1, + symbol_name=None, + symbol_match_exact=True, + module_name=None, + offset=-1, + num_locations=-1): + + out_num_locations = break_results['num_locations'] + + if num_locations == -1: + test.assertTrue(out_num_locations > 0, + "Expecting one or more locations, got none.") + else: + test.assertTrue( + num_locations == out_num_locations, + "Expecting %d locations, got %d." % + (num_locations, + out_num_locations)) + + if file_name: + out_file_name = "" + if 'file' in break_results: + out_file_name = break_results['file'] + test.assertTrue( + file_name == out_file_name, + "Breakpoint file name '%s' doesn't match resultant name '%s'." % + (file_name, + out_file_name)) + + if line_number != -1: + out_file_line = -1 + if 'line_no' in break_results: + out_line_number = break_results['line_no'] + + test.assertTrue( + line_number == out_line_number, + "Breakpoint line number %s doesn't match resultant line %s." % + (line_number, + out_line_number)) + + if symbol_name: + out_symbol_name = "" + # Look first for the inlined symbol name, otherwise use the symbol + # name: + if 'inline_symbol' in break_results and break_results['inline_symbol']: + out_symbol_name = break_results['inline_symbol'] + elif 'symbol' in break_results: + out_symbol_name = break_results['symbol'] + + if symbol_match_exact: + test.assertTrue( + symbol_name == out_symbol_name, + "Symbol name '%s' doesn't match resultant symbol '%s'." % + (symbol_name, + out_symbol_name)) + else: + test.assertTrue( + out_symbol_name.find(symbol_name) != - + 1, + "Symbol name '%s' isn't in resultant symbol '%s'." % + (symbol_name, + out_symbol_name)) + + if module_name: + out_nodule_name = None + if 'module' in break_results: + out_module_name = break_results['module'] + + test.assertTrue( + module_name.find(out_module_name) != - + 1, + "Symbol module name '%s' isn't in expected module name '%s'." % + (out_module_name, + module_name)) + +# ================================================== +# 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 + + +def get_stopped_thread(process, reason): + """A convenience function which returns the first thread with the given stop + reason or None. + + Example usages: + + 1. Get the stopped thread due to a breakpoint condition + + ... + from lldbutil import get_stopped_thread + thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete) + self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") + ... + + 2. Get the thread stopped due to a breakpoint + + ... + from lldbutil import get_stopped_thread + thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) + self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") + ... + + """ + threads = get_stopped_threads(process, reason) + if len(threads) == 0: + return None + return threads[0] + + +def get_threads_stopped_at_breakpoint(process, bkpt): + """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" + stopped_threads = [] + threads = [] + + stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint) + + if len(stopped_threads) == 0: + return threads + + for thread in stopped_threads: + # Make sure we've hit our breakpoint... + break_id = thread.GetStopReasonDataAtIndex(0) + if break_id == bkpt.GetID(): + threads.append(thread) + + return threads + + +def continue_to_breakpoint(process, bkpt): + """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" + process.Continue() + if process.GetState() != lldb.eStateStopped: + return None + else: + return get_threads_stopped_at_breakpoint(process, bkpt) + + +def get_caller_symbol(thread): + """ + Returns the symbol name for the call site of the leaf function. + """ + depth = thread.GetNumFrames() + if depth <= 1: + return None + caller = thread.GetFrameAtIndex(1).GetSymbol() + if caller: + return caller.GetName() + else: + return None + + +def get_function_names(thread): + """ + Returns a sequence of function names from the stack frames of this thread. + """ + def GetFuncName(i): + return thread.GetFrameAtIndex(i).GetFunctionName() + + return [GetFuncName(i) for i in range(thread.GetNumFrames())] + + +def get_symbol_names(thread): + """ + Returns a sequence of symbols for this thread. + """ + def GetSymbol(i): + return thread.GetFrameAtIndex(i).GetSymbol().GetName() + + return [GetSymbol(i) for i in range(thread.GetNumFrames())] + + +def get_pc_addresses(thread): + """ + Returns a sequence of pc addresses for this thread. + """ + def GetPCAddress(i): + return thread.GetFrameAtIndex(i).GetPCAddress() + + return [GetPCAddress(i) for i in range(thread.GetNumFrames())] + + +def get_filenames(thread): + """ + Returns a sequence of file names from the stack frames of this thread. + """ + def GetFilename(i): + return thread.GetFrameAtIndex( + i).GetLineEntry().GetFileSpec().GetFilename() + + return [GetFilename(i) for i in range(thread.GetNumFrames())] + + +def get_line_numbers(thread): + """ + Returns a sequence of line numbers from the stack frames of this thread. + """ + def GetLineNumber(i): + return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() + + return [GetLineNumber(i) for i in range(thread.GetNumFrames())] + + +def get_module_names(thread): + """ + Returns a sequence of module names from the stack frames of this thread. + """ + def GetModuleName(i): + return thread.GetFrameAtIndex( + i).GetModule().GetFileSpec().GetFilename() + + return [GetModuleName(i) for i in range(thread.GetNumFrames())] + + +def get_stack_frames(thread): + """ + Returns a sequence of stack frames for this thread. + """ + def GetStackFrame(i): + return thread.GetFrameAtIndex(i) + + return [GetStackFrame(i) for i in range(thread.GetNumFrames())] + + +def print_stacktrace(thread, string_buffer=False): + """Prints a simple stack trace of this thread.""" + + output = io.StringIO() if string_buffer else sys.stdout + target = thread.GetProcess().GetTarget() + + depth = thread.GetNumFrames() + + mods = get_module_names(thread) + funcs = get_function_names(thread) + symbols = get_symbol_names(thread) + files = get_filenames(thread) + lines = get_line_numbers(thread) + addrs = get_pc_addresses(thread) + + if thread.GetStopReason() != lldb.eStopReasonInvalid: + desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) + else: + desc = "" + print("Stack trace for thread id={0:#x} name={1} queue={2} ".format( + thread.GetThreadID(), thread.GetName(), thread.GetQueueName()) + desc, file=output) + + 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(" frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format( + num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset), file=output) + else: + print(" 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 '()'), file=output) + + if string_buffer: + return output.getvalue() + + +def print_stacktraces(process, string_buffer=False): + """Prints the stack traces of all the threads.""" + + output = io.StringIO() if string_buffer else sys.stdout + + print("Stack traces for " + str(process), file=output) + + for thread in process: + print(print_stacktrace(thread, string_buffer=True), file=output) + + if string_buffer: + return output.getvalue() + +# =================================== +# Utility functions related to Frames +# =================================== + + +def get_parent_frame(frame): + """ + Returns the parent frame of the input frame object; None if not available. + """ + thread = frame.GetThread() + parent_found = False + for f in thread: + if parent_found: + return f + if f.GetFrameID() == frame.GetFrameID(): + parent_found = True + + # If we reach here, no parent has been found, return None. + return None + + +def get_args_as_string(frame, showFuncName=True): + """ + Returns the args of the input frame object as a string. + """ + # arguments => True + # locals => False + # statics => False + # in_scope_only => True + vars = frame.GetVariables(True, False, False, True) # type of SBValueList + args = [] # list of strings + for var in vars: + args.append("(%s)%s=%s" % (var.GetTypeName(), + var.GetName(), + var.GetValue())) + if frame.GetFunction(): + name = frame.GetFunction().GetName() + elif frame.GetSymbol(): + name = frame.GetSymbol().GetName() + else: + name = "" + if showFuncName: + return "%s(%s)" % (name, ", ".join(args)) + else: + return "(%s)" % (", ".join(args)) + + +def print_registers(frame, string_buffer=False): + """Prints all the register sets of the frame.""" + + output = io.StringIO() if string_buffer else sys.stdout + + print("Register sets for " + str(frame), file=output) + + registerSet = frame.GetRegisters() # Return type of SBValueList. + print("Frame registers (size of register set = %d):" % registerSet.GetSize( + ), file=output) + for value in registerSet: + #print >> output, value + print("%s (number of children = %d):" % ( + value.GetName(), value.GetNumChildren()), file=output) + for child in value: + print("Name: %s, Value: %s" % ( + child.GetName(), child.GetValue()), file=output) + + if string_buffer: + return output.getvalue() + + +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") + +# ====================================== +# Utility classes/functions for SBValues +# ====================================== + + +class BasicFormatter(object): + """The basic formatter inspects the value object and prints the value.""" + + def format(self, value, buffer=None, indent=0): + if not buffer: + output = io.StringIO() + else: + output = buffer + # If there is a summary, it suffices. + val = value.GetSummary() + # Otherwise, get the value. + if val is None: + val = value.GetValue() + if val is None and value.GetNumChildren() > 0: + val = "%s (location)" % value.GetLocation() + print("{indentation}({type}) {name} = {value}".format( + indentation=' ' * indent, + type=value.GetTypeName(), + name=value.GetName(), + value=val), file=output) + return output.getvalue() + + +class ChildVisitingFormatter(BasicFormatter): + """The child visiting formatter prints the value and its immediate children. + + The constructor takes a keyword arg: indent_child, which defaults to 2. + """ + + def __init__(self, indent_child=2): + """Default indentation of 2 SPC's for the children.""" + self.cindent = indent_child + + def format(self, value, buffer=None): + if not buffer: + output = io.StringIO() + else: + output = buffer + + BasicFormatter.format(self, value, buffer=output) + for child in value: + BasicFormatter.format( + self, child, buffer=output, indent=self.cindent) + + return output.getvalue() + + +class RecursiveDecentFormatter(BasicFormatter): + """The recursive decent formatter prints the value and the decendents. + + The constructor takes two keyword args: indent_level, which defaults to 0, + and indent_child, which defaults to 2. The current indentation level is + determined by indent_level, while the immediate children has an additional + indentation by inden_child. + """ + + def __init__(self, indent_level=0, indent_child=2): + self.lindent = indent_level + self.cindent = indent_child + + def format(self, value, buffer=None): + if not buffer: + output = io.StringIO() + else: + output = buffer + + BasicFormatter.format(self, value, buffer=output, indent=self.lindent) + new_indent = self.lindent + self.cindent + for child in value: + if child.GetSummary() is not None: + BasicFormatter.format( + self, child, buffer=output, indent=new_indent) + else: + if child.GetNumChildren() > 0: + rdf = RecursiveDecentFormatter(indent_level=new_indent) + rdf.format(child, buffer=output) + else: + BasicFormatter.format( + self, child, buffer=output, indent=new_indent) + + return output.getvalue() diff --git a/gnu/llvm/lldb/utils/lui/lui.py b/gnu/llvm/lldb/utils/lui/lui.py new file mode 100755 index 00000000000..98e1c63ce41 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/lui.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +##===-- lui.py -----------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + + +import curses + +import lldb +import lldbutil + +from optparse import OptionParser +import os +import signal +import sys + +try: + import queue +except ImportError: + import Queue as queue + +import debuggerdriver +import cui + +import breakwin +import commandwin +import eventwin +import sourcewin +import statuswin + +event_queue = None + + +def handle_args(driver, argv): + parser = OptionParser() + parser.add_option( + "-p", + "--attach", + dest="pid", + help="Attach to specified Process ID", + type="int") + parser.add_option( + "-c", + "--core", + dest="core", + help="Load specified core file", + type="string") + + (options, args) = parser.parse_args(argv) + + if options.pid is not None: + try: + pid = int(options.pid) + driver.attachProcess(ui, pid) + except ValueError: + print("Error: expecting integer PID, got '%s'" % options.pid) + elif options.core is not None: + if not os.path.exists(options.core): + raise Exception( + "Specified core file '%s' does not exist." % + options.core) + driver.loadCore(options.core) + elif len(args) == 2: + if not os.path.isfile(args[1]): + raise Exception("Specified target '%s' does not exist" % args[1]) + driver.createTarget(args[1]) + elif len(args) > 2: + if not os.path.isfile(args[1]): + raise Exception("Specified target '%s' does not exist" % args[1]) + driver.createTarget(args[1], args[2:]) + + +def sigint_handler(signal, frame): + global debugger + debugger.terminate() + + +class LLDBUI(cui.CursesUI): + + def __init__(self, screen, event_queue, driver): + super(LLDBUI, self).__init__(screen, event_queue) + + self.driver = driver + + h, w = self.screen.getmaxyx() + + command_win_height = 20 + break_win_width = 60 + + self.status_win = statuswin.StatusWin(0, h - 1, w, 1) + h -= 1 + self.command_win = commandwin.CommandWin( + driver, 0, h - command_win_height, w, command_win_height) + h -= command_win_height + self.source_win = sourcewin.SourceWin(driver, 0, 0, + w - break_win_width - 1, h) + self.break_win = breakwin.BreakWin(driver, w - break_win_width, 0, + break_win_width, h) + + self.wins = [self.status_win, + # self.event_win, + self.source_win, + self.break_win, + self.command_win, + ] + + self.focus = len(self.wins) - 1 # index of command window; + + def handleEvent(self, event): + # hack + if isinstance(event, int): + if event == curses.KEY_F10: + self.driver.terminate() + if event == 20: # ctrl-T + def foo(cmd): + ret = lldb.SBCommandReturnObject() + self.driver.getCommandInterpreter().HandleCommand(cmd, ret) + foo('target create a.out') + foo('b main') + foo('run') + super(LLDBUI, self).handleEvent(event) + + +def main(screen): + signal.signal(signal.SIGINT, sigint_handler) + + global event_queue + event_queue = queue.Queue() + + global debugger + debugger = lldb.SBDebugger.Create() + + driver = debuggerdriver.createDriver(debugger, event_queue) + view = LLDBUI(screen, event_queue, driver) + + driver.start() + + # hack to avoid hanging waiting for prompts! + driver.handleCommand("settings set auto-confirm true") + + handle_args(driver, sys.argv) + view.eventLoop() + +if __name__ == "__main__": + try: + curses.wrapper(main) + except KeyboardInterrupt: + exit() diff --git a/gnu/llvm/lldb/utils/lui/sandbox.py b/gnu/llvm/lldb/utils/lui/sandbox.py new file mode 100755 index 00000000000..8bb4e3595f8 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/sandbox.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +##===-- sandbox.py -------------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + + +import curses + +import os +import signal +import sys + +try: + import queue +except ImportError: + import Queue as queue + +import cui + +event_queue = None + + +class SandboxUI(cui.CursesUI): + + def __init__(self, screen, event_queue): + super(SandboxUI, self).__init__(screen, event_queue) + + height, width = self.screen.getmaxyx() + w2 = width / 2 + h2 = height / 2 + + self.wins = [] + #self.wins.append(cui.TitledWin(w2, h2, w2, h2, "Test Window 4")) + list_win = cui.ListWin(w2, h2, w2, h2) + for i in range(0, 40): + list_win.addItem('Item %s' % i) + self.wins.append(list_win) + self.wins.append(cui.TitledWin(0, 0, w2, h2, "Test Window 1")) + self.wins.append(cui.TitledWin(w2, 0, w2, h2, "Test Window 2")) + self.wins.append(cui.TitledWin(0, h2, w2, h2, "Test Window 3")) + + # def callback(s, content): + # self.wins[0].win.scroll(1) + # self.wins[0].win.addstr(10, 0, '%s: %s' % (s, content)) + # self.wins[0].win.scroll(1) + # self.el.showPrompt(10, 0) + + # self.wins[0].win.scrollok(1) + # self.el = cui.CursesEditLine(self.wins[0].win, None, + # lambda c: callback('got', c), lambda c: callback('tab', c)) + #self.el.prompt = '>>> ' + #self.el.showPrompt(10, 0) + + def handleEvent(self, event): + if isinstance(event, int): + if event == ord('q'): + sys.exit(0) + # self.el.handleEvent(event) + super(SandboxUI, self).handleEvent(event) + + +def main(screen): + global event_queue + event_queue = queue.Queue() + + sandbox = SandboxUI(screen, event_queue) + sandbox.eventLoop() + +if __name__ == "__main__": + try: + curses.wrapper(main) + except KeyboardInterrupt: + exit() diff --git a/gnu/llvm/lldb/utils/lui/sourcewin.py b/gnu/llvm/lldb/utils/lui/sourcewin.py new file mode 100644 index 00000000000..c3add058f12 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/sourcewin.py @@ -0,0 +1,238 @@ +##===-- sourcewin.py -----------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import cui +import curses +import lldb +import lldbutil +import re +import os + + +class SourceWin(cui.TitledWin): + + def __init__(self, driver, x, y, w, h): + super(SourceWin, self).__init__(x, y, w, h, "Source") + self.sourceman = driver.getSourceManager() + self.sources = {} + + self.filename = None + self.pc_line = None + self.viewline = 0 + + self.breakpoints = {} + + self.win.scrollok(1) + + self.markerPC = ":) " + self.markerBP = "B> " + self.markerNone = " " + + try: + from pygments.formatters import TerminalFormatter + self.formatter = TerminalFormatter() + except ImportError: + #self.win.addstr("\nWarning: no 'pygments' library found. Syntax highlighting is disabled.") + self.lexer = None + self.formatter = None + pass + + # FIXME: syntax highlight broken + self.formatter = None + self.lexer = None + + def handleEvent(self, event): + if isinstance(event, int): + self.handleKey(event) + return + + if isinstance(event, lldb.SBEvent): + if lldb.SBBreakpoint.EventIsBreakpointEvent(event): + self.handleBPEvent(event) + + if lldb.SBProcess.EventIsProcessEvent(event) and \ + not lldb.SBProcess.GetRestartedFromEvent(event): + process = lldb.SBProcess.GetProcessFromEvent(event) + if not process.IsValid(): + return + if process.GetState() == lldb.eStateStopped: + self.refreshSource(process) + elif process.GetState() == lldb.eStateExited: + self.notifyExited(process) + + def notifyExited(self, process): + self.win.erase() + target = lldbutil.get_description(process.GetTarget()) + pid = process.GetProcessID() + ec = process.GetExitStatus() + self.win.addstr( + "\nProcess %s [%d] has exited with exit-code %d" % + (target, pid, ec)) + + def pageUp(self): + if self.viewline > 0: + self.viewline = self.viewline - 1 + self.refreshSource() + + def pageDown(self): + if self.viewline < len(self.content) - self.height + 1: + self.viewline = self.viewline + 1 + self.refreshSource() + pass + + def handleKey(self, key): + if key == curses.KEY_DOWN: + self.pageDown() + elif key == curses.KEY_UP: + self.pageUp() + + def updateViewline(self): + half = self.height / 2 + if self.pc_line < half: + self.viewline = 0 + else: + self.viewline = self.pc_line - half + 1 + + if self.viewline < 0: + raise Exception( + "negative viewline: pc=%d viewline=%d" % + (self.pc_line, self.viewline)) + + def refreshSource(self, process=None): + (self.height, self.width) = self.win.getmaxyx() + + if process is not None: + loc = process.GetSelectedThread().GetSelectedFrame().GetLineEntry() + f = loc.GetFileSpec() + self.pc_line = loc.GetLine() + + if not f.IsValid(): + self.win.addstr(0, 0, "Invalid source file") + return + + self.filename = f.GetFilename() + path = os.path.join(f.GetDirectory(), self.filename) + self.setTitle(path) + self.content = self.getContent(path) + self.updateViewline() + + if self.filename is None: + return + + if self.formatter is not None: + from pygments.lexers import get_lexer_for_filename + self.lexer = get_lexer_for_filename(self.filename) + + bps = [] if not self.filename in self.breakpoints else self.breakpoints[self.filename] + self.win.erase() + if self.content: + self.formatContent(self.content, self.pc_line, bps) + + def getContent(self, path): + content = [] + if path in self.sources: + content = self.sources[path] + else: + if os.path.exists(path): + with open(path) as x: + content = x.readlines() + self.sources[path] = content + return content + + def formatContent(self, content, pc_line, breakpoints): + source = "" + count = 1 + self.win.erase() + end = min(len(content), self.viewline + self.height) + for i in range(self.viewline, end): + line_num = i + 1 + marker = self.markerNone + attr = curses.A_NORMAL + if line_num == pc_line: + attr = curses.A_REVERSE + if line_num in breakpoints: + marker = self.markerBP + line = "%s%3d %s" % (marker, line_num, self.highlight(content[i])) + if len(line) >= self.width: + line = line[0:self.width - 1] + "\n" + self.win.addstr(line, attr) + source += line + count = count + 1 + return source + + def highlight(self, source): + if self.lexer and self.formatter: + from pygments import highlight + return highlight(source, self.lexer, self.formatter) + else: + return source + + def addBPLocations(self, locations): + for path in locations: + lines = locations[path] + if path in self.breakpoints: + self.breakpoints[path].update(lines) + else: + self.breakpoints[path] = lines + + def removeBPLocations(self, locations): + for path in locations: + lines = locations[path] + if path in self.breakpoints: + self.breakpoints[path].difference_update(lines) + else: + raise "Removing locations that were never added...no good" + + def handleBPEvent(self, event): + def getLocations(event): + locs = {} + + bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) + + if bp.IsInternal(): + # don't show anything for internal breakpoints + return + + for location in bp: + # hack! getting the LineEntry via SBBreakpointLocation.GetAddress.GetLineEntry does not work good for + # inlined frames, so we get the description (which does take + # into account inlined functions) and parse it. + desc = lldbutil.get_description( + location, lldb.eDescriptionLevelFull) + match = re.search('at\ ([^:]+):([\d]+)', desc) + try: + path = match.group(1) + line = int(match.group(2).strip()) + except ValueError as e: + # bp loc unparsable + continue + + if path in locs: + locs[path].add(line) + else: + locs[path] = set([line]) + return locs + + event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) + if event_type == lldb.eBreakpointEventTypeEnabled \ + or event_type == lldb.eBreakpointEventTypeAdded \ + or event_type == lldb.eBreakpointEventTypeLocationsResolved \ + or event_type == lldb.eBreakpointEventTypeLocationsAdded: + self.addBPLocations(getLocations(event)) + elif event_type == lldb.eBreakpointEventTypeRemoved \ + or event_type == lldb.eBreakpointEventTypeLocationsRemoved \ + or event_type == lldb.eBreakpointEventTypeDisabled: + self.removeBPLocations(getLocations(event)) + elif event_type == lldb.eBreakpointEventTypeCommandChanged \ + or event_type == lldb.eBreakpointEventTypeConditionChanged \ + or event_type == lldb.eBreakpointEventTypeIgnoreChanged \ + or event_type == lldb.eBreakpointEventTypeThreadChanged \ + or event_type == lldb.eBreakpointEventTypeInvalidType: + # no-op + pass + self.refreshSource() diff --git a/gnu/llvm/lldb/utils/lui/statuswin.py b/gnu/llvm/lldb/utils/lui/statuswin.py new file mode 100644 index 00000000000..2d3cc217c01 --- /dev/null +++ b/gnu/llvm/lldb/utils/lui/statuswin.py @@ -0,0 +1,41 @@ +##===-- statuswin.py -----------------------------------------*- Python -*-===## +## +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +## +##===----------------------------------------------------------------------===## + +import lldb +import lldbutil +import cui +import curses + + +class StatusWin(cui.TextWin): + + def __init__(self, x, y, w, h): + super(StatusWin, self).__init__(x, y, w) + + self.keys = [ # ('F1', 'Help', curses.KEY_F1), + ('F3', 'Cycle-focus', curses.KEY_F3), + ('F10', 'Quit', curses.KEY_F10)] + + def draw(self): + self.win.addstr(0, 0, '') + for key in self.keys: + self.win.addstr('{0}'.format(key[0]), curses.A_REVERSE) + self.win.addstr(' {0} '.format(key[1]), curses.A_NORMAL) + super(StatusWin, self).draw() + + def handleEvent(self, event): + if isinstance(event, int): + pass + elif isinstance(event, lldb.SBEvent): + if lldb.SBProcess.EventIsProcessEvent(event): + state = lldb.SBProcess.GetStateFromEvent(event) + status = lldbutil.state_type_to_str(state) + self.win.erase() + x = self.win.getmaxyx()[1] - len(status) - 1 + self.win.addstr(0, x, status) + return diff --git a/gnu/llvm/lldb/utils/test/README-disasm b/gnu/llvm/lldb/utils/test/README-disasm new file mode 100644 index 00000000000..00e9ab681a2 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/README-disasm @@ -0,0 +1,406 @@ +This README describes a sample invocation of disasm.py whose purpose is to test +the low level ARM/Thumb disassembly functionality from llvm using the llvm-mc +command line. We invoke gdb on an executable, try to disassemble a function, +and then read the memory contents of the disassembled function. + +The byte contents are written into a file named disasm-input.txt and then we +invoke llvm-mc -disassemble plus options (set with the -o/--options) on the +byte contents. + +See the following for a sample session using this command: + +[16:26:57] johnny:/Volumes/data/Radar/9131529 $ /Volumes/data/lldb/svn/trunk/utils/test/disasm.py -C 'set shlib-path-substitutions /usr /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr /System /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System /Library /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/Library' -O '-arch armv7' -m /Volumes/data/lldb/llvm/Debug+Asserts/bin/llvm-mc -e /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib -f printf --options='-triple=thumb-apple-darwin -debug-only=arm-disassembler' +gdb commands: ['set shlib-path-substitutions /usr /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr /System /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System /Library /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/Library'] +gdb options: -arch armv7 +executable: /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib +function: printf +llvm-mc: /Volumes/data/lldb/llvm/Debug+Asserts/bin/llvm-mc +llvm-mc options: -triple=thumb-apple-darwin -debug-only=arm-disassembler +GNU gdb 6.3.50-20050815 (Apple version gdb-1518) (Sat Feb 12 02:56:02 UTC 2011) +Copyright 2004 Free Software Foundation, Inc. +GDB is free software, covered by the GNU General Public License, and you are +welcome to change it and/or distribute copies of it under certain conditions. +Type "show copying" to see the conditions. +There is absolutely no warranty for GDB. Type "show warranty" for details. +This GDB was configured as "--host=x86_64-apple-darwin --target=arm-apple-darwin". +<Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/Library +<eloper/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib +Reading symbols for shared libraries ................ done +Reading symbols from /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib...done. +(gdb) disassemble printf +Dump of assembler code for function printf: +0x0704cdd0 <printf+0>: push {r0, r1, r2, r3} +0x0704cdd2 <printf+2>: push {r4, r5, r7, lr} +0x0704cdd4 <printf+4>: add r7, sp, #8 +0x0704cdd6 <printf+6>: sub sp, #4 +0x0704cdd8 <printf+8>: add r3, sp, #20 +0x0704cdda <printf+10>: ldr.w r5, [r3], #4 +0x0704cdde <printf+14>: str r3, [sp, #0] +0x0704cde0 <printf+16>: ldr r3, [pc, #52] (0x704ce18 <printf+72>) +0x0704cde2 <printf+18>: add r3, pc +0x0704cde4 <printf+20>: ldr r0, [r3, #0] +0x0704cde6 <printf+22>: ldr r4, [r0, #0] +0x0704cde8 <printf+24>: ldr r0, [pc, #48] (0x704ce1c <printf+76>) +0x0704cdea <printf+26>: add r0, pc +0x0704cdec <printf+28>: ldr r0, [r0, #0] +0x0704cdee <printf+30>: ldr r0, [r0, #0] +0x0704cdf0 <printf+32>: blx 0x707ba30 <pthread_getspecific> +0x0704cdf4 <printf+36>: cbnz r0, 0x704cdfe <printf+46> +0x0704cdf6 <printf+38>: ldr r1, [pc, #40] (0x704ce20 <printf+80>) +0x0704cdf8 <printf+40>: add r1, pc +0x0704cdfa <printf+42>: ldr r1, [r1, #0] +0x0704cdfc <printf+44>: b.n 0x704ce00 <printf+48> +0x0704cdfe <printf+46>: mov r1, r0 +0x0704ce00 <printf+48>: mov r0, r4 +0x0704ce02 <printf+50>: mov r2, r5 +0x0704ce04 <printf+52>: ldr r3, [sp, #0] +0x0704ce06 <printf+54>: bl 0x704ad44 <vfprintf_l> +0x0704ce0a <printf+58>: sub.w sp, r7, #8 ; 0x8 +0x0704ce0e <printf+62>: ldmia.w sp!, {r4, r5, r7, lr} +0x0704ce12 <printf+66>: add sp, #16 +0x0704ce14 <printf+68>: bx lr +0x0704ce16 <printf+70>: nop +0x0704ce18 <printf+72>: movs r3, #142 +0x0704ce1a <printf+74>: lsls r5, r0, #0 +0x0704ce1c <printf+76>: adds r1, #122 +0x0704ce1e <printf+78>: lsls r5, r0, #0 +0x0704ce20 <printf+80>: adds r1, #104 +0x0704ce22 <printf+82>: lsls r5, r0, #0 +End of assembler dump. +(gdb) x /2b 0x0704cdd0 +0x704cdd0 <printf>: 0x0f 0xb4 +(gdb) x /2b 0x0704cdd2 +0x704cdd2 <printf+2>: 0xb0 0xb5 +(gdb) x /2b 0x0704cdd4 +0x704cdd4 <printf+4>: 0x02 0xaf +(gdb) x /2b 0x0704cdd6 +0x704cdd6 <printf+6>: 0x81 0xb0 +(gdb) x /2b 0x0704cdd8 +0x704cdd8 <printf+8>: 0x05 0xab +(gdb) x /4b 0x0704cdda +0x704cdda <printf+10>: 0x53 0xf8 0x04 0x5b +(gdb) x /2b 0x0704cdde +0x704cdde <printf+14>: 0x00 0x93 +(gdb) x /2b 0x0704cde0 +0x704cde0 <printf+16>: 0x0d 0x4b +(gdb) x /2b 0x0704cde2 +0x704cde2 <printf+18>: 0x7b 0x44 +(gdb) x /2b 0x0704cde4 +0x704cde4 <printf+20>: 0x18 0x68 +(gdb) x /2b 0x0704cde6 +0x704cde6 <printf+22>: 0x04 0x68 +(gdb) x /2b 0x0704cde8 +0x704cde8 <printf+24>: 0x0c 0x48 +(gdb) x /2b 0x0704cdea +0x704cdea <printf+26>: 0x78 0x44 +(gdb) x /2b 0x0704cdec +0x704cdec <printf+28>: 0x00 0x68 +(gdb) x /2b 0x0704cdee +0x704cdee <printf+30>: 0x00 0x68 +(gdb) x /4b 0x0704cdf0 +0x704cdf0 <printf+32>: 0x2e 0xf0 0x1e 0xee +(gdb) x /2b 0x0704cdf4 +0x704cdf4 <printf+36>: 0x18 0xb9 +(gdb) x /2b 0x0704cdf6 +0x704cdf6 <printf+38>: 0x0a 0x49 +(gdb) x /2b 0x0704cdf8 +0x704cdf8 <printf+40>: 0x79 0x44 +(gdb) x /2b 0x0704cdfa +0x704cdfa <printf+42>: 0x09 0x68 +(gdb) x /2b 0x0704cdfc +0x704cdfc <printf+44>: 0x00 0xe0 +(gdb) x /2b 0x0704cdfe +0x704cdfe <printf+46>: 0x01 0x46 +(gdb) x /2b 0x0704ce00 +0x704ce00 <printf+48>: 0x20 0x46 +(gdb) x /2b 0x0704ce02 +0x704ce02 <printf+50>: 0x2a 0x46 +(gdb) x /2b 0x0704ce04 +0x704ce04 <printf+52>: 0x00 0x9b +(gdb) x /4b 0x0704ce06 +0x704ce06 <printf+54>: 0xfd 0xf7 0x9d 0xff +(gdb) x /4b 0x0704ce0a +0x704ce0a <printf+58>: 0xa7 0xf1 0x08 0x0d +(gdb) x /4b 0x0704ce0e +0x704ce0e <printf+62>: 0xbd 0xe8 0xb0 0x40 +(gdb) x /2b 0x0704ce12 +0x704ce12 <printf+66>: 0x04 0xb0 +(gdb) x /2b 0x0704ce14 +0x704ce14 <printf+68>: 0x70 0x47 +(gdb) x /2b 0x0704ce16 +0x704ce16 <printf+70>: 0x00 0xbf +(gdb) x /2b 0x0704ce18 +0x704ce18 <printf+72>: 0x8e 0x23 +(gdb) x /2b 0x0704ce1a +0x704ce1a <printf+74>: 0x05 0x00 +(gdb) x /2b 0x0704ce1c +0x704ce1c <printf+76>: 0x7a 0x31 +(gdb) x /2b 0x0704ce1e +0x704ce1e <printf+78>: 0x05 0x00 +(gdb) x /2b 0x0704ce20 +0x704ce20 <printf+80>: 0x68 0x31 +(gdb) x /2b 0x0704ce22 +0x704ce22 <printf+82>: 0x05 0x00 +(gdb) quit + +Executing command: /Volumes/data/lldb/llvm/Debug+Asserts/bin/llvm-mc -disassemble -triple=thumb-apple-darwin -debug-only=arm-disassembler disasm-input.txt +Opcode=2305 Name=tPUSH Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 0: 1: 0: 0| 0: 0: 0: 0| 1: 1: 1: 1| +------------------------------------------------------------------------------------------------- + + push {r0, r1, r2, r3} +Opcode=2305 Name=tPUSH Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 0: 1: 0: 1| 1: 0: 1: 1| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + push {r4, r5, r7, lr} +Opcode=2228 Name=tADDrSPi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 0| 1: 1: 1: 1| 0: 0: 0: 0| 0: 0: 1: 0| +------------------------------------------------------------------------------------------------- + + add r7, sp, #8 +Opcode=2328 Name=tSUBspi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 0: 0: 0: 0| 1: 0: 0: 0| 0: 0: 0: 1| +------------------------------------------------------------------------------------------------- + + sub sp, #4 +Opcode=2228 Name=tADDrSPi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 0| 1: 0: 1: 1| 0: 0: 0: 0| 0: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + add r3, sp, #20 +Opcode=1963 Name=t2LDR_POST Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 1: 1: 1: 1| 1: 0: 0: 0| 0: 1: 0: 1| 0: 0: 1: 1| 0: 1: 0: 1| 1: 0: 1: 1| 0: 0: 0: 0| 0: 1: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r5, [r3], #4 +Opcode=2324 Name=tSTRspi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 0: 1| 0: 0: 1: 1| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + str r3, [sp] +Opcode=2275 Name=tLDRpci Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 1: 0: 1: 1| 0: 0: 0: 0| 1: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + ldr.n r3, #52 +Opcode=2223 Name=tADDhirr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 0: 0| 0: 1: 1: 1| 1: 0: 1: 1| +------------------------------------------------------------------------------------------------- + + add r3, pc +Opcode=2274 Name=tLDRi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 1: 0| 1: 0: 0: 0| 0: 0: 0: 1| 1: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r0, [r3] +Opcode=2274 Name=tLDRi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 1: 0| 1: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r4, [r0] +Opcode=2275 Name=tLDRpci Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 1: 0: 0: 0| 0: 0: 0: 0| 1: 1: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr.n r0, #48 +Opcode=2223 Name=tADDhirr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 0: 0| 0: 1: 1: 1| 1: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + add r0, pc +Opcode=2274 Name=tLDRi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 1: 0| 1: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r0, [r0] +Opcode=2274 Name=tLDRi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 1: 0| 1: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r0, [r0] +Opcode=2243 Name=tBLXi_r9 Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 1: 1: 1: 1| 0: 0: 0: 0| 0: 0: 1: 0| 1: 1: 1: 0| 1: 1: 1: 0| 1: 1: 1: 0| 0: 0: 0: 1| 1: 1: 1: 0| +------------------------------------------------------------------------------------------------- + + blx #191548 +Opcode=2255 Name=tCBNZ Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 1: 0: 0: 1| 0: 0: 0: 1| 1: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + cbnz r0, #6 +Opcode=2275 Name=tLDRpci Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 1: 0: 0: 1| 0: 0: 0: 0| 1: 0: 1: 0| +------------------------------------------------------------------------------------------------- + + ldr.n r1, #40 +Opcode=2223 Name=tADDhirr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 0: 0| 0: 1: 1: 1| 1: 0: 0: 1| +------------------------------------------------------------------------------------------------- + + add r1, pc +Opcode=2274 Name=tLDRi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 1: 0| 1: 0: 0: 0| 0: 0: 0: 0| 1: 0: 0: 1| +------------------------------------------------------------------------------------------------- + + ldr r1, [r1] +Opcode=2238 Name=tB Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 1: 1: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + b #0 +Opcode=2294 Name=tMOVr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 1: 0| 0: 0: 0: 0| 0: 0: 0: 1| +------------------------------------------------------------------------------------------------- + + mov r1, r0 +Opcode=2294 Name=tMOVr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 1: 0| 0: 0: 1: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + mov r0, r4 +Opcode=2294 Name=tMOVr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 1: 0| 0: 0: 1: 0| 1: 0: 1: 0| +------------------------------------------------------------------------------------------------- + + mov r2, r5 +Opcode=2278 Name=tLDRspi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 0: 1| 1: 0: 1: 1| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + ldr r3, [sp] +Opcode=2246 Name=tBLr9 Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 1: 1: 1: 1| 0: 1: 1: 1| 1: 1: 1: 1| 1: 1: 0: 1| 1: 1: 1: 1| 1: 1: 1: 1| 1: 0: 0: 1| 1: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + bl #-8390 +Opcode=2153 Name=t2SUBri Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 1: 1: 1: 1| 0: 0: 0: 1| 1: 0: 1: 0| 0: 1: 1: 1| 0: 0: 0: 0| 1: 1: 0: 1| 0: 0: 0: 0| 1: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + sub.w sp, r7, #8 +Opcode=1926 Name=t2LDMIA_UPD Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 1: 1: 1: 0| 1: 0: 0: 0| 1: 0: 1: 1| 1: 1: 0: 1| 0: 1: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + pop.w {r4, r5, r7, lr} +Opcode=2230 Name=tADDspi Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| +------------------------------------------------------------------------------------------------- + + add sp, #16 +Opcode=2250 Name=tBX_RET Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 0| 0: 1: 1: 1| 0: 1: 1: 1| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + bx lr +Opcode=2300 Name=tNOP Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 1: 0: 1: 1| 1: 1: 1: 1| 0: 0: 0: 0| 0: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + nop +Opcode=2293 Name=tMOVi8 Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 1: 0| 0: 0: 1: 1| 1: 0: 0: 0| 1: 1: 1: 0| +------------------------------------------------------------------------------------------------- + + movs r3, #142 +Opcode=2290 Name=tMOVSr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + movs r5, r0 +Opcode=2225 Name=tADDi8 Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 1: 1| 0: 0: 0: 1| 0: 1: 1: 1| 1: 0: 1: 0| +------------------------------------------------------------------------------------------------- + + adds r1, #122 +Opcode=2290 Name=tMOVSr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + movs r5, r0 +Opcode=2225 Name=tADDi8 Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 1: 1| 0: 0: 0: 1| 0: 1: 1: 0| 1: 0: 0: 0| +------------------------------------------------------------------------------------------------- + + adds r1, #104 +Opcode=2290 Name=tMOVSr Format=ARM_FORMAT_THUMBFRM(25) + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +------------------------------------------------------------------------------------------------- +| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 0: 0: 0| 0: 1: 0: 1| +------------------------------------------------------------------------------------------------- + + movs r5, r0 +[16:28:00] johnny:/Volumes/data/Radar/9131529 $ diff --git a/gnu/llvm/lldb/utils/test/README-lldb-disasm b/gnu/llvm/lldb/utils/test/README-lldb-disasm new file mode 100644 index 00000000000..328658c326b --- /dev/null +++ b/gnu/llvm/lldb/utils/test/README-lldb-disasm @@ -0,0 +1,94 @@ +This README describes a sample invocation of lldb-disasm.py whose purpose is to test +the lldb 'disassemble' command. + +This is for the initial checkin of lldb-disasm.py which only reads an executable image and +dumps the symbol table from the imgae and its dependent libraries. The output was cut off +since it is too large. + +da0603a-dhcp191:9131529 johnny$ /Volumes/data/lldb/svn/trunk/utils/test/lldb-disasm.py -C 'platform create remote-ios' -e /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib +lldb commands: ['platform create remote-ios'] +lldb options: None +executable: /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib +sys.path: ['/Volumes/data/lldb/svn/trunk/utils/test', '/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python26.zip', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac/lib-scriptpackages', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-old', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-dynload', '/Library/Python/2.6/site-packages', '/AppleInternal/Library/Python/2.6/site-packages', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/wx-2.8-mac-unicode', '/Volumes/data/lldb/svn/trunk/utils/test/../../test/pexpect-2.4', '/Volumes/data/lldb/svn/trunk/test'] +/Volumes/data/lldb/svn/trunk/test/lldbutil.py:80: SyntaxWarning: import * only allowed at module level + def int_to_bytearray(val, bytesize): +/Volumes/data/lldb/svn/trunk/test/lldbutil.py:105: SyntaxWarning: import * only allowed at module level + def bytearray_to_int(bytes, bytesize): +run command: platform create remote-ios +output: Platform: remote-ios +Not connected to a remote platform. +SDKROOT: "/Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3 (8F190)" + +run command: file /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib +output: Current executable set to '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib' (armv7). + +run command: image dump symtab +output: Dumping symbol table for 18 modules. +Symtab, file = /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/usr/lib/libSystem.B.dylib, num_symbols = 851: + Debug symbol + |Synthetic symbol + ||Externally Visible + ||| +Index UserID DSX Type File Address/Value Load Address Size Flags Name +------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ---------------------------------- +[ 0] 0 Code 0x0000000000001420 0x0000000000000000 0x000e0008 libSystem_initializer +[ 1] 1 Code 0x00000000000014c4 0x0000000000000000 0x001e0008 __keymgr_initializer +[ 2] 2 Code 0x00000000000014fc 0x0000000000000000 0x000e0008 dwarf2_unwind_dyld_add_image_hook +[ 3] 3 Code 0x0000000000001564 0x0000000000000000 0x000e0008 get_or_create_key_element +[ 4] 4 Code 0x0000000000001684 0x0000000000000000 0x000e0008 unlock_node +[ 5] 5 Code 0x0000000000001930 0x0000000000000000 0x000e0000 RsqrtTable +[ 6] 6 Code 0x0000000000001c30 0x0000000000000000 0x000e0000 acosf_crossover +[ 7] 7 Code 0x0000000000001c34 0x0000000000000000 0x000e0000 acosf_mid_poly +[ 8] 8 Code 0x0000000000001c48 0x0000000000000000 0x000e0000 Pi2_Q30 +[ 9] 9 Code 0x0000000000001c4c 0x0000000000000000 0x000e0000 Pi_Q30 +[ 10] 10 Code 0x0000000000001c78 0x0000000000000000 0x000e0000 acosf_approx +[ 11] 11 Code 0x0000000000001cec 0x0000000000000000 0x000e0000 acosf_pos_tail_poly +[ 12] 12 Code 0x0000000000001d00 0x0000000000000000 0x000e0000 acosf_tail +[ 13] 13 Code 0x0000000000001dfc 0x0000000000000000 0x000e0000 acosf_normalize +[ 14] 14 Code 0x0000000000001e10 0x0000000000000000 0x000e0000 acosf_round +[ 15] 15 Code 0x0000000000001e28 0x0000000000000000 0x000e0000 acosf_encode +[ 16] 16 Code 0x0000000000001e30 0x0000000000000000 0x000e0000 acosf_done +[ 17] 17 Code 0x0000000000001e38 0x0000000000000000 0x000e0000 acosf_special +[ 18] 18 Code 0x0000000000001e68 0x0000000000000000 0x000e0000 acosf_small +[ 19] 19 Code 0x0000000000001e9c 0x0000000000000000 0x000e0000 acosf_very_small +[ 20] 20 Code 0x0000000000001eb8 0x0000000000000000 0x000e0000 Pif +[ 21] 21 Code 0x000000000000220c 0x0000000000000000 0x000e0000 RsqrtTable +[ 22] 22 Code 0x000000000000250c 0x0000000000000000 0x000e0000 asinf_crossover +[ 23] 23 Code 0x0000000000002510 0x0000000000000000 0x000e0000 asinf_mid_poly +[ 24] 24 Code 0x0000000000002524 0x0000000000000000 0x000e0000 Pi2_Q30 +[ 25] 25 Code 0x0000000000002550 0x0000000000000000 0x000e0000 asinf_approx +[ 26] 26 Code 0x00000000000025e4 0x0000000000000000 0x000e0000 asinf_tail_poly +[ 27] 27 Code 0x0000000000002600 0x0000000000000000 0x000e0000 asinf_tail +[ 28] 28 Code 0x00000000000026e0 0x0000000000000000 0x000e0000 asinf_normalize +[ 29] 29 Code 0x00000000000026f4 0x0000000000000000 0x000e0000 asinf_round +[ 30] 30 Code 0x000000000000270c 0x0000000000000000 0x000e0000 asinf_encode +[ 31] 31 Code 0x0000000000002718 0x0000000000000000 0x000e0000 asinf_done +[ 32] 32 Code 0x0000000000002720 0x0000000000000000 0x000e0000 asinf_special +[ 33] 33 Code 0x0000000000002754 0x0000000000000000 0x000e0000 asinf_small +[ 34] 34 Code 0x0000000000002784 0x0000000000000000 0x000e0000 Pi2f +[ 35] 35 Code 0x0000000000005774 0x0000000000000000 0x000e0008 rem_pio2 +[ 36] 36 Code 0x00000000000076c4 0x0000000000000000 0x000e0008 __kernel_rem_pio2 +[ 37] 37 Code 0x0000000000008c90 0x0000000000000000 0x000e0008 __kernel_tan +[ 38] 38 Code 0x0000000000008ef0 0x0000000000000000 0x000e0008 lgammaApprox +[ 39] 39 Code 0x000000000000b3d4 0x0000000000000000 0x000e0000 powf_not_special +[ 40] 40 Code 0x000000000000b3dc 0x0000000000000000 0x000e0000 powf_ylgx +[ 41] 41 Code 0x000000000000b438 0x0000000000000000 0x000e0000 powf_done +[ 42] 42 Code 0x000000000000b43c 0x0000000000000000 0x000e0000 powf_special_y +[ 43] 43 Code 0x000000000000b4a8 0x0000000000000000 0x000e0000 powf_special_x +[ 44] 44 Code 0x000000000000b4cc 0x0000000000000000 0x000e0000 powf_mzero_minf +[ 45] 45 Code 0x000000000000b54c 0x0000000000000000 0x000e0000 powf_y_odd +[ 46] 46 Code 0x000000000000b57c 0x0000000000000000 0x000e0000 powf_y_nonint +[ 47] 47 Code 0x000000000000b588 0x0000000000000000 0x000e0000 powf_y_even +[ 48] 48 Code 0x000000000000b7a8 0x0000000000000000 0x000e0000 powf_log2_reduction +[ 49] 49 Code 0x000000000000b7a8 0x0000000000000000 0x000e0000 powf_log2 +[ 50] 50 Code 0x000000000000b814 0x0000000000000000 0x000e0000 powf_log2_approx +[ 51] 51 Code 0x000000000000b88c 0x0000000000000000 0x000e0000 powf_log2_synthesis +[ 52] 52 Code 0x000000000000b960 0x0000000000000000 0x000e0000 powf_log2_exactPowerOfTwo +[ 53] 53 Code 0x000000000000b980 0x0000000000000000 0x000e0000 powf_log2_near1 +[ 54] 54 Code 0x000000000000b9ec 0x0000000000000000 0x000e0000 powf_log2_synthesis_near1 +[ 55] 55 Code 0x000000000000ba04 0x0000000000000000 0x000e0000 Q32_minimax +[ 56] 56 Code 0x000000000000ba10 0x0000000000000000 0x000e0000 iexp2_lut +[ 57] 57 Code 0x000000000000ba94 0x0000000000000000 0x000e0000 powf_exp2 +[ 58] 58 Code 0x000000000000bb18 0x0000000000000000 0x000e0000 powf_exp2_exact_int +[ 59] 59 Code 0x000000000000bb24 0x0000000000000000 0x000e0000 powf_exp2_big +[ 60] 60 Code 0x000000000000bb74 0x0000000000000000 0x000e0000 powf_exp2_overflow diff --git a/gnu/llvm/lldb/utils/test/README-run-until-faulted b/gnu/llvm/lldb/utils/test/README-run-until-faulted new file mode 100644 index 00000000000..f89f8636d62 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/README-run-until-faulted @@ -0,0 +1,18 @@ +A example usage of the Python script run-until-faulted.py: + +[18:20:29] johnny:/Volumes/data/lldb/svn/trunk/utils/test $ ./run-until-faulted.py -l /Volumes/data/lldb/svn/trunk/build/Debug/lldb -e './a.out' +lldb command: /Volumes/data/lldb/svn/trunk/build/Debug/lldb +executable: ./a.out +executable options: +sending file command.... +sending process launch -- (iteration: 0) + +* thread #1: tid = 0x2d03, 0x0000000100000eef a.out`main + 39 at main.c:7, stop reason = EXC_BAD_ACCESS (code=1, address=0x0) + 4 { + 5 int *null_ptr = 0; + 6 printf("Hello, fault!\n"); +-> 7 printf("Now segfault %d\n", *null_ptr); + 8 } + +(lldb) q +[18:20:40] johnny:/Volumes/data/lldb/svn/trunk/utils/test $ diff --git a/gnu/llvm/lldb/utils/test/disasm.py b/gnu/llvm/lldb/utils/test/disasm.py new file mode 100755 index 00000000000..7d95d893747 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/disasm.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python + +""" +Run gdb to disassemble a function, feed the bytes to 'llvm-mc -disassemble' command, +and display the disassembly result. + +""" + +from __future__ import print_function + +import os +import sys +from optparse import OptionParser + + +def is_exe(fpath): + """Check whether fpath is an executable.""" + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + +def which(program): + """Find the full path to a program, or return None.""" + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + return None + + +def do_llvm_mc_disassembly( + gdb_commands, + gdb_options, + exe, + func, + mc, + mc_options): + from io import StringIO + import pexpect + + gdb_prompt = "\r\n\(gdb\) " + gdb = pexpect.spawn(('gdb %s' % gdb_options) if gdb_options else 'gdb') + # Turn on logging for what gdb sends back. + gdb.logfile_read = sys.stdout + gdb.expect(gdb_prompt) + + # See if there any extra command(s) to execute before we issue the file + # command. + for cmd in gdb_commands: + gdb.sendline(cmd) + gdb.expect(gdb_prompt) + + # Now issue the file command. + gdb.sendline('file %s' % exe) + gdb.expect(gdb_prompt) + + # Send the disassemble command. + gdb.sendline('disassemble %s' % func) + gdb.expect(gdb_prompt) + + # Get the output from gdb. + gdb_output = gdb.before + + # Use StringIO to record the memory dump as well as the gdb assembler code. + mc_input = StringIO() + + # These keep track of the states of our simple gdb_output parser. + prev_line = None + prev_addr = None + curr_addr = None + addr_diff = 0 + looking = False + for line in gdb_output.split(os.linesep): + if line.startswith('Dump of assembler code'): + looking = True + continue + + if line.startswith('End of assembler dump.'): + looking = False + prev_addr = curr_addr + if mc_options and mc_options.find('arm') != -1: + addr_diff = 4 + if mc_options and mc_options.find('thumb') != -1: + # It is obviously wrong to assume the last instruction of the + # function has two bytes. + # FIXME + addr_diff = 2 + + if looking and line.startswith('0x'): + # It's an assembler code dump. + prev_addr = curr_addr + curr_addr = line.split(None, 1)[0] + if prev_addr and curr_addr: + addr_diff = int(curr_addr, 16) - int(prev_addr, 16) + + if prev_addr and addr_diff > 0: + # Feed the examining memory command to gdb. + gdb.sendline('x /%db %s' % (addr_diff, prev_addr)) + gdb.expect(gdb_prompt) + x_output = gdb.before + # Get the last output line from the gdb examine memory command, + # split the string into a 3-tuple with separator '>:' to handle + # objc method names. + memory_dump = x_output.split( + os.linesep)[-1].partition('>:')[2].strip() + # print "\nbytes:", memory_dump + disasm_str = prev_line.partition('>:')[2] + print('%s # %s' % (memory_dump, disasm_str), file=mc_input) + + # We're done with the processing. Assign the current line to be + # prev_line. + prev_line = line + + # Close the gdb session now that we are done with it. + gdb.sendline('quit') + gdb.expect(pexpect.EOF) + gdb.close() + + # Write the memory dump into a file. + with open('disasm-input.txt', 'w') as f: + f.write(mc_input.getvalue()) + + mc_cmd = '%s -disassemble %s disasm-input.txt' % (mc, mc_options) + print("\nExecuting command:", mc_cmd) + os.system(mc_cmd) + + # And invoke llvm-mc with the just recorded file. + #mc = pexpect.spawn('%s -disassemble %s disasm-input.txt' % (mc, mc_options)) + #mc.logfile_read = sys.stdout + # print "mc:", mc + # mc.close() + + +def main(): + # This is to set up the Python path to include the pexpect-2.4 dir. + # Remember to update this when/if things change. + scriptPath = sys.path[0] + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) + + parser = OptionParser(usage="""\ +Run gdb to disassemble a function, feed the bytes to 'llvm-mc -disassemble' command, +and display the disassembly result. + +Usage: %prog [options] +""") + parser.add_option( + '-C', + '--gdb-command', + type='string', + action='append', + metavar='COMMAND', + default=[], + dest='gdb_commands', + help='Command(s) gdb executes after starting up (can be empty)') + parser.add_option( + '-O', + '--gdb-options', + type='string', + action='store', + dest='gdb_options', + help="""The options passed to 'gdb' command if specified.""") + parser.add_option('-e', '--executable', + type='string', action='store', + dest='executable', + help="""The executable to do disassembly on.""") + parser.add_option( + '-f', + '--function', + type='string', + action='store', + dest='function', + help="""The function name (could be an address to gdb) for disassembly.""") + parser.add_option('-m', '--llvm-mc', + type='string', action='store', + dest='llvm_mc', + help="""The llvm-mc executable full path, if specified. + Otherwise, it must be present in your PATH environment.""") + + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='llvm_mc_options', + help="""The options passed to 'llvm-mc -disassemble' command if specified.""") + + opts, args = parser.parse_args() + + gdb_commands = opts.gdb_commands + gdb_options = opts.gdb_options + + if not opts.executable: + parser.print_help() + sys.exit(1) + executable = opts.executable + + if not opts.function: + parser.print_help() + sys.exit(1) + function = opts.function + + llvm_mc = opts.llvm_mc if opts.llvm_mc else which('llvm-mc') + if not llvm_mc: + parser.print_help() + sys.exit(1) + + # This is optional. For example: + # --options='-triple=arm-apple-darwin -debug-only=arm-disassembler' + llvm_mc_options = opts.llvm_mc_options + + # We have parsed the options. + print("gdb commands:", gdb_commands) + print("gdb options:", gdb_options) + print("executable:", executable) + print("function:", function) + print("llvm-mc:", llvm_mc) + print("llvm-mc options:", llvm_mc_options) + + do_llvm_mc_disassembly( + gdb_commands, + gdb_options, + executable, + function, + llvm_mc, + llvm_mc_options) + +if __name__ == '__main__': + main() diff --git a/gnu/llvm/lldb/utils/test/lldb-disasm.py b/gnu/llvm/lldb/utils/test/lldb-disasm.py new file mode 100755 index 00000000000..339e8e7caba --- /dev/null +++ b/gnu/llvm/lldb/utils/test/lldb-disasm.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python + +""" +Run lldb to disassemble all the available functions for an executable image. + +""" + +from __future__ import print_function + +import os +import re +import sys +from optparse import OptionParser + + +def setupSysPath(): + """ + Add LLDB.framework/Resources/Python and the test dir to the sys.path. + """ + # Get the directory containing the current script. + scriptPath = sys.path[0] + if not scriptPath.endswith(os.path.join('utils', 'test')): + print("This script expects to reside in lldb's utils/test directory.") + sys.exit(-1) + + # This is our base name component. + base = os.path.abspath(os.path.join(scriptPath, os.pardir, os.pardir)) + + # This is for the goodies in the test directory under base. + sys.path.append(os.path.join(base, 'test')) + + # These are for xcode build directories. + xcode3_build_dir = ['build'] + xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] + dbg = ['Debug'] + rel = ['Release'] + bai = ['BuildAndIntegration'] + python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] + + dbgPath = os.path.join( + base, *(xcode3_build_dir + dbg + python_resource_dir)) + dbgPath2 = os.path.join( + base, *(xcode4_build_dir + dbg + python_resource_dir)) + relPath = os.path.join( + base, *(xcode3_build_dir + rel + python_resource_dir)) + relPath2 = os.path.join( + base, *(xcode4_build_dir + rel + python_resource_dir)) + baiPath = os.path.join( + base, *(xcode3_build_dir + bai + python_resource_dir)) + baiPath2 = os.path.join( + base, *(xcode4_build_dir + bai + python_resource_dir)) + + lldbPath = None + if os.path.isfile(os.path.join(dbgPath, 'lldb.py')): + lldbPath = dbgPath + elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')): + lldbPath = dbgPath2 + elif os.path.isfile(os.path.join(relPath, 'lldb.py')): + lldbPath = relPath + elif os.path.isfile(os.path.join(relPath2, 'lldb.py')): + lldbPath = relPath2 + elif os.path.isfile(os.path.join(baiPath, 'lldb.py')): + lldbPath = baiPath + elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')): + lldbPath = baiPath2 + + if not lldbPath: + print('This script requires lldb.py to be in either ' + dbgPath + ',', end=' ') + print(relPath + ', or ' + baiPath) + sys.exit(-1) + + # This is to locate the lldb.py module. Insert it right after sys.path[0]. + sys.path[1:1] = [lldbPath] + # print "sys.path:", sys.path + + +def run_command(ci, cmd, res, echo=True): + if echo: + print("run command:", cmd) + ci.HandleCommand(cmd, res) + if res.Succeeded(): + if echo: + print("run_command output:", res.GetOutput()) + else: + if echo: + print("run command failed!") + print("run_command error:", res.GetError()) + + +def do_lldb_disassembly(lldb_commands, exe, disassemble_options, num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + quiet_disassembly): + import lldb + import atexit + import re + + # Create the debugger instance now. + dbg = lldb.SBDebugger.Create() + if not dbg: + raise Exception('Invalid debugger instance') + + # Register an exit callback. + atexit.register(lambda: lldb.SBDebugger.Terminate()) + + # We want our debugger to be synchronous. + dbg.SetAsync(False) + + # Get the command interpreter from the debugger. + ci = dbg.GetCommandInterpreter() + if not ci: + raise Exception('Could not get the command interpreter') + + # And the associated result object. + res = lldb.SBCommandReturnObject() + + # See if there any extra command(s) to execute before we issue the file + # command. + for cmd in lldb_commands: + run_command(ci, cmd, res, not quiet_disassembly) + + # Now issue the file command. + run_command(ci, 'file %s' % exe, res, not quiet_disassembly) + + # Create a target. + #target = dbg.CreateTarget(exe) + target = dbg.GetSelectedTarget() + stream = lldb.SBStream() + + def IsCodeType(symbol): + """Check whether an SBSymbol represents code.""" + return symbol.GetType() == lldb.eSymbolTypeCode + + # Define a generator for the symbols to disassemble. + def symbol_iter(num, symbols, re_symbol_pattern, target, verbose): + # If we specify the symbols to disassemble, ignore symbol table dump. + if symbols: + for i in range(len(symbols)): + if verbose: + print("symbol:", symbols[i]) + yield symbols[i] + else: + limited = True if num != -1 else False + if limited: + count = 0 + if re_symbol_pattern: + pattern = re.compile(re_symbol_pattern) + stream = lldb.SBStream() + for m in target.module_iter(): + if verbose: + print("module:", m) + for s in m: + if limited and count >= num: + return + # If a regexp symbol pattern is supplied, consult it. + if re_symbol_pattern: + # If the pattern does not match, look for the next + # symbol. + if not pattern.match(s.GetName()): + continue + + # If we come here, we're ready to disassemble the symbol. + if verbose: + print("symbol:", s.GetName()) + if IsCodeType(s): + if limited: + count = count + 1 + if verbose: + print("returning symbol:", s.GetName()) + yield s.GetName() + if verbose: + print("start address:", s.GetStartAddress()) + print("end address:", s.GetEndAddress()) + s.GetDescription(stream) + print("symbol description:", stream.GetData()) + stream.Clear() + + # Disassembly time. + for symbol in symbol_iter( + num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + target, + not quiet_disassembly): + cmd = "disassemble %s '%s'" % (disassemble_options, symbol) + run_command(ci, cmd, res, not quiet_disassembly) + + +def main(): + # This is to set up the Python path to include the pexpect-2.4 dir. + # Remember to update this when/if things change. + scriptPath = sys.path[0] + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) + + parser = OptionParser(usage="""\ +Run lldb to disassemble all the available functions for an executable image. + +Usage: %prog [options] +""") + parser.add_option( + '-C', + '--lldb-command', + type='string', + action='append', + metavar='COMMAND', + default=[], + dest='lldb_commands', + help='Command(s) lldb executes after starting up (can be empty)') + parser.add_option( + '-e', + '--executable', + type='string', + action='store', + dest='executable', + help="""Mandatory: the executable to do disassembly on.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='disassemble_options', + help="""Mandatory: the options passed to lldb's 'disassemble' command.""") + parser.add_option( + '-q', + '--quiet-disassembly', + action='store_true', + default=False, + dest='quiet_disassembly', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + parser.add_option( + '-n', + '--num-symbols', + type='int', + action='store', + default=-1, + dest='num_symbols', + help="""The number of symbols to disassemble, if specified.""") + parser.add_option( + '-p', + '--symbol_pattern', + type='string', + action='store', + dest='re_symbol_pattern', + help="""The regular expression of symbols to invoke lldb's 'disassemble' command.""") + parser.add_option( + '-s', + '--symbol', + type='string', + action='append', + metavar='SYMBOL', + default=[], + dest='symbols_to_disassemble', + help="""The symbol(s) to invoke lldb's 'disassemble' command on, if specified.""") + + opts, args = parser.parse_args() + + lldb_commands = opts.lldb_commands + + if not opts.executable or not opts.disassemble_options: + parser.print_help() + sys.exit(1) + + executable = opts.executable + disassemble_options = opts.disassemble_options + quiet_disassembly = opts.quiet_disassembly + num_symbols = opts.num_symbols + symbols_to_disassemble = opts.symbols_to_disassemble + re_symbol_pattern = opts.re_symbol_pattern + + # We have parsed the options. + if not quiet_disassembly: + print("lldb commands:", lldb_commands) + print("executable:", executable) + print("disassemble options:", disassemble_options) + print("quiet disassembly output:", quiet_disassembly) + print("num of symbols to disassemble:", num_symbols) + print("symbols to disassemble:", symbols_to_disassemble) + print("regular expression of symbols to disassemble:", re_symbol_pattern) + + setupSysPath() + do_lldb_disassembly(lldb_commands, executable, disassemble_options, + num_symbols, + symbols_to_disassemble, + re_symbol_pattern, + quiet_disassembly) + +if __name__ == '__main__': + main() diff --git a/gnu/llvm/lldb/utils/test/llvm-mc-shell.py b/gnu/llvm/lldb/utils/test/llvm-mc-shell.py new file mode 100755 index 00000000000..6adaf5dd3c5 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/llvm-mc-shell.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +""" +Run llvm-mc interactively. + +""" + +from __future__ import print_function + +import os +import sys +from optparse import OptionParser + + +def is_exe(fpath): + """Check whether fpath is an executable.""" + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + +def which(program): + """Find the full path to a program, or return None.""" + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + return None + + +def llvm_mc_loop(mc, mc_options): + contents = [] + fname = 'mc-input.txt' + sys.stdout.write( + "Enter your input to llvm-mc. A line starting with 'END' terminates the current batch of input.\n") + sys.stdout.write("Enter 'quit' or Ctrl-D to quit the program.\n") + while True: + sys.stdout.write("> ") + next = sys.stdin.readline() + # EOF => terminate this llvm-mc shell + if not next or next.startswith('quit'): + sys.stdout.write('\n') + sys.exit(0) + # 'END' => send the current batch of input to llvm-mc + if next.startswith('END'): + # Write contents to our file and clear the contents. + with open(fname, 'w') as f: + f.writelines(contents) + # Clear the list: replace all items with an empty list. + contents[:] = [] + + # Invoke llvm-mc with our newly created file. + mc_cmd = '%s %s %s' % (mc, mc_options, fname) + sys.stdout.write("Executing command: %s\n" % mc_cmd) + os.system(mc_cmd) + else: + # Keep accumulating our input. + contents.append(next) + + +def main(): + # This is to set up the Python path to include the pexpect-2.4 dir. + # Remember to update this when/if things change. + scriptPath = sys.path[0] + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) + + parser = OptionParser(usage="""\ +Do llvm-mc interactively within a shell-like environment. A batch of input is +submitted to llvm-mc to execute whenever you terminate the current batch by +inputing a line which starts with 'END'. Quit the program by either 'quit' or +Ctrl-D. + +Usage: %prog [options] +""") + parser.add_option('-m', '--llvm-mc', + type='string', action='store', + dest='llvm_mc', + help="""The llvm-mc executable full path, if specified. + Otherwise, it must be present in your PATH environment.""") + + parser.add_option( + '-o', + '--options', + type='string', + action='store', + dest='llvm_mc_options', + help="""The options passed to 'llvm-mc' command if specified.""") + + opts, args = parser.parse_args() + + llvm_mc = opts.llvm_mc if opts.llvm_mc else which('llvm-mc') + if not llvm_mc: + parser.print_help() + sys.exit(1) + + # This is optional. For example: + # --options='-disassemble -triple=arm-apple-darwin -debug-only=arm-disassembler' + llvm_mc_options = opts.llvm_mc_options + + # We have parsed the options. + print("llvm-mc:", llvm_mc) + print("llvm-mc options:", llvm_mc_options) + + llvm_mc_loop(llvm_mc, llvm_mc_options) + +if __name__ == '__main__': + main() diff --git a/gnu/llvm/lldb/utils/test/main.c b/gnu/llvm/lldb/utils/test/main.c new file mode 100644 index 00000000000..c0f600995d2 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/main.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, const char *argv[]) { + int *null_ptr = 0; + printf("Hello, fault!\n"); + u_int32_t val = (arc4random() & 0x0f); + printf("val=%u\n", val); + if (val == 0x07) // Lucky 7 :-) + printf("Now segfault %d\n", *null_ptr); + else + printf("Better luck next time!\n"); +} diff --git a/gnu/llvm/lldb/utils/test/ras.py b/gnu/llvm/lldb/utils/test/ras.py new file mode 100755 index 00000000000..1b7caecdb0f --- /dev/null +++ b/gnu/llvm/lldb/utils/test/ras.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python + +""" +Run the test suite and send the result as an email message. + +The code for sending of the directory is copied from +http://docs.python.org/library/email-examples.html. +""" + +from __future__ import print_function + +import os +import sys +import shutil +import smtplib +# For guessing MIME type based on file name extension +import mimetypes + +from optparse import OptionParser + +from email import encoders +from email.message import Message +from email.mime.audio import MIMEAudio +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + + +def runTestsuite(testDir, sessDir, envs=None): + """Run the testsuite and return a (summary, output) tuple.""" + os.chdir(testDir) + + for env in envs: + list = env.split('=') + var = list[0].strip() + val = list[1].strip() + print(var + "=" + val) + os.environ[var] = val + + import shlex + import subprocess + + command_line = "./dotest.py -w -s %s" % sessDir + # Apply correct tokenization for subprocess.Popen(). + args = shlex.split(command_line) + + # Use subprocess module to spawn a new process. + process = subprocess.Popen(args, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # Wait for subprocess to terminate. + stdout, stderr = process.communicate() + + # This will be used as the subject line of our email about this test. + cmd = "%s %s" % (' '.join(envs) if envs else "", command_line) + + return (cmd, stderr) + + +COMMASPACE = ', ' + + +def main(): + parser = OptionParser(usage="""\ +Run lldb test suite and send the results as a MIME message. + +Usage: %prog [options] + +Unless the -o option is given, the email is sent by forwarding to the specified +SMTP server, which then does the normal delivery process. +""") + parser.add_option('-d', '--directory', + type='string', action='store', + dest='testDir', + help="""The LLDB test directory directly under the top dir. + Otherwise use the current directory.""") + # + # This is similar to TestBase.getRunSpec(self) from lldbtest.py. + # + parser.add_option('-e', '--environment', + type='string', action='append', metavar='ENVIRONMENT', + default=[], dest='environments', + help="""The environment setting as prefix to the test driver. + Example: -e 'CC=clang' -e 'ARCH=x86_64'""") + parser.add_option('-m', '--mailserver', + type='string', action='store', metavar='MAILSERVER', + dest='mailserver', + help="""The outgoing SMTP server.""") + parser.add_option('-o', '--output', + type='string', action='store', metavar='FILE', + help="""Print the composed message to FILE instead of + sending the message to the SMTP server.""") + parser.add_option('-s', '--sender', + type='string', action='store', metavar='SENDER', + help='The value of the From: header (required)') + parser.add_option('-r', '--recipient', + type='string', action='append', metavar='RECIPIENT', + default=[], dest='recipients', + help='A To: header value (at least one required)') + opts, args = parser.parse_args() + if not opts.sender or not opts.recipients: + parser.print_help() + sys.exit(1) + testDir = opts.testDir + if not testDir: + testDir = '.' + + sessDir = 'tmp-lldb-session' + if os.path.exists(sessDir): + shutil.rmtree(sessDir) + # print "environments:", opts.environments + summary, output = runTestsuite(testDir, sessDir, opts.environments) + + # Create the enclosing (outer) message + outer = MIMEMultipart() + outer['Subject'] = summary + outer['To'] = COMMASPACE.join(opts.recipients) + outer['From'] = opts.sender + outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' + + # The sessDir contains all the session logs for failed/errored tests. + # Attach them all if it exists! + + if not os.path.exists(sessDir): + outer.attach(MIMEText(output, 'plain')) + else: + outer.attach( + MIMEText( + "%s\n%s\n\n" % + (output, "Session logs of test failures/errors:"), 'plain')) + + for filename in (os.listdir(sessDir) if os.path.exists(sessDir) else []): + path = os.path.join(sessDir, filename) + if not os.path.isfile(path): + continue + # Guess the content type based on the file's extension. Encoding + # will be ignored, although we should check for simple things like + # gzip'd or compressed files. + ctype, encoding = mimetypes.guess_type(path) + if ctype is None or encoding is not None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + if maintype == 'text': + fp = open(path) + # Note: we should handle calculating the charset + msg = MIMEText(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'image': + fp = open(path, 'rb') + msg = MIMEImage(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'audio': + fp = open(path, 'rb') + msg = MIMEAudio(fp.read(), _subtype=subtype) + fp.close() + else: + fp = open(path, 'rb') + msg = MIMEBase(maintype, subtype) + msg.set_payload(fp.read()) + fp.close() + # Encode the payload using Base64 + encoders.encode_base64(msg) + # Set the filename parameter + msg.add_header('Content-Disposition', 'attachment', filename=filename) + outer.attach(msg) + + # Now send or store the message + composed = outer.as_string() + if opts.output: + fp = open(opts.output, 'w') + fp.write(composed) + fp.close() + else: + s = smtplib.SMTP(opts.mailserver) + s.sendmail(opts.sender, opts.recipients, composed) + s.quit() + + +if __name__ == '__main__': + main() diff --git a/gnu/llvm/lldb/utils/test/run-dis.py b/gnu/llvm/lldb/utils/test/run-dis.py new file mode 100755 index 00000000000..5df65e85ba1 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/run-dis.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python + +""" +Run lldb disassembler on all the binaries specified by a combination of root dir +and path pattern. +""" + +from __future__ import print_function + +import os +import sys +import subprocess +import re +from optparse import OptionParser + +# The directory of this Python script as well as the lldb-disasm.py workhorse. +scriptPath = None + +# The root directory for the SDK symbols. +root_dir = None + +# The regular expression pattern to match the desired pathname to the binaries. +path_pattern = None + +# And the re-compiled regular expression object. +path_regexp = None + +# If specified, number of symbols to disassemble for each qualified binary. +num_symbols = -1 + +# Command template of the invocation of lldb disassembler. +template = '%s/lldb-disasm.py -C "platform select remote-ios" -o "-n" -q -e %s -n %s' + +# Regular expression for detecting file output for Mach-o binary. +mach_o = re.compile('\sMach-O.+binary') + + +def isbinary(path): + file_output = subprocess.Popen(["file", path], + stdout=subprocess.PIPE).stdout.read() + return (mach_o.search(file_output) is not None) + + +def walk_and_invoke(sdk_root, path_regexp, suffix, num_symbols): + """Look for matched file and invoke lldb disassembly on it.""" + global scriptPath + + for root, dirs, files in os.walk(sdk_root, topdown=False): + for name in files: + path = os.path.join(root, name) + + # We're not interested in .h file. + if name.endswith(".h"): + continue + # Neither a symbolically linked file. + if os.path.islink(path): + continue + + # We'll be pattern matching based on the path relative to the SDK + # root. + replaced_path = path.replace(root_dir, "", 1) + # Check regular expression match for the replaced path. + if not path_regexp.search(replaced_path): + continue + # If a suffix is specified, check it, too. + if suffix and not name.endswith(suffix): + continue + if not isbinary(path): + continue + + command = template % ( + scriptPath, path, num_symbols if num_symbols > 0 else 1000) + print("Running %s" % (command)) + os.system(command) + + +def main(): + """Read the root dir and the path spec, invoke lldb-disasm.py on the file.""" + global scriptPath + global root_dir + global path_pattern + global path_regexp + global num_symbols + + scriptPath = sys.path[0] + + parser = OptionParser(usage="""\ +Run lldb disassembler on all the binaries specified by a combination of root dir +and path pattern. +""") + parser.add_option( + '-r', + '--root-dir', + type='string', + action='store', + dest='root_dir', + help='Mandatory: the root directory for the SDK symbols.') + parser.add_option( + '-p', + '--path-pattern', + type='string', + action='store', + dest='path_pattern', + help='Mandatory: regular expression pattern for the desired binaries.') + parser.add_option('-s', '--suffix', + type='string', action='store', default=None, + dest='suffix', + help='Specify the suffix of the binaries to look for.') + parser.add_option( + '-n', + '--num-symbols', + type='int', + action='store', + default=-1, + dest='num_symbols', + help="""The number of symbols to disassemble, if specified.""") + + opts, args = parser.parse_args() + if not opts.root_dir or not opts.path_pattern: + parser.print_help() + sys.exit(1) + + # Sanity check the root directory. + root_dir = opts.root_dir + root_dir = os.path.abspath(root_dir) + if not os.path.isdir(root_dir): + parser.print_help() + sys.exit(1) + + path_pattern = opts.path_pattern + path_regexp = re.compile(path_pattern) + suffix = opts.suffix + num_symbols = opts.num_symbols + + print("Root directory for SDK symbols:", root_dir) + print("Regular expression for the binaries:", path_pattern) + print("Suffix of the binaries to look for:", suffix) + print("num of symbols to disassemble:", num_symbols) + + walk_and_invoke(root_dir, path_regexp, suffix, num_symbols) + + +if __name__ == '__main__': + main() diff --git a/gnu/llvm/lldb/utils/test/run-until-faulted.py b/gnu/llvm/lldb/utils/test/run-until-faulted.py new file mode 100755 index 00000000000..0ce32771f75 --- /dev/null +++ b/gnu/llvm/lldb/utils/test/run-until-faulted.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python + +""" +Run a program via lldb until it fails. +The lldb executable is located via your PATH env variable, if not specified. +""" + +from __future__ import print_function + +import os +import sys +from optparse import OptionParser + + +def is_exe(fpath): + """Check whether fpath is an executable.""" + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + +def which(program): + """Find the full path to a program, or return None.""" + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + return None + + +def do_lldb_launch_loop(lldb_command, exe, exe_options): + import pexpect + import time + + prompt = "\(lldb\) " + lldb = pexpect.spawn(lldb_command) + # Turn on logging for what lldb sends back. + lldb.logfile_read = sys.stdout + lldb.expect(prompt) + + # Now issue the file command. + # print "sending 'file %s' command..." % exe + lldb.sendline('file %s' % exe) + lldb.expect(prompt) + + # Loop until it faults.... + count = 0 + # while True: + # count = count + 1 + for i in range(100): + count = i + # print "sending 'process launch -- %s' command... (iteration: %d)" % + # (exe_options, count) + lldb.sendline('process launch -- %s' % exe_options) + index = lldb.expect(['Process .* exited with status', + 'Process .* stopped', + pexpect.TIMEOUT]) + if index == 0: + # We'll try again later. + time.sleep(3) + elif index == 1: + # Perfect, our process had stopped; break out of the loop. + break + elif index == 2: + # Something went wrong. + print("TIMEOUT occurred:", str(lldb)) + + # Give control of lldb shell to the user. + lldb.interact() + + +def main(): + # This is to set up the Python path to include the pexpect-2.4 dir. + # Remember to update this when/if things change. + scriptPath = sys.path[0] + sys.path.append( + os.path.join( + scriptPath, + os.pardir, + os.pardir, + 'test', + 'pexpect-2.4')) + + parser = OptionParser(usage="""\ +%prog [options] +Run a program via lldb until it fails. +The lldb executable is located via your PATH env variable, if not specified.\ +""") + parser.add_option('-l', '--lldb-command', + type='string', action='store', metavar='LLDB_COMMAND', + default='lldb', dest='lldb_command', + help='Full path to your lldb command') + parser.add_option( + '-e', + '--executable', + type='string', + action='store', + dest='exe', + help="""(Mandatory) The executable to launch via lldb.""") + parser.add_option( + '-o', + '--options', + type='string', + action='store', + default='', + dest='exe_options', + help="""The args/options passed to the launched program, if specified.""") + + opts, args = parser.parse_args() + + lldb_command = which(opts.lldb_command) + + if not opts.exe: + parser.print_help() + sys.exit(1) + exe = opts.exe + + exe_options = opts.exe_options + + # We have parsed the options. + print("lldb command:", lldb_command) + print("executable:", exe) + print("executable options:", exe_options) + + do_lldb_launch_loop(lldb_command, exe, exe_options) + +if __name__ == '__main__': + main() |