[Utils] Remove legacy scripts

As pointed out by Nathan in D65155, these scrips don't seem to serve any
real need anymore.

llvm-svn: 366827
This commit is contained in:
Jonas Devlieghere 2019-07-23 17:23:36 +00:00
parent 6f13637a3e
commit 6491076ec6
47 changed files with 0 additions and 6978 deletions

View File

@ -1,14 +0,0 @@
# 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 (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
LLDBTableGen.cpp
)
set_target_properties(lldb-tblgen PROPERTIES FOLDER "LLDB tablegenning")
endif()

View File

@ -1,153 +0,0 @@
//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===//
//
// 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 "llvm/ADT/StringExtras.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <map>
#include <vector>
using namespace llvm;
/// Map of command names to their associated records. Also makes sure our
/// commands are sorted in a deterministic way.
typedef std::map<std::string, std::vector<Record *>> RecordsByCommand;
/// Groups all records by their command.
static RecordsByCommand getCommandList(std::vector<Record *> Options) {
RecordsByCommand result;
for (Record *Option : Options)
result[Option->getValueAsString("Command").str()].push_back(Option);
return result;
}
static void emitOption(Record *Option, raw_ostream &OS) {
OS << " {";
// List of option groups this option is in.
std::vector<std::string> GroupsArg;
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));
}
// If we have any groups, we merge them. Otherwise we move this option into
// the all group.
if (GroupsArg.empty())
OS << "LLDB_OPT_SET_ALL";
else
OS << llvm::join(GroupsArg.begin(), GroupsArg.end(), " | ");
OS << ", ";
// Check if this option is required.
OS << (Option->getValue("Required") ? "true" : "false");
// Add the full and short name for this option.
OS << ", \"" << Option->getValueAsString("FullName") << "\", ";
OS << '\'' << Option->getValueAsString("ShortName") << "'";
auto ArgType = Option->getValue("ArgType");
bool IsOptionalArg = Option->getValue("OptionalArg") != nullptr;
// Decide if we have either an option, required or no argument for this
// option.
OS << ", OptionParser::";
if (ArgType) {
if (IsOptionalArg)
OS << "eOptionalArgument";
else
OS << "eRequiredArgument";
} else
OS << "eNoArgument";
OS << ", nullptr, ";
if (Option->getValue("ArgEnum"))
OS << Option->getValueAsString("ArgEnum");
else
OS << "{}";
OS << ", ";
// Read the tab completions we offer for this option (if there are any)
if (Option->getValue("Completions")) {
auto Completions = Option->getValueAsListOfStrings("Completions");
std::vector<std::string> CompletionArgs;
for (llvm::StringRef Completion : 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 (ArgType) {
OS << ArgType->getValue()->getAsUnquotedString();
} else
OS << "None";
OS << ", ";
// Add the description if there is any.
if (auto D = Option->getValue("Description")) {
OS << "\"";
llvm::printEscapedString(D->getValue()->getAsUnquotedString(), OS);
OS << "\"";
} else
OS << "\"\"";
OS << "},\n";
}
/// Emits all option initializers to the raw_ostream.
static void emitOptions(std::string Command, std::vector<Record *> Option,
raw_ostream &OS) {
// Generate the macro that the user needs to define before including the
// *.inc file.
std::string NeededMacro = "LLDB_OPTIONS_" + Command;
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 << "// Options for " << Command << "\n";
OS << "#ifdef " << NeededMacro << "\n";
for (Record *R : Option)
emitOption(R, OS);
// We undefine the macro for the user like Clang's include files are doing it.
OS << "#undef " << NeededMacro << "\n";
OS << "#endif // " << Command << " command\n\n";
}
void lldb_private::EmitOptionDefs(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record *> Options = Records.getAllDerivedDefinitions("Option");
emitSourceFileHeader("Options for LLDB command line commands.", OS);
RecordsByCommand ByCommand = getCommandList(Options);
for (auto &CommandRecordPair : ByCommand) {
emitOptions(CommandRecordPair.first, CommandRecordPair.second, OS);
}
}

View File

@ -1,71 +0,0 @@
//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===//
//
// 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 Clang'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,
};
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 clang attribute clases")));
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;
}
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)

View File

@ -1,34 +0,0 @@
//===- TableGen.cpp - Top-Level TableGen implementation for Clang ---------===//
//
// 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 <string>
namespace llvm {
class raw_ostream;
class RecordKeeper;
} // namespace llvm
using llvm::raw_ostream;
using llvm::RecordKeeper;
namespace lldb_private {
void EmitOptionDefs(RecordKeeper &RK, raw_ostream &OS);
} // namespace lldb_private
#endif

View File

@ -1,73 +0,0 @@
#!/usr/bin/env python
"""
Convert the raw message sources from git patch emails to git-am friendly files.
Usage:
1. Mail.app -> Save As -> api.eml (Raw Message Source)
2. .../convert.py api.eml
3. git am [--signoff] < api.eml
4. git svn dcommit [--commit-url https://id@llvm.org/svn/llvm-project/lldb/trunk]
"""
from __future__ import print_function
import os
import re
import sys
import io
def usage(problem_file=None):
if problem_file:
print("%s is not a file" % problem_file)
print("Usage: convert.py raw-message-source [raw-message-source2 ...]")
sys.exit(0)
def do_convert(file):
"""Skip all preceding mail message headers until 'From: ' is encountered.
Then for each line ('From: ' header included), replace the dos style CRLF
end-of-line with unix style LF end-of-line.
"""
print("converting %s ..." % file)
with open(file, 'r') as f_in:
content = f_in.read()
# The new content to be written back to the same file.
new_content = io.StringIO()
# Boolean flag controls whether to start printing lines.
from_header_seen = False
# By default, splitlines() don't include line breaks. CRLF should be gone.
for line in content.splitlines():
# Wait till we scan the 'From: ' header before start printing the
# lines.
if not from_header_seen:
if not line.startswith('From: '):
continue
else:
from_header_seen = True
print(line, file=new_content)
with open(file, 'w') as f_out:
f_out.write(new_content.getvalue())
print("done")
def main():
if len(sys.argv) == 1:
usage()
# Convert the raw message source one by one.
for file in sys.argv[1:]:
if not os.path.isfile(file):
usage(file)
do_convert(file)
if __name__ == '__main__':
main()

View File

@ -1,6 +0,0 @@
add_llvm_utility(lit-cpuid
lit-cpuid.cpp
)
target_link_libraries(lit-cpuid PRIVATE LLVMSupport)
set_target_properties(lit-cpuid PROPERTIES FOLDER "lldb utils")

View File

@ -1,37 +0,0 @@
//===- 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;
}

View File

@ -1,47 +0,0 @@
# 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()

View File

@ -1,17 +0,0 @@
#!/usr/bin/env python
import subprocess
import sys
dotest_path = '@LLDB_SOURCE_DIR@/test/dotest.py'
dotest_args_str = '@LLDB_DOTEST_ARGS@'
if __name__ == '__main__':
wrapper_args = sys.argv[1:]
dotest_args = dotest_args_str.split(';')
# Build dotest.py command.
cmd = [sys.executable, dotest_path, '-q']
cmd.extend(dotest_args)
cmd.extend(wrapper_args)
# Invoke dotest.py and return exit code.
print(' '.join(cmd))
sys.exit(subprocess.call(cmd))

View File

@ -1,36 +0,0 @@
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

View File

@ -1,93 +0,0 @@
##===-- 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)

View File

@ -1,130 +0,0 @@
##===-- 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()

View File

@ -1,338 +0,0 @@
##===-- 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()

View File

@ -1,142 +0,0 @@
##===-- 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

View File

@ -1,26 +0,0 @@
##===-- 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

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
#!/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()

View File

@ -1,77 +0,0 @@
#!/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()

View File

@ -1,238 +0,0 @@
##===-- 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()

View File

@ -1,41 +0,0 @@
##===-- 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

View File

@ -1,97 +0,0 @@
#!/usr/bin/env python
"""
Greps and returns the first svn log entry containing a line matching the regular
expression pattern passed as the only arg.
Example:
svn log -v | grep-svn-log.py '^ D.+why_are_you_missing.h$'
"""
from __future__ import print_function
import fileinput
import re
import sys
import io
# Separator string for "svn log -v" output.
separator = '-' * 72
usage = """Usage: grep-svn-log.py line-pattern
Example:
svn log -v | grep-svn-log.py '^ D.+why_are_you_missing.h'"""
class Log(io.StringIO):
"""Simple facade to keep track of the log content."""
def __init__(self):
self.reset()
def add_line(self, a_line):
"""Add a line to the content, if there is a previous line, commit it."""
global separator
if self.prev_line is not None:
print(self.prev_line, file=self)
self.prev_line = a_line
self.separator_added = (a_line == separator)
def del_line(self):
"""Forget about the previous line, do not commit it."""
self.prev_line = None
def reset(self):
"""Forget about the previous lines entered."""
io.StringIO.__init__(self)
self.prev_line = None
def finish(self):
"""Call this when you're finished with populating content."""
if self.prev_line is not None:
print(self.prev_line, file=self)
self.prev_line = None
def grep(regexp):
# The log content to be written out once a match is found.
log = Log()
LOOKING_FOR_MATCH = 0
FOUND_LINE_MATCH = 1
state = LOOKING_FOR_MATCH
while True:
line = sys.stdin.readline()
if not line:
return
line = line.splitlines()[0]
if state == FOUND_LINE_MATCH:
# At this state, we keep on accumulating lines until the separator
# is encountered. At which point, we can return the log content.
if line == separator:
log.finish()
print(log.getvalue())
return
log.add_line(line)
elif state == LOOKING_FOR_MATCH:
if line == separator:
log.reset()
log.add_line(line)
# Update next state if necessary.
if regexp.search(line):
state = FOUND_LINE_MATCH
def main():
if len(sys.argv) != 2:
print(usage)
sys.exit(0)
regexp = re.compile(sys.argv[1])
grep(regexp)
sys.stdin.close()
if __name__ == '__main__':
main()

View File

@ -1,293 +0,0 @@
syncsource.py
OVERVIEW
The syncsource.py utility transfers groups of files between
computers. The primary use case is to enable developing LLVM project
software on one machine, transfer it efficiently to other machines ---
possibly of other architectures --- and test it there. syncsource.py
supports configurable, named source-to-destination mappings and has a
transfer agent plug-in architecture. The current distribution provides
an rsync-over-ssh transfer agent.
The primary benefits of using syncsource.py are:
* Provides a simple, reliable way to get a mirror copy of primary-
machine files onto several different destinations without concern
of compromising the patch during testing on different machines.
* Handles directory-mapping differences between two machines. For
LLDB, this is helpful when going between OS X and any other non-OS X
target system.
EXAMPLE WORKFLOW
This utility was developed in the context of working on the LLDB
project. Below we show the transfers we'd like to have happen,
and the configuration that supports it.
Workflow Example:
* Develop on OS X (primary machine)
* Test candidate changes on OS X.
* Test candidate changes on a Linux machine (machine-name: lldb-linux).
* Test candidate changes on a FreeBSD machine (machine-name: lldb-freebsd).
* Do check-ins from OS X machine.
Requirements:
* OS X machine requires the lldb source layout: lldb, lldb/llvm,
lldb/llvm/tools/clang. Note this is different than the canonical
llvm, llvm/tools/clang, llvm/tools/lldb layout that we'll want on
the Linux and FreeBSD test machines.
* Linux machine requires the llvm, llvm/tools/clang and
llvm/tools/lldb layout.
* FreeBSD machine requires the same layout as the llvm machine.
syncsource.py configuration in ~/.syncsourcerc:
# This is my configuration with a comment. Configuration
# files are JSON-based.
{ "configurations": [
# Here we have a collection of named configuration blocks.
# Configuration blocks can chain back to a parent by name.
{
# Every block has a name so it can be referenced from
# the command line or chained back to by a child block
# for sharing.
"name": "base_tot_settings",
# This directive lists the "directory ids" that we'll care
# about. If your local repository has additional directories
# for other projects that need to ride along, add them here.
# For defaulting purposes, it makes sense to name the
# directory IDs as the most likely name for the directory
# itself. For stock LLDB from top of tree, we generally only
# care about lldb, llvm and clang.
"dir_names": [ "llvm", "clang", "lldb" ],
# This section describes where the source files live on
# the primary machine. There should always be a base_dir
# entry, which indicates where in the local filesystem the
# projects are rooted. For each dir in dir_names, there
# should be either:
# 1. an entry named {dir-id}_dir (e.g. llvm_dir), which
# specifies the source directory for the given dir id
# relative to the base_dir entry, OR
# 2. no entry, in which case the directory is assumed to
# be the same as {dir-id}. In the example below, the
# base_dir-relative directory for the "lldb" dir-id is
# defaulted to being "lldb". That's exactly what
# we need in an OS X-style lldb dir layout.
"source": {
"base_dir": "~/work/lldb-tot",
"llvm_dir": "lldb/llvm",
"clang_dir": "lldb/llvm/tools/clang"
},
# source_excludes covers any exclusions that:
# * should be applied when copying files from the source
# * should be excluded from deletion on the destination
#
# By default, ".git", ".svn" and ".pyc" are added to
# all dir-id exclusions. The default excludes can be
# controlled by the syncsource.py --default-excludes
# option.
#
# Below, I have transfer of the lldb dir skip everything
# rooted at "/llvm" below the lldb dir. This is
# because we want the source OS X lldb to move to
# a destination of {some-dest-root}/llvm/tools/lldb, and
# not have the OS-X-inverted llvm copy over with the lldb
# transfer portion. We'll see the complete picture of
# how this works when we get to specifying destinations
# later on in the config.
#
# We also exclude the "/build" and "/llvm-build" dir rooted in
# the OS X-side sources. The Xcode configuration on this
# OS X machine will dump lldb builds in the /build directory
# relative to the lldb dir, and it will build llvm+clang in
# the /llvm-build dir relative to the lldb dir.
#
# Note the first forward slash in "/build" indicates to the
# transfer agent that we only want to exclude the
# ~/work/lldb-tot/lldb/build dir, not just any file or
# directory named "build" somewhere underneath the lldb
# directory. Without the leading forward slash, any file
# or directory called build anywhere underneath the lldb dir
# will be excluded, which is definitely not what we want here.
#
# For the llvm dir, we do a source-side exclude for
# "/tools/clang". We manage the clang transfer as a separate
# entity, so we don't want the movement of llvm to also move
# clang.
#
# The llvm_dir exclusion of "/tools/lldb" is the first example
# of an exclude targeting a requirement of the destination
# side. Normally the transfer agent will delete anything on
# the destination that is not present on the source. It is
# trying to mirror, and ensure both sides have the same
# content. The source side of llvm on OS X does not have a
# "/tools/lldb", so at first this exclude looks non-sensical.
# But on the canonical destination layout, lldb lives in
# {some-dest-root}/llvm/tools/lldb. Without this exclude,
# the transfer agent would blow away the tools/lldb directory
# on the destination every time we transfer, and then have to
# copy the lldb dir all over again. For rsync+ssh, that
# totally would defeat the huge transfer efficiencies gained
# by using rsync in the first place.
#
# Note the overloading of both source and dest style excludes
# ultimately comes from the rsync-style exclude mechanism.
# If it wasn't for that, I would have separated source and
# dest excludes out better.
"source_excludes": {
"lldb_dir": ["/llvm", "/build", "/llvm-build"],
"llvm_dir": ["/tools/lldb", "/tools/clang"]
}
},
# Top of tree public, common settings for all destinations.
{
# The name for this config block.
"name": "common_tot",
# Here is our first chaining back to a parent config block.
# Any settings in "common_tot" not specified here are going
# to be retrieved from the parent.
"parent": "base_tot_settings",
# The transfer agent class to use. Right now, the only one
# available is this one here that uses rsync over ssh.
# If some other mechanism is needed to reach this destination,
# it can be specified here in full [[package.]module.]class form.
"transfer_class": "transfer.rsync.RsyncOverSsh",
# Specifies the destination-root-relative directories.
# Here our desination is rooted at:
# {some-yet-to-be-specified-destination-root} + "base_dir".
# In other words, each destination will have some kind of root
# for all relative file placement. We'll see those defined
# later, as they can change per destination machine.
# The block below describes the settings relative to that
# destination root.
#
# As before, each dir-id used in this configuration is
# expected to have either:
# 1. an entry named {dir-id}_dir (e.g. llvm_dir), which
# specifies the destination directory for the given dir id
# relative to the dest_root+base_dir entries, OR
# 2. no entry, in which case the directory is assumed to
# be the same as {dir-id}. In the example below, the
# dest_root+base_dir-relative directory for the "llvm" dir-id is
# defaulted to being "llvm". That's exactly what
# we need in a canonical llvm/clang/lldb setup on
# Linux/FreeBSD.
#
# Note we see the untangling of the OS X lldb-centric
# directory structure to the canonical llvm,
# llvm/tools/clang, llvm/tools/lldb structure below.
# We are mapping lldb into a subdirectory of the llvm
# directory.
#
# The transfer logic figures out which directories to copy
# first by finding the shortest destination absolute path
# and doing them in that order. For our case, this ensures
# llvm is copied over before lldb or clang.
"dest": {
"base_dir": "work/mirror/git",
"lldb_dir": "llvm/tools/lldb",
"clang_dir": "llvm/tools/clang"
}
},
# Describe the lldb-linux destination. With this,
# we're done with the mapping for transfer setup
# for the lldb-linux box. This configuration can
# be used either by:
# 1. having a parent "default" blockthat points to this one,
# which then gets used by default, or
# 2. using the --configuration/-c CONFIG option to
# specify using this name on the syncsource.py command line.
{
"name": "lldb-linux"
"parent": "common_tot",
# The ssh block is understood by the rsync+ssh transfer
# agent. Other agents would probably require different
# agent-specific details that they could read from
# other blocks.
"ssh": {
# This specifies the host name (or IP address) as would
# be used as the target for an ssh command.
"dest_host": "lldb-linux.example.com",
# root_dir specifies the global root directory for
# this destination. All destinations on this target
# will be in a directory that is built from
# root_dir + base_dir + {dir_id}_dir.
"root_dir" : "/home/tfiala",
# The ssh user is specified here.
"user": "tfiala",
# The ssh port is specified here.
"port": 22
}
},
# Describe the lldb-freebsd destination.
# Very similar to the lldb-linux one.
{
"name": "lldb-freebsd"
"parent": "common_tot",
"ssh": {
"dest_host": "lldb-freebsd.example.com",
# Specify a different destination-specific root dir here.
"root_dir" : "/mnt/ssd02/fialato",
"user": "fialato",
# The ssh port is specified here.
"port": 2022
}
},
# If a block named "default" exists, and if no configuration
# is specified on the command line, then the default block
# will be used. Use this block to point to the most common
# transfer destination you would use.
{
"name": "default",
"parent": "lldb-linux"
}
]
}
Using it
Now that we have a .syncsourcerc file set up, we can do a transfer.
The .syncsourcerc file will be searched for as follows, using the
first one that is found:
* First check the --rc-file RCFILE option. If this is specified
and doesn't exist, it will raise an error and quit.
* Check if the current directory has a .syncsourcerc file. If so,
use that.
* Use the .syncsourcerc file from the user's home directory.
Run the command:
python /path/to/syncsource.rc -c {configuration-name}
The -c {configuration-name} can be left off, in which case a
configuration with the name 'default' will be used.
After that, the transfer will occur. With the rsync-over-ssh
transfer agent, one rsync per dir-id will be used. rsync output
is redirected to the console.
FEEDBACK
Feel free to pass feedback along to Todd Fiala (todd.fiala@gmail.com).

View File

@ -1,8 +0,0 @@
class Protocol(object):
def __init__(self, options, config):
self.options = options
self.config = config
def transfer(transfer_specs, dry_run):
raise "transfer must be overridden by transfer implementation"

View File

@ -1,61 +0,0 @@
import os.path
import pprint
import subprocess
import sys
import transfer.protocol
class RsyncOverSsh(transfer.protocol.Protocol):
def __init__(self, options, config):
super(RsyncOverSsh, self).__init__(options, config)
self.ssh_config = config.get_value("ssh")
def build_rsync_command(self, transfer_spec, dry_run):
dest_path = os.path.join(
self.ssh_config["root_dir"],
transfer_spec.dest_path)
flags = "-avz"
if dry_run:
flags += "n"
cmd = [
"rsync",
flags,
"-e",
"ssh -p {}".format(self.ssh_config["port"]),
"--rsync-path",
# The following command needs to know the right way to do
# this on the dest platform - ensures the target dir exists.
"mkdir -p {} && rsync".format(dest_path)
]
# Add source dir exclusions
if transfer_spec.exclude_paths:
for exclude_path in transfer_spec.exclude_paths:
cmd.append("--exclude")
cmd.append(exclude_path)
cmd.extend([
"--delete",
transfer_spec.source_path + "/",
"{}@{}:{}".format(
self.ssh_config["user"],
self.ssh_config["dest_host"],
dest_path)])
return cmd
def transfer(self, transfer_specs, dry_run):
if self.options.verbose:
printer = pprint.PrettyPrinter()
for spec in transfer_specs:
printer.pprint(spec)
for spec in transfer_specs:
cmd = self.build_rsync_command(spec, dry_run)
if self.options.verbose:
print("executing the following command:\n{}".format(cmd))
result = subprocess.call(
cmd, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
if result != 0:
return result

View File

@ -1,12 +0,0 @@
class TransferSpec(object):
def __init__(self, source_path, exclude_paths, dest_path):
self.source_path = source_path
self.exclude_paths = exclude_paths
self.dest_path = dest_path
def __repr__(self):
fmt = (
"TransferSpec(source_path='{}', exclude_paths='{}', "
"dest_path='{}')")
return fmt.format(self.source_path, self.exclude_paths, self.dest_path)

View File

@ -1,2 +0,0 @@
[Master]
init-hook='import os; import sys; sys.path.append(os.path.join(os.getcwd(), "lib")); print("hello from {}".format(os.getcwd()))'

View File

@ -1,270 +0,0 @@
#!/usr/bin/env 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
Sync lldb and related source from a local machine to a remote machine.
This facilitates working on the lldb sourcecode on multiple machines
and multiple OS types, verifying changes across all.
"""
import argparse
import io
import importlib
import json
import os.path
import re
import sys
# Add the local lib directory to the python path.
LOCAL_LIB_PATH = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"lib")
sys.path.append(LOCAL_LIB_PATH)
import transfer.transfer_spec
DOTRC_BASE_FILENAME = ".syncsourcerc"
class Configuration(object):
"""Provides chaining configuration lookup."""
def __init__(self, rcdata_configs):
self.__rcdata_configs = rcdata_configs
def get_value(self, key):
"""
Return the first value in the parent chain that has the key.
The traversal starts from the most derived configuration (i.e.
child) and works all the way up the parent chain.
@return the value of the first key in the parent chain that
contains a value for the given key.
"""
for config in self.__rcdata_configs:
if key in config:
return config[key]
return None
def __getitem__(self, key):
value = self.get_value(key)
if value:
return value
else:
raise KeyError(key)
def parse_args():
"""@return options parsed from the command line."""
parser = argparse.ArgumentParser()
parser.add_argument(
"--config-name", "-c", action="store", default="default",
help="specify configuration name to use")
parser.add_argument(
"--default-excludes", action="store", default="*.git,*.svn,*.pyc",
help=("comma-separated list of default file patterns to exclude "
"from each source directory and to protect from deletion "
"on each destination directory; if starting with forward "
"slash, it only matches at the top of the base directory"))
parser.add_argument(
"--dry-run", "-n", action="store_true",
help="do a dry run of the transfer operation, don't really transfer")
parser.add_argument(
"--rc-file", "-r", action="store",
help="specify the sync-source rc file to use for configurations")
parser.add_argument(
"--verbose", "-v", action="store_true", help="turn on verbose output")
return parser.parse_args()
def read_rcfile(filename):
"""Returns the json-parsed contents of the input file."""
# First parse file contents, removing all comments but
# preserving the line count.
regex = re.compile(r"#.*$")
comment_stripped_file = io.StringIO()
with open(filename, "r") as json_file:
for line in json_file:
comment_stripped_file.write(regex.sub("", line))
return json.load(io.StringIO(comment_stripped_file.getvalue()))
def find_appropriate_rcfile(options):
# Use an options-specified rcfile if specified.
if options.rc_file and len(options.rc_file) > 0:
if not os.path.isfile(options.rc_file):
# If it doesn't exist, error out here.
raise "rcfile '{}' specified but doesn't exist".format(
options.rc_file)
return options.rc_file
# Check if current directory .sync-sourcerc exists. If so, use it.
local_rc_filename = os.path.abspath(DOTRC_BASE_FILENAME)
if os.path.isfile(local_rc_filename):
return local_rc_filename
# Check if home directory .sync-sourcerc exists. If so, use it.
homedir_rc_filename = os.path.abspath(
os.path.join(os.path.expanduser("~"), DOTRC_BASE_FILENAME))
if os.path.isfile(homedir_rc_filename):
return homedir_rc_filename
# Nothing matched. We don't have an rc filename candidate.
return None
def get_configuration(options, rcdata, config_name):
rcdata_configs = []
next_config_name = config_name
while next_config_name:
# Find the next rcdata configuration for the given name.
rcdata_config = next(
config for config in rcdata["configurations"]
if config["name"] == next_config_name)
# See if we found it.
if rcdata_config:
# This is our next configuration to use in the chain.
rcdata_configs.append(rcdata_config)
# If we have a parent, check that next.
if "parent" in rcdata_config:
next_config_name = rcdata_config["parent"]
else:
next_config_name = None
else:
raise "failed to find specified parent config '{}'".format(
next_config_name)
return Configuration(rcdata_configs)
def create_transfer_agent(options, configuration):
transfer_class_spec = configuration.get_value("transfer_class")
if options.verbose:
print("specified transfer class: '{}'".format(transfer_class_spec))
# Load the module (possibly package-qualified).
components = transfer_class_spec.split(".")
module = importlib.import_module(".".join(components[:-1]))
# Create the class name we need to load.
clazz = getattr(module, components[-1])
return clazz(options, configuration)
def sync_configured_sources(options, configuration, default_excludes):
# Look up the transfer method.
transfer_agent = create_transfer_agent(options, configuration)
# For each configured dir_names source, do the following transfer:
# 1. Start with base_dir + {source-dir-name}_dir
# 2. Copy all files recursively, but exclude
# all dirs specified by source_excludes:
# skip all base_dir + {source-dir-name}_dir +
# {source-dir-name}_dir excludes.
source_dirs = configuration.get_value("source")
source_excludes = configuration.get_value("source_excludes")
dest_dirs = configuration.get_value("dest")
source_base_dir = source_dirs["base_dir"]
dest_base_dir = dest_dirs["base_dir"]
dir_ids = configuration.get_value("dir_names")
transfer_specs = []
for dir_id in dir_ids:
dir_key = "{}_dir".format(dir_id)
# Build the source dir (absolute) that we're copying from.
# Defaults the base-relative source dir to the source id (e.g. lldb)
rel_source_dir = source_dirs.get(dir_key, dir_id)
transfer_source_dir = os.path.expanduser(
os.path.join(source_base_dir, rel_source_dir))
# Exclude dirs do two things:
# 1) stop items from being copied on the source side, and
# 2) protect things from being deleted on the dest side.
#
# In both cases, they are specified relative to the base
# directory on either the source or dest side.
#
# Specifying a leading '/' in the directory will limit it to
# be rooted in the base directory. i.e. "/.git" will only
# match {base-dir}/.git, not {base-dir}/subdir/.git, but
# ".svn" will match {base-dir}/.svn and
# {base-dir}/subdir/.svn.
#
# If excludes are specified for this dir_id, then pass along
# the excludes. These are relative to the dir_id directory
# source, and get passed along that way as well.
transfer_source_excludes = []
# Add the source excludes for this dir.
skip_defaults = False
if source_excludes and dir_key in source_excludes:
transfer_source_excludes.extend(source_excludes[dir_key])
if "<no-defaults>" in source_excludes[dir_key]:
skip_defaults = True
transfer_source_excludes.remove("<no-defaults>")
if not skip_defaults and default_excludes is not None:
transfer_source_excludes.extend(list(default_excludes))
# Build the destination-base-relative dest dir into which
# we'll be syncing. Relative directory defaults to the
# dir id
rel_dest_dir = dest_dirs.get(dir_key, dir_id)
transfer_dest_dir = os.path.join(dest_base_dir, rel_dest_dir)
# Add the exploded paths to the list that we'll ask the
# transfer agent to transfer for us.
transfer_specs.append(
transfer.transfer_spec.TransferSpec(
transfer_source_dir,
transfer_source_excludes,
transfer_dest_dir))
# Do the transfer.
if len(transfer_specs) > 0:
transfer_agent.transfer(transfer_specs, options.dry_run)
else:
raise Exception("nothing to transfer, bad configuration?")
def main():
"""Drives the main program."""
options = parse_args()
if options.default_excludes and len(options.default_excludes) > 0:
default_excludes = options.default_excludes.split(",")
else:
default_excludes = []
# Locate the rc filename to load, then load it.
rc_filename = find_appropriate_rcfile(options)
if rc_filename:
if options.verbose:
print("reading rc data from file '{}'".format(rc_filename))
rcdata = read_rcfile(rc_filename)
else:
sys.stderr.write("no rcfile specified, cannot guess configuration")
exit(1)
# Find configuration.
configuration = get_configuration(options, rcdata, options.config_name)
if not configuration:
sys.stderr.write("failed to find configuration for {}".format(
options.config_data))
exit(2)
# Kick off the transfer.
sync_configured_sources(options, configuration, default_excludes)
if __name__ == "__main__":
main()

View File

@ -1,406 +0,0 @@
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 $

View File

@ -1,94 +0,0 @@
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

View File

@ -1,18 +0,0 @@
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 $

View File

@ -1,238 +0,0 @@
#!/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()

View File

@ -1,294 +0,0 @@
#!/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()

View File

@ -1,116 +0,0 @@
#!/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()

View File

@ -1,13 +0,0 @@
#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");
}

View File

@ -1,182 +0,0 @@
#!/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()

View File

@ -1,144 +0,0 @@
#!/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()

View File

@ -1,131 +0,0 @@
#!/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()

View File

@ -1,59 +0,0 @@
=================
LLDB Vim Frontend
=================
Prerequisites
-------------
This plugin is known to work with the following flavours of Vim:
* Linux (tested on Ubuntu 12.04/12.10):
* vim/gvim (from vim-gnome package version 7.3)
* Mac OS X (tested on Mountain Lion)
* Vim command-line (7.3 from Xcode)
* MacVim 7.3
To install the plugin, ensure you have
* a working version of lldb on your path, or the environment variable LLDB
pointing to the lldb binary you would like to use.
* a python-enabled vim (check with ":python print 2")
Installation
------------
1) Install the Vim pathogen plugin (it keeps installed plugins organized):
https://github.com/tpope/vim-pathogen
Or, for the impatient:
mkdir -p ~/.vim/autoload ~/.vim/bundle; \
curl -Sso ~/.vim/autoload/pathogen.vim \
https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim
2) Symlink (or copy) ~/.vim/bundle/vim-lldb to this directory:
ln -sf <lldb-dir>/utils/vim-lldb ~/.vim/bundle/vim-lldb
3) Update your help-tags. Start vim, do:
:Helptags
4) Have fun!
Usage/Getting Help
------------------
All LLDB commands (with tab-completion) can be accessed in Vim's
command mode. Try it out by typing:
:L<tab>
There are several sources of help available:
:help lldb -- Documentation for this plugin
:Lhelp -- LLDB's built-in help system (i.e lldb 'help' command)
:Lscript help (lldb) -- Complete LLDB Python API reference

View File

@ -1,115 +0,0 @@
*lldb.txt* A plugin that enables debugging from your favourite editor
Author: Daniel Malea <daniel.malea@intel.com>
License: Same terms as Vim itself (see |license|)
INTRODUCTION *lldb*
Installing this plugin enables a set of commands in Vim to control the
LLDB (http://lldb.llvm.org) debugger.
COMMANDS *lldb-commands*
The LLDB command interpreter is exposed to Vim's command mode using the
':L' prefix. Tab-completion is available and will cycle through commands.
Some commands have modified behaviour in Vim; for example, :Lbreakpoint
with no arguments will set a breakpoint at the current cursor, rather than
printing the standard help information for the LLDB command 'breakpoint'.
*lldb-windows*
In addition to the standard commands available under the LLDB interpreter,
there are also commands to display or hide informational debugger panes.
Windows can be shown or hidden using the ':Lhide <name>' or ':Lshow <name>'
commands.
*lldb-:Lhide*
:Lhide [windowname] Hide informational debugger pane named 'windowname'.
*lldb-:Lshow*
:Lshow [windowname] Show informational debugger pane named 'windowname'.
Possible window name arguments to the Lhide and Lshow commands include:
* backtrace
* breakpoints
* disassembly
* locals
* registers
* threads
*lldb-:Lattach*
:Lattach <process-name> Attach to a process by name.
*lldb-:Ldetach*
:Ldetach Detach from the current process.
*lldb-:Ltarget*
:Ltarget [[create] executable]
Create a target with the specified executable. If
run with a single argument, that argument is assumed
to be a path to the executable to be debugged.
Otherwise, all arguments are passed into LLDB's command
interpreter.
*lldb-:Lstart*
:Lstart Create a process by executing the current target
and wait for LLDB to attach.
*lldb-:Lrun*
:Lrun Create a process by executing the current target
without waiting for LLDB to attach.
*lldb-:Lcontinue*
:Lcontinue Continue execution of the process until the next
breakpoint is hit or the process exits.
*lldb-:Lthread*
:Lthread <args> Passes through to LLDB. See :Lhelp thread.
*lldb-:Lstep*
:Lstep Step into the current function call.
*lldb-:Lstepin*
:Lstepin Step into the current function call.
*lldb-:Lstepinst*
:Lstepinst Step one instruction.
*lldb-:Lstepinstover*
:Lstepinstover Step one instruction, but skip over jump or call
instructions.
*lldb-:Lnext*
:Lnext Step to the next line.
*lldb-:Lfinish*
:Lfinish Step out of the current function.
*lldb-:Lbreakpoint*
:Lbreakpoint [args] When arguments are provided, the lldb breakpoint
command is invoked. If no arguments are provided,
a breakpoint at the location under the cursor.
*lldb-:Lprint*
*lldb-:Lpo*
*lldb-:LpO*
:Lprint <expr> Aliases to the lldb print and po commands. Cursor
:Lpo <expr> word (cursor WORD for LpO) will be used when
:LpO <expr> expression omitted.
MAPPINGS *lldb-mappings*
On Mac OS X (under MacVim) , the following key mappings are available:
<Command-B> Insert a breakpoint at the line under cursor
ABOUT *lldb-about*
Grab the latest version of this plugin (and LLDB sources) with:
git clone https://github.com/llvm/llvm-project.git
File any bugs at:
http://llvm.org/bugs/enter_bug.cgi?product=lldb
vim:tw=78:et:ft=help:norl:

View File

@ -1,151 +0,0 @@
" Vim script glue code for LLDB integration
function! s:FindPythonScriptDir()
for dir in pathogen#split(&runtimepath)
let searchstr = "python-vim-lldb"
let candidates = pathogen#glob_directories(dir . "/" . searchstr)
if len(candidates) > 0
return candidates[0]
endif
endfor
return
endfunction()
function! s:InitLldbPlugin()
if has('python') == 0
call confirm('ERROR: This Vim installation does not have python support. lldb.vim will not work.')
return
endif
" Key-Bindings
" FIXME: choose sensible keybindings for:
" - process: start, interrupt, continue, continue-to-cursor
" - step: instruction, in, over, out
"
if has('gui_macvim')
" Apple-B toggles breakpoint on cursor
map <D-B> :Lbreakpoint<CR>
endif
"
" Setup the python interpreter path
"
let vim_lldb_pydir = s:FindPythonScriptDir()
execute 'python import sys; sys.path.append("' . vim_lldb_pydir . '")'
"
" Register :L<Command>
" The LLDB CommandInterpreter provides tab-completion in Vim's command mode.
" FIXME: this list of commands, at least partially should be auto-generated
"
" Window show/hide commands
command -complete=custom,s:CompleteWindow -nargs=1 Lhide python ctrl.doHide('<args>')
command -complete=custom,s:CompleteWindow -nargs=0 Lshow python ctrl.doShow('<args>')
" Launching convenience commands (no autocompletion)
command -nargs=* Lstart python ctrl.doLaunch(True, '<args>')
command -nargs=* Lrun python ctrl.doLaunch(False, '<args>')
command -nargs=1 Lattach python ctrl.doAttach('<args>')
command -nargs=0 Ldetach python ctrl.doDetach()
" Regexp-commands: because vim's command mode does not support '_' or '-'
" characters in command names, we omit them when creating the :L<cmd>
" equivalents.
command -complete=custom,s:CompleteCommand -nargs=* Lregexpattach python ctrl.doCommand('_regexp-attach', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpbreak python ctrl.doCommand('_regexp-break', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpbt python ctrl.doCommand('_regexp-bt', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpdown python ctrl.doCommand('_regexp-down', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexptbreak python ctrl.doCommand('_regexp-tbreak', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpdisplay python ctrl.doCommand('_regexp-display', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpundisplay python ctrl.doCommand('_regexp-undisplay', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregexpup python ctrl.doCommand('_regexp-up', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lapropos python ctrl.doCommand('apropos', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lbacktrace python ctrl.doCommand('bt', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lbreakpoint python ctrl.doBreakpoint('<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lcommand python ctrl.doCommand('command', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Ldisassemble python ctrl.doCommand('disassemble', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lexpression python ctrl.doCommand('expression', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lhelp python ctrl.doCommand('help', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Llog python ctrl.doCommand('log', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lplatform python ctrl.doCommand('platform','<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lplugin python ctrl.doCommand('plugin', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lprocess python ctrl.doProcess('<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lregister python ctrl.doCommand('register', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lscript python ctrl.doCommand('script', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lsettings python ctrl.doCommand('settings','<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lsource python ctrl.doCommand('source', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Ltype python ctrl.doCommand('type', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lversion python ctrl.doCommand('version', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Lwatchpoint python ctrl.doCommand('watchpoint', '<args>')
" Convenience (shortcut) LLDB commands
command -complete=custom,s:CompleteCommand -nargs=* Lprint python ctrl.doCommand('print', vim.eval("s:CursorWord('<args>')"))
command -complete=custom,s:CompleteCommand -nargs=* Lpo python ctrl.doCommand('po', vim.eval("s:CursorWord('<args>')"))
command -complete=custom,s:CompleteCommand -nargs=* LpO python ctrl.doCommand('po', vim.eval("s:CursorWORD('<args>')"))
command -complete=custom,s:CompleteCommand -nargs=* Lbt python ctrl.doCommand('bt', '<args>')
" Frame/Thread-Selection (commands that also do an Uupdate but do not
" generate events in LLDB)
command -complete=custom,s:CompleteCommand -nargs=* Lframe python ctrl.doSelect('frame', '<args>')
command -complete=custom,s:CompleteCommand -nargs=? Lup python ctrl.doCommand('up', '<args>', print_on_success=False, goto_file=True)
command -complete=custom,s:CompleteCommand -nargs=? Ldown python ctrl.doCommand('down', '<args>', print_on_success=False, goto_file=True)
command -complete=custom,s:CompleteCommand -nargs=* Lthread python ctrl.doSelect('thread', '<args>')
command -complete=custom,s:CompleteCommand -nargs=* Ltarget python ctrl.doTarget('<args>')
" Continue
command -complete=custom,s:CompleteCommand -nargs=* Lcontinue python ctrl.doContinue()
" Thread-Stepping (no autocompletion)
command -nargs=0 Lstepinst python ctrl.doStep(StepType.INSTRUCTION)
command -nargs=0 Lstepinstover python ctrl.doStep(StepType.INSTRUCTION_OVER)
command -nargs=0 Lstepin python ctrl.doStep(StepType.INTO)
command -nargs=0 Lstep python ctrl.doStep(StepType.INTO)
command -nargs=0 Lnext python ctrl.doStep(StepType.OVER)
command -nargs=0 Lfinish python ctrl.doStep(StepType.OUT)
" hack: service the LLDB event-queue when the cursor moves
" FIXME: some threaded solution would be better...but it
" would have to be designed carefully because Vim's APIs are non threadsafe;
" use of the vim module **MUST** be restricted to the main thread.
command -nargs=0 Lrefresh python ctrl.doRefresh()
autocmd CursorMoved * :Lrefresh
autocmd CursorHold * :Lrefresh
autocmd VimLeavePre * python ctrl.doExit()
execute 'pyfile ' . vim_lldb_pydir . '/plugin.py'
endfunction()
function! s:CompleteCommand(A, L, P)
python << EOF
a = vim.eval("a:A")
l = vim.eval("a:L")
p = vim.eval("a:P")
returnCompleteCommand(a, l, p)
EOF
endfunction()
function! s:CompleteWindow(A, L, P)
python << EOF
a = vim.eval("a:A")
l = vim.eval("a:L")
p = vim.eval("a:P")
returnCompleteWindow(a, l, p)
EOF
endfunction()
" Returns cword if search term is empty
function! s:CursorWord(term)
return empty(a:term) ? expand('<cword>') : a:term
endfunction()
" Returns cleaned cWORD if search term is empty
function! s:CursorWORD(term)
" Will strip all non-alphabetic characters from both sides
return empty(a:term) ? substitute(expand('<cWORD>'), '^\A*\(.\{-}\)\A*$', '\1', '') : a:term
endfunction()
call s:InitLldbPlugin()

View File

@ -1,71 +0,0 @@
# Locate and load the lldb python module
import os
import sys
def import_lldb():
""" Find and import the lldb modules. This function tries to find the lldb module by:
1. Simply by doing "import lldb" in case the system python installation is aware of lldb. If that fails,
2. Executes the lldb executable pointed to by the LLDB environment variable (or if unset, the first lldb
on PATH") with the -P flag to determine the PYTHONPATH to set. If the lldb executable returns a valid
path, it is added to sys.path and the import is attempted again. If that fails, 3. On Mac OS X the
default Xcode 4.5 installation path.
"""
# Try simple 'import lldb', in case of a system-wide install or a
# pre-configured PYTHONPATH
try:
import lldb
return True
except ImportError:
pass
# Allow overriding default path to lldb executable with the LLDB
# environment variable
lldb_executable = 'lldb'
if 'LLDB' in os.environ and os.path.exists(os.environ['LLDB']):
lldb_executable = os.environ['LLDB']
# Try using builtin module location support ('lldb -P')
from subprocess import check_output, CalledProcessError
try:
with open(os.devnull, 'w') as fnull:
lldb_minus_p_path = check_output(
"%s -P" %
lldb_executable,
shell=True,
stderr=fnull).strip()
if not os.path.exists(lldb_minus_p_path):
# lldb -P returned invalid path, probably too old
pass
else:
sys.path.append(lldb_minus_p_path)
import lldb
return True
except CalledProcessError:
# Cannot run 'lldb -P' to determine location of lldb python module
pass
except ImportError:
# Unable to import lldb module from path returned by `lldb -P`
pass
# On Mac OS X, use the try the default path to XCode lldb module
if "darwin" in sys.platform:
xcode_python_path = "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/Current/Resources/Python/"
sys.path.append(xcode_python_path)
try:
import lldb
return True
except ImportError:
# Unable to import lldb module from default Xcode python path
pass
return False
if not import_lldb():
import vim
vim.command(
'redraw | echo "%s"' %
" Error loading lldb module; vim-lldb will be disabled. Check LLDB installation or set LLDB environment variable.")

View File

@ -1,415 +0,0 @@
#
# This file defines the layer that talks to lldb
#
from __future__ import print_function
import os
import re
import sys
import lldb
import vim
from vim_ui import UI
# =================================================
# Convert some enum value to its string counterpart
# =================================================
# Shamelessly copy/pasted from lldbutil.py in the test suite
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")
class StepType:
INSTRUCTION = 1
INSTRUCTION_OVER = 2
INTO = 3
OVER = 4
OUT = 5
class LLDBController(object):
""" Handles Vim and LLDB events such as commands and lldb events. """
# Timeouts (sec) for waiting on new events. Because vim is not multi-threaded, we are restricted to
# servicing LLDB events from the main UI thread. Usually, we only process events that are already
# sitting on the queue. But in some situations (when we are expecting an event as a result of some
# user interaction) we want to wait for it. The constants below set these wait period in which the
# Vim UI is "blocked". Lower numbers will make Vim more responsive, but LLDB will be delayed and higher
# numbers will mean that LLDB events are processed faster, but the Vim UI may appear less responsive at
# times.
eventDelayStep = 2
eventDelayLaunch = 1
eventDelayContinue = 1
def __init__(self):
""" Creates the LLDB SBDebugger object and initializes the UI class. """
self.target = None
self.process = None
self.load_dependent_modules = True
self.dbg = lldb.SBDebugger.Create()
self.commandInterpreter = self.dbg.GetCommandInterpreter()
self.ui = UI()
def completeCommand(self, a, l, p):
""" Returns a list of viable completions for command a with length l and cursor at p """
assert l[0] == 'L'
# Remove first 'L' character that all commands start with
l = l[1:]
# Adjust length as string has 1 less character
p = int(p) - 1
result = lldb.SBStringList()
num = self.commandInterpreter.HandleCompletion(l, p, 1, -1, result)
if num == -1:
# FIXME: insert completion character... what's a completion
# character?
pass
elif num == -2:
# FIXME: replace line with result.GetStringAtIndex(0)
pass
if result.GetSize() > 0:
results = [_f for _f in [result.GetStringAtIndex(x)
for x in range(result.GetSize())] if _f]
return results
else:
return []
def doStep(self, stepType):
""" Perform a step command and block the UI for eventDelayStep seconds in order to process
events on lldb's event queue.
FIXME: if the step does not complete in eventDelayStep seconds, we relinquish control to
the main thread to avoid the appearance of a "hang". If this happens, the UI will
update whenever; usually when the user moves the cursor. This is somewhat annoying.
"""
if not self.process:
sys.stderr.write("No process to step")
return
t = self.process.GetSelectedThread()
if stepType == StepType.INSTRUCTION:
t.StepInstruction(False)
if stepType == StepType.INSTRUCTION_OVER:
t.StepInstruction(True)
elif stepType == StepType.INTO:
t.StepInto()
elif stepType == StepType.OVER:
t.StepOver()
elif stepType == StepType.OUT:
t.StepOut()
self.processPendingEvents(self.eventDelayStep, True)
def doSelect(self, command, args):
""" Like doCommand, but suppress output when "select" is the first argument."""
a = args.split(' ')
return self.doCommand(command, args, "select" != a[0], True)
def doProcess(self, args):
""" Handle 'process' command. If 'launch' is requested, use doLaunch() instead
of the command interpreter to start the inferior process.
"""
a = args.split(' ')
if len(args) == 0 or (len(a) > 0 and a[0] != 'launch'):
self.doCommand("process", args)
#self.ui.update(self.target, "", self)
else:
self.doLaunch('-s' not in args, "")
def doAttach(self, process_name):
""" Handle process attach. """
error = lldb.SBError()
self.processListener = lldb.SBListener("process_event_listener")
self.target = self.dbg.CreateTarget('')
self.process = self.target.AttachToProcessWithName(
self.processListener, process_name, False, error)
if not error.Success():
sys.stderr.write("Error during attach: " + str(error))
return
self.ui.activate()
self.pid = self.process.GetProcessID()
print("Attached to %s (pid=%d)" % (process_name, self.pid))
def doDetach(self):
if self.process is not None and self.process.IsValid():
pid = self.process.GetProcessID()
state = state_type_to_str(self.process.GetState())
self.process.Detach()
self.processPendingEvents(self.eventDelayLaunch)
def doLaunch(self, stop_at_entry, args):
""" Handle process launch. """
error = lldb.SBError()
fs = self.target.GetExecutable()
exe = os.path.join(fs.GetDirectory(), fs.GetFilename())
if self.process is not None and self.process.IsValid():
pid = self.process.GetProcessID()
state = state_type_to_str(self.process.GetState())
self.process.Destroy()
launchInfo = lldb.SBLaunchInfo(args.split(' '))
self.process = self.target.Launch(launchInfo, error)
if not error.Success():
sys.stderr.write("Error during launch: " + str(error))
return
# launch succeeded, store pid and add some event listeners
self.pid = self.process.GetProcessID()
self.processListener = lldb.SBListener("process_event_listener")
self.process.GetBroadcaster().AddListener(
self.processListener, lldb.SBProcess.eBroadcastBitStateChanged)
print("Launched %s %s (pid=%d)" % (exe, args, self.pid))
if not stop_at_entry:
self.doContinue()
else:
self.processPendingEvents(self.eventDelayLaunch)
def doTarget(self, args):
""" Pass target command to interpreter, except if argument is not one of the valid options, or
is create, in which case try to create a target with the argument as the executable. For example:
target list ==> handled by interpreter
target create blah ==> custom creation of target 'blah'
target blah ==> also creates target blah
"""
target_args = [ # "create",
"delete",
"list",
"modules",
"select",
"stop-hook",
"symbols",
"variable"]
a = args.split(' ')
if len(args) == 0 or (len(a) > 0 and a[0] in target_args):
self.doCommand("target", args)
return
elif len(a) > 1 and a[0] == "create":
exe = a[1]
elif len(a) == 1 and a[0] not in target_args:
exe = a[0]
err = lldb.SBError()
self.target = self.dbg.CreateTarget(
exe, None, None, self.load_dependent_modules, err)
if not self.target:
sys.stderr.write(
"Error creating target %s. %s" %
(str(exe), str(err)))
return
self.ui.activate()
self.ui.update(self.target, "created target %s" % str(exe), self)
def doContinue(self):
""" Handle 'contiue' command.
FIXME: switch to doCommand("continue", ...) to handle -i ignore-count param.
"""
if not self.process or not self.process.IsValid():
sys.stderr.write("No process to continue")
return
self.process.Continue()
self.processPendingEvents(self.eventDelayContinue)
def doBreakpoint(self, args):
""" Handle breakpoint command with command interpreter, except if the user calls
"breakpoint" with no other args, in which case add a breakpoint at the line
under the cursor.
"""
a = args.split(' ')
if len(args) == 0:
show_output = False
# User called us with no args, so toggle the bp under cursor
cw = vim.current.window
cb = vim.current.buffer
name = cb.name
line = cw.cursor[0]
# Since the UI is responsbile for placing signs at bp locations, we have to
# ask it if there already is one or more breakpoints at (file,
# line)...
if self.ui.haveBreakpoint(name, line):
bps = self.ui.getBreakpoints(name, line)
args = "delete %s" % " ".join([str(b.GetID()) for b in bps])
self.ui.deleteBreakpoints(name, line)
else:
args = "set -f %s -l %d" % (name, line)
else:
show_output = True
self.doCommand("breakpoint", args, show_output)
return
def doRefresh(self):
""" process pending events and update UI on request """
status = self.processPendingEvents()
def doShow(self, name):
""" handle :Lshow <name> """
if not name:
self.ui.activate()
return
if self.ui.showWindow(name):
self.ui.update(self.target, "", self)
def doHide(self, name):
""" handle :Lhide <name> """
if self.ui.hideWindow(name):
self.ui.update(self.target, "", self)
def doExit(self):
self.dbg.Terminate()
self.dbg = None
def getCommandResult(self, command, command_args):
""" Run cmd in the command interpreter and returns (success, output) """
result = lldb.SBCommandReturnObject()
cmd = "%s %s" % (command, command_args)
self.commandInterpreter.HandleCommand(cmd, result)
return (result.Succeeded(), result.GetOutput()
if result.Succeeded() else result.GetError())
def doCommand(
self,
command,
command_args,
print_on_success=True,
goto_file=False):
""" Run cmd in interpreter and print result (success or failure) on the vim status line. """
(success, output) = self.getCommandResult(command, command_args)
if success:
self.ui.update(self.target, "", self, goto_file)
if len(output) > 0 and print_on_success:
print(output)
else:
sys.stderr.write(output)
def getCommandOutput(self, command, command_args=""):
""" runs cmd in the command interpreter andreturns (status, result) """
result = lldb.SBCommandReturnObject()
cmd = "%s %s" % (command, command_args)
self.commandInterpreter.HandleCommand(cmd, result)
return (result.Succeeded(), result.GetOutput()
if result.Succeeded() else result.GetError())
def processPendingEvents(self, wait_seconds=0, goto_file=True):
""" Handle any events that are queued from the inferior.
Blocks for at most wait_seconds, or if wait_seconds == 0,
process only events that are already queued.
"""
status = None
num_events_handled = 0
if self.process is not None:
event = lldb.SBEvent()
old_state = self.process.GetState()
new_state = None
done = False
if old_state == lldb.eStateInvalid or old_state == lldb.eStateExited:
# Early-exit if we are in 'boring' states
pass
else:
while not done and self.processListener is not None:
if not self.processListener.PeekAtNextEvent(event):
if wait_seconds > 0:
# No events on the queue, but we are allowed to wait for wait_seconds
# for any events to show up.
self.processListener.WaitForEvent(
wait_seconds, event)
new_state = lldb.SBProcess.GetStateFromEvent(event)
num_events_handled += 1
done = not self.processListener.PeekAtNextEvent(event)
else:
# An event is on the queue, process it here.
self.processListener.GetNextEvent(event)
new_state = lldb.SBProcess.GetStateFromEvent(event)
# continue if stopped after attaching
if old_state == lldb.eStateAttaching and new_state == lldb.eStateStopped:
self.process.Continue()
# If needed, perform any event-specific behaviour here
num_events_handled += 1
if num_events_handled == 0:
pass
else:
if old_state == new_state:
status = ""
self.ui.update(self.target, status, self, goto_file)
def returnCompleteCommand(a, l, p):
""" Returns a "\n"-separated string with possible completion results
for command a with length l and cursor at p.
"""
separator = "\n"
results = ctrl.completeCommand(a, l, p)
vim.command('return "%s%s"' % (separator.join(results), separator))
def returnCompleteWindow(a, l, p):
""" Returns a "\n"-separated string with possible completion results
for commands that expect a window name parameter (like hide/show).
FIXME: connect to ctrl.ui instead of hardcoding the list here
"""
separator = "\n"
results = [
'breakpoints',
'backtrace',
'disassembly',
'locals',
'threads',
'registers']
vim.command('return "%s%s"' % (separator.join(results), separator))
global ctrl
ctrl = LLDBController()

View File

@ -1,16 +0,0 @@
# Try to import all dependencies, catch and handle the error gracefully if
# it fails.
import import_lldb
try:
import lldb
import vim
except ImportError:
sys.stderr.write(
"Unable to load vim/lldb module. Check lldb is on the path is available (or LLDB is set) and that script is invoked inside Vim with :pyfile")
pass
else:
# Everthing went well, so use import to start the plugin controller
from lldb_controller import *

View File

@ -1,669 +0,0 @@
#
# This file contains implementations of the LLDB display panes in VIM
#
# The most generic way to define a new window is to inherit from VimPane
# and to implement:
# - get_content() - returns a string with the pane contents
#
# Optionally, to highlight text, implement:
# - get_highlights() - returns a map
#
# And call:
# - define_highlight(unique_name, colour)
# at some point in the constructor.
#
#
# If the pane shows some key-value data that is in the context of a
# single frame, inherit from FrameKeyValuePane and implement:
# - get_frame_content(self, SBFrame frame)
#
#
# If the pane presents some information that can be retrieved with
# a simple LLDB command while the subprocess is stopped, inherit
# from StoppedCommandPane and call:
# - self.setCommand(command, command_args)
# at some point in the constructor.
#
# Optionally, you can implement:
# - get_selected_line()
# to highlight a selected line and place the cursor there.
#
#
# FIXME: implement WatchlistPane to displayed watched expressions
# FIXME: define interface for interactive panes, like catching enter
# presses to change selected frame/thread...
#
import lldb
import vim
import sys
# ==============================================================
# Get the description of an lldb object or None if not available
# ==============================================================
# Shamelessly copy/pasted from lldbutil.py in the test suite
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()
def get_selected_thread(target):
""" Returns a tuple with (thread, error) where thread == None if error occurs """
process = target.GetProcess()
if process is None or not process.IsValid():
return (None, VimPane.MSG_NO_PROCESS)
thread = process.GetSelectedThread()
if thread is None or not thread.IsValid():
return (None, VimPane.MSG_NO_THREADS)
return (thread, "")
def get_selected_frame(target):
""" Returns a tuple with (frame, error) where frame == None if error occurs """
(thread, error) = get_selected_thread(target)
if thread is None:
return (None, error)
frame = thread.GetSelectedFrame()
if frame is None or not frame.IsValid():
return (None, VimPane.MSG_NO_FRAME)
return (frame, "")
def _cmd(cmd):
vim.command("call confirm('%s')" % cmd)
vim.command(cmd)
def move_cursor(line, col=0):
""" moves cursor to specified line and col """
cw = vim.current.window
if cw.cursor[0] != line:
vim.command("execute \"normal %dgg\"" % line)
def winnr():
""" Returns currently selected window number """
return int(vim.eval("winnr()"))
def bufwinnr(name):
""" Returns window number corresponding with buffer name """
return int(vim.eval("bufwinnr('%s')" % name))
def goto_window(nr):
""" go to window number nr"""
if nr != winnr():
vim.command(str(nr) + ' wincmd w')
def goto_next_window():
""" go to next window. """
vim.command('wincmd w')
return (winnr(), vim.current.buffer.name)
def goto_previous_window():
""" go to previously selected window """
vim.command("execute \"normal \\<c-w>p\"")
def have_gui():
""" Returns True if vim is in a gui (Gvim/MacVim), False otherwise. """
return int(vim.eval("has('gui_running')")) == 1
class PaneLayout(object):
""" A container for a (vertical) group layout of VimPanes """
def __init__(self):
self.panes = {}
def havePane(self, name):
""" Returns true if name is a registered pane, False otherwise """
return name in self.panes
def prepare(self, panes=[]):
""" Draw panes on screen. If empty list is provided, show all. """
# If we can't select a window contained in the layout, we are doing a
# first draw
first_draw = not self.selectWindow(True)
did_first_draw = False
# Prepare each registered pane
for name in self.panes:
if name in panes or len(panes) == 0:
if first_draw:
# First window in layout will be created with :vsp, and
# closed later
vim.command(":vsp")
first_draw = False
did_first_draw = True
self.panes[name].prepare()
if did_first_draw:
# Close the split window
vim.command(":q")
self.selectWindow(False)
def contains(self, bufferName=None):
""" Returns True if window with name bufferName is contained in the layout, False otherwise.
If bufferName is None, the currently selected window is checked.
"""
if not bufferName:
bufferName = vim.current.buffer.name
for p in self.panes:
if bufferName is not None and bufferName.endswith(p):
return True
return False
def selectWindow(self, select_contained=True):
""" Selects a window contained in the layout (if select_contained = True) and returns True.
If select_contained = False, a window that is not contained is selected. Returns False
if no group windows can be selected.
"""
if select_contained == self.contains():
# Simple case: we are already selected
return True
# Otherwise, switch to next window until we find a contained window, or
# reach the first window again.
first = winnr()
(curnum, curname) = goto_next_window()
while not select_contained == self.contains(
curname) and curnum != first:
(curnum, curname) = goto_next_window()
return self.contains(curname) == select_contained
def hide(self, panes=[]):
""" Hide panes specified. If empty list provided, hide all. """
for name in self.panes:
if name in panes or len(panes) == 0:
self.panes[name].destroy()
def registerForUpdates(self, p):
self.panes[p.name] = p
def update(self, target, controller):
for name in self.panes:
self.panes[name].update(target, controller)
class VimPane(object):
""" A generic base class for a pane that displays stuff """
CHANGED_VALUE_HIGHLIGHT_NAME_GUI = 'ColorColumn'
CHANGED_VALUE_HIGHLIGHT_NAME_TERM = 'lldb_changed'
CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM = 'darkred'
SELECTED_HIGHLIGHT_NAME_GUI = 'Cursor'
SELECTED_HIGHLIGHT_NAME_TERM = 'lldb_selected'
SELECTED_HIGHLIGHT_COLOUR_TERM = 'darkblue'
MSG_NO_TARGET = "Target does not exist."
MSG_NO_PROCESS = "Process does not exist."
MSG_NO_THREADS = "No valid threads."
MSG_NO_FRAME = "No valid frame."
# list of defined highlights, so we avoid re-defining them
highlightTypes = []
def __init__(self, owner, name, open_below=False, height=3):
self.owner = owner
self.name = name
self.buffer = None
self.maxHeight = 20
self.openBelow = open_below
self.height = height
self.owner.registerForUpdates(self)
def isPrepared(self):
""" check window is OK """
if self.buffer is None or len(
dir(self.buffer)) == 0 or bufwinnr(self.name) == -1:
return False
return True
def prepare(self, method='new'):
""" check window is OK, if not then create """
if not self.isPrepared():
self.create(method)
def on_create(self):
pass
def destroy(self):
""" destroy window """
if self.buffer is None or len(dir(self.buffer)) == 0:
return
vim.command('bdelete ' + self.name)
def create(self, method):
""" create window """
if method != 'edit':
belowcmd = "below" if self.openBelow else ""
vim.command('silent %s %s %s' % (belowcmd, method, self.name))
else:
vim.command('silent %s %s' % (method, self.name))
self.window = vim.current.window
# Set LLDB pane options
vim.command("setlocal buftype=nofile") # Don't try to open a file
vim.command("setlocal noswapfile") # Don't use a swap file
vim.command("set nonumber") # Don't display line numbers
# vim.command("set nowrap") # Don't wrap text
# Save some parameters and reference to buffer
self.buffer = vim.current.buffer
self.width = int(vim.eval("winwidth(0)"))
self.height = int(vim.eval("winheight(0)"))
self.on_create()
goto_previous_window()
def update(self, target, controller):
""" updates buffer contents """
self.target = target
if not self.isPrepared():
# Window is hidden, or otherwise not ready for an update
return
original_cursor = self.window.cursor
# Select pane
goto_window(bufwinnr(self.name))
# Clean and update content, and apply any highlights.
self.clean()
if self.write(self.get_content(target, controller)):
self.apply_highlights()
cursor = self.get_selected_line()
if cursor is None:
# Place the cursor at its original position in the window
cursor_line = min(original_cursor[0], len(self.buffer))
cursor_col = min(
original_cursor[1], len(
self.buffer[
cursor_line - 1]))
else:
# Place the cursor at the location requested by a VimPane
# implementation
cursor_line = min(cursor, len(self.buffer))
cursor_col = self.window.cursor[1]
self.window.cursor = (cursor_line, cursor_col)
goto_previous_window()
def get_selected_line(self):
""" Returns the line number to move the cursor to, or None to leave
it where the user last left it.
Subclasses implement this to define custom behaviour.
"""
return None
def apply_highlights(self):
""" Highlights each set of lines in each highlight group """
highlights = self.get_highlights()
for highlightType in highlights:
lines = highlights[highlightType]
if len(lines) == 0:
continue
cmd = 'match %s /' % highlightType
lines = ['\%' + '%d' % line + 'l' for line in lines]
cmd += '\\|'.join(lines)
cmd += '/'
vim.command(cmd)
def define_highlight(self, name, colour):
""" Defines highlihght """
if name in VimPane.highlightTypes:
# highlight already defined
return
vim.command(
"highlight %s ctermbg=%s guibg=%s" %
(name, colour, colour))
VimPane.highlightTypes.append(name)
def write(self, msg):
""" replace buffer with msg"""
self.prepare()
msg = str(msg.encode("utf-8", "replace")).split('\n')
try:
self.buffer.append(msg)
vim.command("execute \"normal ggdd\"")
except vim.error:
# cannot update window; happens when vim is exiting.
return False
move_cursor(1, 0)
return True
def clean(self):
""" clean all datas in buffer """
self.prepare()
vim.command(':%d')
#self.buffer[:] = None
def get_content(self, target, controller):
""" subclasses implement this to provide pane content """
assert(0 and "pane subclass must implement this")
pass
def get_highlights(self):
""" Subclasses implement this to provide pane highlights.
This function is expected to return a map of:
{ highlight_name ==> [line_number, ...], ... }
"""
return {}
class FrameKeyValuePane(VimPane):
def __init__(self, owner, name, open_below):
""" Initialize parent, define member variables, choose which highlight
to use based on whether or not we have a gui (MacVim/Gvim).
"""
VimPane.__init__(self, owner, name, open_below)
# Map-of-maps key/value history { frame --> { variable_name,
# variable_value } }
self.frameValues = {}
if have_gui():
self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_GUI
else:
self.changedHighlight = VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM
self.define_highlight(VimPane.CHANGED_VALUE_HIGHLIGHT_NAME_TERM,
VimPane.CHANGED_VALUE_HIGHLIGHT_COLOUR_TERM)
def format_pair(self, key, value, changed=False):
""" Formats a key/value pair. Appends a '*' if changed == True """
marker = '*' if changed else ' '
return "%s %s = %s\n" % (marker, key, value)
def get_content(self, target, controller):
""" Get content for a frame-aware pane. Also builds the list of lines that
need highlighting (i.e. changed values.)
"""
if target is None or not target.IsValid():
return VimPane.MSG_NO_TARGET
self.changedLines = []
(frame, err) = get_selected_frame(target)
if frame is None:
return err
output = get_description(frame)
lineNum = 1
# Retrieve the last values displayed for this frame
frameId = get_description(frame.GetBlock())
if frameId in self.frameValues:
frameOldValues = self.frameValues[frameId]
else:
frameOldValues = {}
# Read the frame variables
vals = self.get_frame_content(frame)
for (key, value) in vals:
lineNum += 1
if len(frameOldValues) == 0 or (
key in frameOldValues and frameOldValues[key] == value):
output += self.format_pair(key, value)
else:
output += self.format_pair(key, value, True)
self.changedLines.append(lineNum)
# Save values as oldValues
newValues = {}
for (key, value) in vals:
newValues[key] = value
self.frameValues[frameId] = newValues
return output
def get_highlights(self):
ret = {}
ret[self.changedHighlight] = self.changedLines
return ret
class LocalsPane(FrameKeyValuePane):
""" Pane that displays local variables """
def __init__(self, owner, name='locals'):
FrameKeyValuePane.__init__(self, owner, name, open_below=True)
# FIXME: allow users to customize display of args/locals/statics/scope
self.arguments = True
self.show_locals = True
self.show_statics = True
self.show_in_scope_only = True
def format_variable(self, var):
""" Returns a Tuple of strings "(Type) Name", "Value" for SBValue var """
val = var.GetValue()
if val is None:
# If the value is too big, SBValue.GetValue() returns None; replace
# with ...
val = "..."
return ("(%s) %s" % (var.GetTypeName(), var.GetName()), "%s" % val)
def get_frame_content(self, frame):
""" Returns list of key-value pairs of local variables in frame """
vals = frame.GetVariables(self.arguments,
self.show_locals,
self.show_statics,
self.show_in_scope_only)
return [self.format_variable(x) for x in vals]
class RegistersPane(FrameKeyValuePane):
""" Pane that displays the contents of registers """
def __init__(self, owner, name='registers'):
FrameKeyValuePane.__init__(self, owner, name, open_below=True)
def format_register(self, reg):
""" Returns a tuple of strings ("name", "value") for SBRegister reg. """
name = reg.GetName()
val = reg.GetValue()
if val is None:
val = "..."
return (name, val.strip())
def get_frame_content(self, frame):
""" Returns a list of key-value pairs ("name", "value") of registers in frame """
result = []
for register_sets in frame.GetRegisters():
# hack the register group name into the list of registers...
result.append((" = = %s =" % register_sets.GetName(), ""))
for reg in register_sets:
result.append(self.format_register(reg))
return result
class CommandPane(VimPane):
""" Pane that displays the output of an LLDB command """
def __init__(self, owner, name, open_below, process_required=True):
VimPane.__init__(self, owner, name, open_below)
self.process_required = process_required
def setCommand(self, command, args=""):
self.command = command
self.args = args
def get_content(self, target, controller):
output = ""
if not target:
output = VimPane.MSG_NO_TARGET
elif self.process_required and not target.GetProcess():
output = VimPane.MSG_NO_PROCESS
else:
(success, output) = controller.getCommandOutput(
self.command, self.args)
return output
class StoppedCommandPane(CommandPane):
""" Pane that displays the output of an LLDB command when the process is
stopped; otherwise displays process status. This class also implements
highlighting for a single line (to show a single-line selected entity.)
"""
def __init__(self, owner, name, open_below):
""" Initialize parent and define highlight to use for selected line. """
CommandPane.__init__(self, owner, name, open_below)
if have_gui():
self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_GUI
else:
self.selectedHighlight = VimPane.SELECTED_HIGHLIGHT_NAME_TERM
self.define_highlight(VimPane.SELECTED_HIGHLIGHT_NAME_TERM,
VimPane.SELECTED_HIGHLIGHT_COLOUR_TERM)
def get_content(self, target, controller):
""" Returns the output of a command that relies on the process being stopped.
If the process is not in 'stopped' state, the process status is returned.
"""
output = ""
if not target or not target.IsValid():
output = VimPane.MSG_NO_TARGET
elif not target.GetProcess() or not target.GetProcess().IsValid():
output = VimPane.MSG_NO_PROCESS
elif target.GetProcess().GetState() == lldb.eStateStopped:
(success, output) = controller.getCommandOutput(
self.command, self.args)
else:
(success, output) = controller.getCommandOutput("process", "status")
return output
def get_highlights(self):
""" Highlight the line under the cursor. Users moving the cursor has
no effect on the selected line.
"""
ret = {}
line = self.get_selected_line()
if line is not None:
ret[self.selectedHighlight] = [line]
return ret
return ret
def get_selected_line(self):
""" Subclasses implement this to control where the cursor (and selected highlight)
is placed.
"""
return None
class DisassemblyPane(CommandPane):
""" Pane that displays disassembly around PC """
def __init__(self, owner, name='disassembly'):
CommandPane.__init__(self, owner, name, open_below=True)
# FIXME: let users customize the number of instructions to disassemble
self.setCommand("disassemble", "-c %d -p" % self.maxHeight)
class ThreadPane(StoppedCommandPane):
""" Pane that displays threads list """
def __init__(self, owner, name='threads'):
StoppedCommandPane.__init__(self, owner, name, open_below=False)
self.setCommand("thread", "list")
# FIXME: the function below assumes threads are listed in sequential order,
# which turns out to not be the case. Highlighting of selected thread
# will be disabled until this can be fixed. LLDB prints a '*' anyways
# beside the selected thread, so this is not too big of a problem.
# def get_selected_line(self):
# """ Place the cursor on the line with the selected entity.
# Subclasses should override this to customize selection.
# Formula: selected_line = selected_thread_id + 1
# """
# (thread, err) = get_selected_thread(self.target)
# if thread is None:
# return None
# else:
# return thread.GetIndexID() + 1
class BacktracePane(StoppedCommandPane):
""" Pane that displays backtrace """
def __init__(self, owner, name='backtrace'):
StoppedCommandPane.__init__(self, owner, name, open_below=False)
self.setCommand("bt", "")
def get_selected_line(self):
""" Returns the line number in the buffer with the selected frame.
Formula: selected_line = selected_frame_id + 2
FIXME: the above formula hack does not work when the function return
value is printed in the bt window; the wrong line is highlighted.
"""
(frame, err) = get_selected_frame(self.target)
if frame is None:
return None
else:
return frame.GetFrameID() + 2
class BreakpointsPane(CommandPane):
def __init__(self, owner, name='breakpoints'):
super(
BreakpointsPane,
self).__init__(
owner,
name,
open_below=False,
process_required=False)
self.setCommand("breakpoint", "list")

View File

@ -1,81 +0,0 @@
# Classes responsible for drawing signs in the Vim user interface.
import vim
class VimSign(object):
SIGN_TEXT_BREAKPOINT_RESOLVED = "B>"
SIGN_TEXT_BREAKPOINT_UNRESOLVED = "b>"
SIGN_TEXT_PC = "->"
SIGN_HIGHLIGHT_COLOUR_PC = 'darkblue'
# unique sign id (for ':[sign/highlight] define)
sign_id = 1
# unique name id (for ':sign place')
name_id = 1
# Map of {(sign_text, highlight_colour) --> sign_name}
defined_signs = {}
def __init__(self, sign_text, buffer, line_number, highlight_colour=None):
""" Define the sign and highlight (if applicable) and show the sign. """
# Get the sign name, either by defining it, or looking it up in the map
# of defined signs
key = (sign_text, highlight_colour)
if key not in VimSign.defined_signs:
name = self.define(sign_text, highlight_colour)
else:
name = VimSign.defined_signs[key]
self.show(name, buffer.number, line_number)
pass
def define(self, sign_text, highlight_colour):
""" Defines sign and highlight (if highlight_colour is not None). """
sign_name = "sign%d" % VimSign.name_id
if highlight_colour is None:
vim.command("sign define %s text=%s" % (sign_name, sign_text))
else:
self.highlight_name = "highlight%d" % VimSign.name_id
vim.command(
"highlight %s ctermbg=%s guibg=%s" %
(self.highlight_name, highlight_colour, highlight_colour))
vim.command(
"sign define %s text=%s linehl=%s texthl=%s" %
(sign_name, sign_text, self.highlight_name, self.highlight_name))
VimSign.defined_signs[(sign_text, highlight_colour)] = sign_name
VimSign.name_id += 1
return sign_name
def show(self, name, buffer_number, line_number):
self.id = VimSign.sign_id
VimSign.sign_id += 1
vim.command("sign place %d name=%s line=%d buffer=%s" %
(self.id, name, line_number, buffer_number))
pass
def hide(self):
vim.command("sign unplace %d" % self.id)
pass
class BreakpointSign(VimSign):
def __init__(self, buffer, line_number, is_resolved):
txt = VimSign.SIGN_TEXT_BREAKPOINT_RESOLVED if is_resolved else VimSign.SIGN_TEXT_BREAKPOINT_UNRESOLVED
super(BreakpointSign, self).__init__(txt, buffer, line_number)
class PCSign(VimSign):
def __init__(self, buffer, line_number, is_selected_thread):
super(
PCSign,
self).__init__(
VimSign.SIGN_TEXT_PC,
buffer,
line_number,
VimSign.SIGN_HIGHLIGHT_COLOUR_PC if is_selected_thread else None)

View File

@ -1,257 +0,0 @@
# LLDB UI state in the Vim user interface.
from __future__ import print_function
import os
import re
import sys
import lldb
import vim
from vim_panes import *
from vim_signs import *
def is_same_file(a, b):
""" returns true if paths a and b are the same file """
a = os.path.realpath(a)
b = os.path.realpath(b)
return a in b or b in a
class UI:
def __init__(self):
""" Declare UI state variables """
# Default panes to display
self.defaultPanes = [
'breakpoints',
'backtrace',
'locals',
'threads',
'registers',
'disassembly']
# map of tuples (filename, line) --> SBBreakpoint
self.markedBreakpoints = {}
# Currently shown signs
self.breakpointSigns = {}
self.pcSigns = []
# Container for panes
self.paneCol = PaneLayout()
# All possible LLDB panes
self.backtracePane = BacktracePane(self.paneCol)
self.threadPane = ThreadPane(self.paneCol)
self.disassemblyPane = DisassemblyPane(self.paneCol)
self.localsPane = LocalsPane(self.paneCol)
self.registersPane = RegistersPane(self.paneCol)
self.breakPane = BreakpointsPane(self.paneCol)
def activate(self):
""" Activate UI: display default set of panes """
self.paneCol.prepare(self.defaultPanes)
def get_user_buffers(self, filter_name=None):
""" Returns a list of buffers that are not a part of the LLDB UI. That is, they
are not contained in the PaneLayout object self.paneCol.
"""
ret = []
for w in vim.windows:
b = w.buffer
if not self.paneCol.contains(b.name):
if filter_name is None or filter_name in b.name:
ret.append(b)
return ret
def update_pc(self, process, buffers, goto_file):
""" Place the PC sign on the PC location of each thread's selected frame """
def GetPCSourceLocation(thread):
""" Returns a tuple (thread_index, file, line, column) that represents where
the PC sign should be placed for a thread.
"""
frame = thread.GetSelectedFrame()
frame_num = frame.GetFrameID()
le = frame.GetLineEntry()
while not le.IsValid() and frame_num < thread.GetNumFrames():
frame_num += 1
le = thread.GetFrameAtIndex(frame_num).GetLineEntry()
if le.IsValid():
path = os.path.join(
le.GetFileSpec().GetDirectory(),
le.GetFileSpec().GetFilename())
return (
thread.GetIndexID(),
path,
le.GetLine(),
le.GetColumn())
return None
# Clear all existing PC signs
del_list = []
for sign in self.pcSigns:
sign.hide()
del_list.append(sign)
for sign in del_list:
self.pcSigns.remove(sign)
del sign
# Select a user (non-lldb) window
if not self.paneCol.selectWindow(False):
# No user window found; avoid clobbering by splitting
vim.command(":vsp")
# Show a PC marker for each thread
for thread in process:
loc = GetPCSourceLocation(thread)
if not loc:
# no valid source locations for PCs. hide all existing PC
# markers
continue
buf = None
(tid, fname, line, col) = loc
buffers = self.get_user_buffers(fname)
is_selected = thread.GetIndexID() == process.GetSelectedThread().GetIndexID()
if len(buffers) == 1:
buf = buffers[0]
if buf != vim.current.buffer:
# Vim has an open buffer to the required file: select it
vim.command('execute ":%db"' % buf.number)
elif is_selected and vim.current.buffer.name not in fname and os.path.exists(fname) and goto_file:
# FIXME: If current buffer is modified, vim will complain when we try to switch away.
# Find a way to detect if the current buffer is modified,
# and...warn instead?
vim.command('execute ":e %s"' % fname)
buf = vim.current.buffer
elif len(buffers) > 1 and goto_file:
# FIXME: multiple open buffers match PC location
continue
else:
continue
self.pcSigns.append(PCSign(buf, line, is_selected))
if is_selected and goto_file:
# if the selected file has a PC marker, move the cursor there
# too
curname = vim.current.buffer.name
if curname is not None and is_same_file(curname, fname):
move_cursor(line, 0)
elif move_cursor:
print("FIXME: not sure where to move cursor because %s != %s " % (vim.current.buffer.name, fname))
def update_breakpoints(self, target, buffers):
""" Decorates buffer with signs corresponding to breakpoints in target. """
def GetBreakpointLocations(bp):
""" Returns a list of tuples (resolved, filename, line) where a breakpoint was resolved. """
if not bp.IsValid():
sys.stderr.write("breakpoint is invalid, no locations")
return []
ret = []
numLocs = bp.GetNumLocations()
for i in range(numLocs):
loc = bp.GetLocationAtIndex(i)
desc = get_description(loc, lldb.eDescriptionLevelFull)
match = re.search('at\ ([^:]+):([\d]+)', desc)
try:
lineNum = int(match.group(2).strip())
ret.append((loc.IsResolved(), match.group(1), lineNum))
except ValueError as e:
sys.stderr.write(
"unable to parse breakpoint location line number: '%s'" %
match.group(2))
sys.stderr.write(str(e))
return ret
if target is None or not target.IsValid():
return
needed_bps = {}
for bp_index in range(target.GetNumBreakpoints()):
bp = target.GetBreakpointAtIndex(bp_index)
locations = GetBreakpointLocations(bp)
for (is_resolved, file, line) in GetBreakpointLocations(bp):
for buf in buffers:
if file in buf.name:
needed_bps[(buf, line, is_resolved)] = bp
# Hide any signs that correspond with disabled breakpoints
del_list = []
for (b, l, r) in self.breakpointSigns:
if (b, l, r) not in needed_bps:
self.breakpointSigns[(b, l, r)].hide()
del_list.append((b, l, r))
for d in del_list:
del self.breakpointSigns[d]
# Show any signs for new breakpoints
for (b, l, r) in needed_bps:
bp = needed_bps[(b, l, r)]
if self.haveBreakpoint(b.name, l):
self.markedBreakpoints[(b.name, l)].append(bp)
else:
self.markedBreakpoints[(b.name, l)] = [bp]
if (b, l, r) not in self.breakpointSigns:
s = BreakpointSign(b, l, r)
self.breakpointSigns[(b, l, r)] = s
def update(self, target, status, controller, goto_file=False):
""" Updates debugger info panels and breakpoint/pc marks and prints
status to the vim status line. If goto_file is True, the user's
cursor is moved to the source PC location in the selected frame.
"""
self.paneCol.update(target, controller)
self.update_breakpoints(target, self.get_user_buffers())
if target is not None and target.IsValid():
process = target.GetProcess()
if process is not None and process.IsValid():
self.update_pc(process, self.get_user_buffers, goto_file)
if status is not None and len(status) > 0:
print(status)
def haveBreakpoint(self, file, line):
""" Returns True if we have a breakpoint at file:line, False otherwise """
return (file, line) in self.markedBreakpoints
def getBreakpoints(self, fname, line):
""" Returns the LLDB SBBreakpoint object at fname:line """
if self.haveBreakpoint(fname, line):
return self.markedBreakpoints[(fname, line)]
else:
return None
def deleteBreakpoints(self, name, line):
del self.markedBreakpoints[(name, line)]
def showWindow(self, name):
""" Shows (un-hides) window pane specified by name """
if not self.paneCol.havePane(name):
sys.stderr.write("unknown window: %s" % name)
return False
self.paneCol.prepare([name])
return True
def hideWindow(self, name):
""" Hides window pane specified by name """
if not self.paneCol.havePane(name):
sys.stderr.write("unknown window: %s" % name)
return False
self.paneCol.hide([name])
return True
global ui
ui = UI()