Vendor import of lldb trunk r257626:

https://llvm.org/svn/llvm-project/lldb/trunk@257626
This commit is contained in:
Dimitry Andric 2016-01-13 20:06:56 +00:00
parent 9e6d35490a
commit 7fed546d19
112 changed files with 2632 additions and 2548 deletions

View File

@ -0,0 +1,152 @@
//===-- LoadedModuleInfoList.h ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_LoadedModuleInfoList_h_
#define liblldb_LoadedModuleInfoList_h_
// C Includes
// C++ Includes
#include <vector>
// Other libraries and framework includes
#include "lldb/lldb-private-forward.h"
namespace lldb_private {
class LoadedModuleInfoList
{
public:
class LoadedModuleInfo
{
public:
enum e_data_point
{
e_has_name = 0,
e_has_base ,
e_has_dynamic ,
e_has_link_map ,
e_num
};
LoadedModuleInfo ()
{
for (uint32_t i = 0; i < e_num; ++i)
m_has[i] = false;
};
void set_name (const std::string & name)
{
m_name = name;
m_has[e_has_name] = true;
}
bool get_name (std::string & out) const
{
out = m_name;
return m_has[e_has_name];
}
void set_base (const lldb::addr_t base)
{
m_base = base;
m_has[e_has_base] = true;
}
bool get_base (lldb::addr_t & out) const
{
out = m_base;
return m_has[e_has_base];
}
void set_base_is_offset (bool is_offset)
{
m_base_is_offset = is_offset;
}
bool get_base_is_offset(bool & out) const
{
out = m_base_is_offset;
return m_has[e_has_base];
}
void set_link_map (const lldb::addr_t addr)
{
m_link_map = addr;
m_has[e_has_link_map] = true;
}
bool get_link_map (lldb::addr_t & out) const
{
out = m_link_map;
return m_has[e_has_link_map];
}
void set_dynamic (const lldb::addr_t addr)
{
m_dynamic = addr;
m_has[e_has_dynamic] = true;
}
bool get_dynamic (lldb::addr_t & out) const
{
out = m_dynamic;
return m_has[e_has_dynamic];
}
bool has_info (e_data_point datum) const
{
assert (datum < e_num);
return m_has[datum];
}
bool
operator == (LoadedModuleInfo const &rhs) const
{
if (e_num != rhs.e_num)
return false;
for (size_t i = 0; i < e_num; ++i)
{
if (m_has[i] != rhs.m_has[i])
return false;
}
return (m_base == rhs.m_base) &&
(m_link_map == rhs.m_link_map) &&
(m_dynamic == rhs.m_dynamic) &&
(m_name == rhs.m_name);
}
protected:
bool m_has[e_num];
std::string m_name;
lldb::addr_t m_link_map;
lldb::addr_t m_base;
bool m_base_is_offset;
lldb::addr_t m_dynamic;
};
LoadedModuleInfoList ()
: m_list ()
, m_link_map (LLDB_INVALID_ADDRESS)
{}
void add (const LoadedModuleInfo & mod)
{
m_list.push_back (mod);
}
void clear ()
{
m_list.clear ();
}
std::vector<LoadedModuleInfo> m_list;
lldb::addr_t m_link_map;
};
} // namespace lldb_private
#endif // liblldb_LoadedModuleInfoList_h_

View File

@ -170,6 +170,18 @@ class CommandReturnObject
void
SetInteractive (bool b);
bool
GetAbnormalStopWasExpected() const
{
return m_abnormal_stop_was_expected;
}
void
SetAbnormalStopWasExpected(bool signal_was_expected)
{
m_abnormal_stop_was_expected = signal_was_expected;
}
private:
enum
{
@ -183,6 +195,12 @@ class CommandReturnObject
lldb::ReturnStatus m_status;
bool m_did_change_process_state;
bool m_interactive; // If true, then the input handle from the debugger will be hooked up
bool m_abnormal_stop_was_expected; // This is to support eHandleCommandFlagStopOnCrash vrs. attach.
// The attach command often ends up with the process stopped due to a signal.
// Normally that would mean stop on crash should halt batch execution, but we
// obviously don't want that for attach. Using this flag, the attach command
// (and anything else for which this is relevant) can say that the signal is
// expected, and batch command execution can continue.
};
} // namespace lldb_private

View File

@ -573,6 +573,9 @@ class ClangASTContext : public TypeSystem
ConstString
DeclContextGetName (void *opaque_decl_ctx) override;
ConstString
DeclContextGetScopeQualifiedName (void *opaque_decl_ctx) override;
bool
DeclContextIsClassMethod (void *opaque_decl_ctx,
lldb::LanguageType *language_ptr,

View File

@ -128,6 +128,9 @@ class CompilerDeclContext
ConstString
GetName () const;
ConstString
GetScopeQualifiedName() const;
bool
IsStructUnionOrClass () const;

View File

@ -112,6 +112,12 @@ class GoASTContext : public TypeSystem
return ConstString();
}
ConstString
DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override
{
return ConstString();
}
bool
DeclContextIsClassMethod(void *opaque_decl_ctx, lldb::LanguageType *language_ptr, bool *is_instance_method_ptr,
ConstString *language_object_name_ptr) override

View File

@ -144,6 +144,7 @@ class SymbolFile :
virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, TypeMap& types);
virtual size_t FindTypes (const std::vector<CompilerContext> &context, bool append, TypeMap& types);
virtual void GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names);
// virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types) = 0;
virtual TypeList * GetTypeList ();
virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,

View File

@ -151,6 +151,9 @@ class TypeSystem : public PluginInterface
virtual ConstString
DeclContextGetName (void *opaque_decl_ctx) = 0;
virtual ConstString
DeclContextGetScopeQualifiedName (void *opaque_decl_ctx) = 0;
virtual bool
DeclContextIsClassMethod (void *opaque_decl_ctx,
lldb::LanguageType *language_ptr,

View File

@ -42,9 +42,6 @@ class CPPLanguageRuntime :
bool
GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override;
virtual size_t
GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) = 0;
protected:
//------------------------------------------------------------------

View File

@ -30,6 +30,7 @@
#include "lldb/Core/Communication.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/StructuredData.h"
@ -1152,6 +1153,12 @@ class Process :
return 0;
}
virtual size_t
LoadModules (LoadedModuleInfoList &)
{
return 0;
}
protected:
virtual JITLoaderList &
GetJITLoaders ();
@ -3149,6 +3156,34 @@ class Process :
void
ResetImageToken(size_t token);
//------------------------------------------------------------------
/// Find the next branch instruction to set a breakpoint on
///
/// When instruction stepping through a source line, instead of
/// stepping through each instruction, we can put a breakpoint on
/// the next branch instruction (within the range of instructions
/// we are stepping through) and continue the process to there,
/// yielding significant performance benefits over instruction
/// stepping.
///
/// @param[in] default_stop_addr
/// The address of the instruction where lldb would put a
/// breakpoint normally.
///
/// @param[in] range_bounds
/// The range which the breakpoint must be contained within.
/// Typically a source line.
///
/// @return
/// The address of the next branch instruction, or the end of
/// the range provided in range_bounds. If there are any
/// problems with the disassembly or getting the instructions,
/// the original default_stop_addr will be returned.
//------------------------------------------------------------------
Address
AdvanceAddressToNextBranchInstruction (Address default_stop_addr,
AddressRange range_bounds);
protected:
void
SetState (lldb::EventSP &event_sp);

View File

@ -275,6 +275,23 @@ class SystemRuntime :
return LLDB_INVALID_ADDRESS;
}
//------------------------------------------------------------------
/// Retrieve the Queue kind for the queue at a thread's dispatch_qaddr.
///
/// Retrieve the Queue kind - either eQueueKindSerial or
/// eQueueKindConcurrent, indicating that this queue processes work
/// items serially or concurrently.
///
/// @return
/// The Queue kind, if it could be read, else eQueueKindUnknown.
//------------------------------------------------------------------
virtual lldb::QueueKind
GetQueueKind (lldb::addr_t dispatch_qaddr)
{
return lldb::eQueueKindUnknown;
}
//------------------------------------------------------------------
/// Get the pending work items for a libdispatch Queue
///

View File

@ -366,6 +366,35 @@ class Thread :
{
}
//------------------------------------------------------------------
/// Whether this thread can be associated with a libdispatch queue
///
/// The Thread may know if it is associated with a libdispatch queue,
/// it may know definitively that it is NOT associated with a libdispatch
/// queue, or it may be unknown whether it is associated with a libdispatch
/// queue.
///
/// @return
/// eLazyBoolNo if this thread is definitely not associated with a
/// libdispatch queue (e.g. on a non-Darwin system where GCD aka
/// libdispatch is not available).
///
/// eLazyBoolYes this thread is associated with a libdispatch queue.
///
/// eLazyBoolCalculate this thread may be associated with a libdispatch
/// queue but the thread doesn't know one way or the other.
//------------------------------------------------------------------
virtual lldb_private::LazyBool
GetAssociatedWithLibdispatchQueue ()
{
return eLazyBoolNo;
}
virtual void
SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue)
{
}
//------------------------------------------------------------------
/// Retrieve the Queue ID for the queue currently using this Thread
///
@ -413,6 +442,29 @@ class Thread :
{
}
//------------------------------------------------------------------
/// Retrieve the Queue kind for the queue currently using this Thread
///
/// If this Thread is doing work on behalf of a libdispatch/GCD queue,
/// retrieve the Queue kind - either eQueueKindSerial or
/// eQueueKindConcurrent, indicating that this queue processes work
/// items serially or concurrently.
///
/// @return
/// The Queue kind, if the Thread subclass implements this, else
/// eQueueKindUnknown.
//------------------------------------------------------------------
virtual lldb::QueueKind
GetQueueKind ()
{
return lldb::eQueueKindUnknown;
}
virtual void
SetQueueKind (lldb::QueueKind kind)
{
}
//------------------------------------------------------------------
/// Retrieve the Queue for this thread, if any.
///
@ -451,6 +503,30 @@ class Thread :
return LLDB_INVALID_ADDRESS;
}
virtual void
SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t)
{
}
//------------------------------------------------------------------
/// Whether this Thread already has all the Queue information cached or not
///
/// A Thread may be associated with a libdispatch work Queue at a given
/// public stop event. If so, the thread can satisify requests like
/// GetQueueLibdispatchQueueAddress, GetQueueKind, GetQueueName, and GetQueueID
/// either from information from the remote debug stub when it is initially
/// created, or it can query the SystemRuntime for that information.
///
/// This method allows the SystemRuntime to discover if a thread has this
/// information already, instead of calling the thread to get the information
/// and having the thread call the SystemRuntime again.
//------------------------------------------------------------------
virtual bool
ThreadHasQueueInformation () const
{
return false;
}
virtual uint32_t
GetStackFrameCount()
{
@ -888,6 +964,16 @@ class Thread :
/// @param[in] run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// @param[in] continue_to_next_branch
/// Normally this will enqueue a plan that will put a breakpoint on the return address and continue
/// to there. If continue_to_next_branch is true, this is an operation not involving the user --
/// e.g. stepping "next" in a source line and we instruction stepped into another function --
/// so instead of putting a breakpoint on the return address, advance the breakpoint to the
/// end of the source line that is doing the call, or until the next flow control instruction.
/// If the return value from the function call is to be retrieved / displayed to the user, you must stop
/// on the return address. The return value may be stored in volatile registers which are overwritten
/// before the next branch instruction.
///
/// @return
/// A shared pointer to the newly queued thread plan, or nullptr if the plan could not be queued.
//------------------------------------------------------------------
@ -898,7 +984,8 @@ class Thread :
bool stop_other_threads,
Vote stop_vote, // = eVoteYes,
Vote run_vote, // = eVoteNoOpinion);
uint32_t frame_idx);
uint32_t frame_idx,
bool continue_to_next_branch = false);
//------------------------------------------------------------------
/// Gets the plan used to step through the code that steps from a function

View File

@ -31,7 +31,8 @@ class ThreadPlanStepOut : public ThreadPlan,
Vote stop_vote,
Vote run_vote,
uint32_t frame_idx,
LazyBool step_out_avoids_code_without_debug_info);
LazyBool step_out_avoids_code_without_debug_info,
bool continue_to_next_branch = false);
~ThreadPlanStepOut() override;

View File

@ -157,3 +157,10 @@ o Writing test cases:
then use SBInterpreter::HandleCommand to run the command. You get the full result text
from the command in the command return object, and all the part where you are driving the
debugger to the point you want to test will be more robust.
o Attaching in test cases:
If you need to attach to inferiors in your tests, you must make sure the inferior calls
lldb_enable_attach(), before the debugger attempts to attach. This function performs any
platform-specific processing needed to enable attaching to this process (e.g., on Linux, we
execute prctl(PR_SET_TRACER) syscall to disable protections present in some Linux systems).

View File

@ -51,7 +51,7 @@ def test_sb_api_listener_event_process_state(self):
@skipIfNoSBHeaders
@skipIfWindows # clang-cl does not support throw or catch (llvm.org/pr24538)
@expectedFlakeyFreeBSD
@expectedFlakeyLinux
@expectedFailureLinux
def test_sb_api_listener_resume(self):
""" Test that a process can be resumed from a non-main thread. """
self.build_and_test('driver.cpp listener_test.cpp test_listener_resume.cpp',

View File

@ -1149,11 +1149,6 @@ def getExpectedTimeouts(platform_name):
"TestExitDuringStep.py",
"TestHelloWorld.py",
}
if host.startswith("win32"):
expected_timeout |= {
"TestEvents.py",
"TestThreadStates.py",
}
elif target.startswith("freebsd"):
expected_timeout |= {
"TestBreakpointConditions.py",

View File

@ -14,21 +14,12 @@ class DriverBatchModeTest (TestBase):
mydir = TestBase.compute_mydir(__file__)
@skipIfRemote # test not remote-ready llvm.org/pr24813
@expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot")
@expectedFlakeyLinux("llvm.org/pr25172")
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
def test_driver_batch_mode(self):
"""Test that the lldb driver's batch mode works correctly."""
self.build()
self.setTearDownCleanup()
self.batch_mode()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Our simple source filename.
self.source = 'main.c'
self.victim = None
def expect_string (self, string):
import pexpect
@ -40,12 +31,20 @@ def expect_string (self, string):
except pexpect.TIMEOUT:
self.fail ("Timed out waiting for '%s'"%(string))
def batch_mode (self):
@skipIfRemote # test not remote-ready llvm.org/pr24813
@expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot")
@expectedFlakeyLinux("llvm.org/pr25172")
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
def test_batch_mode_run_crash (self):
"""Test that the lldb driver's batch mode works correctly."""
self.build()
self.setTearDownCleanup()
import pexpect
exe = os.path.join(os.getcwd(), "a.out")
prompt = "(lldb) "
# First time through, pass CRASH so the process will crash and stop in batch mode.
# Pass CRASH so the process will crash and stop in batch mode.
run_commands = ' -b -o "break set -n main" -o "run" -o "continue" -k "frame var touch_me_not"'
self.child = pexpect.spawn('%s %s %s %s -- CRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe))
child = self.child
@ -68,7 +67,21 @@ def batch_mode (self):
self.deletePexpectChild()
# Now do it again, and see make sure if we don't crash, we quit:
@skipIfRemote # test not remote-ready llvm.org/pr24813
@expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot")
@expectedFlakeyLinux("llvm.org/pr25172")
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
def test_batch_mode_run_exit (self):
"""Test that the lldb driver's batch mode works correctly."""
self.build()
self.setTearDownCleanup()
import pexpect
exe = os.path.join(os.getcwd(), "a.out")
prompt = "(lldb) "
# Now do it again, and make sure if we don't crash, we quit:
run_commands = ' -b -o "break set -n main" -o "run" -o "continue" '
self.child = pexpect.spawn('%s %s %s %s -- NOCRASH' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe))
child = self.child
@ -87,3 +100,69 @@ def batch_mode (self):
index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT])
self.assertTrue(index == 0, "lldb didn't close on successful batch completion.")
def closeVictim(self):
if self.victim != None:
self.victim.close()
self.victim = None
@skipIfRemote # test not remote-ready llvm.org/pr24813
@expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot")
@expectedFlakeyLinux("llvm.org/pr25172")
@expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
def test_batch_mode_attach_exit (self):
"""Test that the lldb driver's batch mode works correctly."""
self.build()
self.setTearDownCleanup()
import pexpect
exe = os.path.join(os.getcwd(), "a.out")
prompt = "(lldb) "
# Finally, start up the process by hand, attach to it, and wait for its completion.
# Attach is funny, since it looks like it stops with a signal on most Unixen so
# care must be taken not to treat that as a reason to exit batch mode.
# Start up the process by hand and wait for it to get to the wait loop.
self.victim = pexpect.spawn('%s WAIT' %(exe))
if self.victim == None:
self.fail("Could not spawn ", exe, ".")
self.addTearDownHook (self.closeVictim)
if self.TraceOn():
self.victim.logfile_read = sys.stdout
self.victim.expect("PID: ([0-9]+) END")
if self.victim.match == None:
self.fail("Couldn't get the target PID.")
victim_pid = int(self.victim.match.group(1))
self.victim.expect("Waiting")
run_commands = ' -b -o "process attach -p %d" -o "breakpoint set --file %s -p \'Stop here to unset keep_waiting\' -N keep_waiting" -o "continue" -o "break delete keep_waiting" -o "expr keep_waiting = 0" -o "continue" ' % (victim_pid, self.source)
self.child = pexpect.spawn('%s %s %s %s' % (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe))
child = self.child
# Turn on logging for what the child sends back.
if self.TraceOn():
child.logfile_read = sys.stdout
# We should see the "run":
self.expect_string ("attach")
self.expect_string(prompt + "continue")
self.expect_string(prompt + "continue")
# Then we should see the process exit:
self.expect_string ("Process %d exited with status"%(victim_pid))
victim_index = self.victim.expect([pexpect.EOF, pexpect.TIMEOUT])
self.assertTrue(victim_index == 0, "Victim didn't really exit.")
index = self.child.expect([pexpect.EOF, pexpect.TIMEOUT])
self.assertTrue(index == 0, "lldb didn't close on successful batch completion.")

View File

@ -1,10 +1,36 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
if (argc >= 2 && strcmp (argv[1], "CRASH") == 0)
lldb_enable_attach();
int do_crash = 0;
int do_wait = 0;
int idx;
for (idx = 1; idx < argc; idx++)
{
if (strcmp(argv[idx], "CRASH") == 0)
do_crash = 1;
if (strcmp(argv[idx], "WAIT") == 0)
do_wait = 1;
}
printf("PID: %d END\n", getpid());
if (do_wait)
{
int keep_waiting = 1;
while (keep_waiting)
{
printf ("Waiting\n");
sleep(1); // Stop here to unset keep_waiting
}
}
if (do_crash)
{
char *touch_me_not = (char *) 0;
printf ("About to crash.\n");

View File

@ -4,10 +4,6 @@
#include <chrono>
#include <thread>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
volatile bool debugger_flag = true; // The debugger will flip this to false
void *start(void *data)
@ -25,18 +21,7 @@ void *start(void *data)
int main(int argc, char const *argv[])
{
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
static_cast<void> (prctl_result);
#endif
#endif
lldb_enable_attach();
static const size_t nthreads = 16;
std::thread threads[nthreads];

View File

@ -0,0 +1,5 @@
LEVEL = ../../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,51 @@
"""
Test embedded breakpoints, like `asm int 3;` in x86 or or `__debugbreak` on Windows.
"""
from __future__ import print_function
import os
import lldb
from lldbsuite.test.lldbtest import *
import lldbsuite.test.lldbutil as lldbutil
class DebugBreakTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@skipIf(archs=not_in(["i386", "i686"]))
@no_debug_info_test
def test_asm_int_3(self):
"""Test that intrinsics like `__debugbreak();` and `asm {"int3"}` are treated like breakpoints."""
self.build()
exe = os.path.join(os.getcwd(), "a.out")
# Run the program.
target = self.dbg.CreateTarget(exe)
process = target.LaunchSimple(None, None, self.get_process_working_directory())
# We've hit the first stop, so grab the frame.
self.assertEqual(process.GetState(), lldb.eStateStopped)
thread = process.GetThreadAtIndex(0)
frame = thread.GetFrameAtIndex(0)
# We should be in funciton 'bar'.
self.assertTrue(frame.IsValid())
function_name = frame.GetFunctionName()
self.assertTrue('bar' in function_name)
# We should be able to evaluate the parameter foo.
value = frame.EvaluateExpression('*foo')
self.assertEqual(value.GetValueAsSigned(), 42)
# The counter should be 1 at the first stop and increase by 2 for each
# subsequent stop.
counter = 1
while counter < 20:
value = frame.EvaluateExpression('count')
self.assertEqual(value.GetValueAsSigned(), counter)
counter += 2
process.Continue()
# The inferior should exit after the last iteration.
self.assertEqual(process.GetState(), lldb.eStateExited)

View File

@ -0,0 +1,29 @@
#ifdef _MSC_VER
#include <intrin.h>
#define BREAKPOINT_INTRINSIC() __debugbreak()
#else
#define BREAKPOINT_INTRINSIC() __asm__ __volatile__ ("int3")
#endif
int
bar(int const *foo)
{
int count = 0, i = 0;
for (; i < 10; ++i)
{
count += 1;
BREAKPOINT_INTRINSIC();
count += 1;
}
return *foo;
}
int
main(int argc, char **argv)
{
int foo = 42;
bar(&foo);
return 0;
}

View File

@ -21,7 +21,6 @@ def setUp(self):
# Find the line number to break at.
self.line = line_number('main.cpp', '// break here')
@expectedFailureWindows("llvm.org/pr24462") # Data formatters have problems on Windows
def test_with_run_command(self):
"""Test that LLDB correctly cleans caches when language categories change."""
# This is the function to remove the custom formats in order to have a

View File

@ -16,6 +16,7 @@ class AssertingInferiorTestCase(TestBase):
@expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows")
@expectedFailurei386("llvm.org/pr25338")
@expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386'])
def test_inferior_asserting(self):
"""Test that lldb reliably catches the inferior asserting (command)."""
self.build()
@ -30,6 +31,7 @@ def test_inferior_asserting_register(self):
@expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows")
@expectedFailurei386("llvm.org/pr25338")
@expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386'])
def test_inferior_asserting_disassemble(self):
"""Test that lldb reliably disassembles frames after asserting (command)."""
self.build()
@ -44,6 +46,7 @@ def test_inferior_asserting_python(self):
@expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows")
@expectedFailurei386("llvm.org/pr25338")
@expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386'])
def test_inferior_asserting_expr(self):
"""Test that the lldb expression interpreter can read from the inferior after asserting (command)."""
self.build()
@ -51,6 +54,7 @@ def test_inferior_asserting_expr(self):
@expectedFailureWindows("llvm.org/pr21793: need to implement support for detecting assertion / abort on Windows")
@expectedFailurei386("llvm.org/pr25338")
@expectedFailureLinux("llvm.org/pr25338", archs=['arm', 'i386'])
def test_inferior_asserting_step(self):
"""Test that lldb functions correctly after stepping through a call to assert()."""
self.build()

View File

@ -16,7 +16,6 @@ class TestInlineStepping(TestBase):
@add_test_categories(['pyapi'])
@expectedFailureFreeBSD('llvm.org/pr17214')
@expectedFailureIcc # Not really a bug. ICC combines two inlined functions.
@expectedFailureWindows("llvm.org/pr24778")
# failed 1/365 dosep runs, (i386-clang), TestInlineStepping.py:237 failed to stop at first breakpoint in main
@expectedFailureAll(oslist=["linux"], archs=["i386"])
def test_with_python_api(self):

View File

@ -3,7 +3,7 @@
"""
from __future__ import print_function
from six import iteritems
import lldb
@ -83,8 +83,8 @@ def test_deeper_stack_in_mini_dump(self):
thread = process.GetThreadAtIndex(0)
expected_stack = { 0: 'bar', 1: 'foo', 2: 'main' }
self.assertEqual(thread.GetNumFrames(), len(expected_stack))
for index, name in expected_stack.iteritems():
self.assertGreaterEqual(thread.GetNumFrames(), len(expected_stack))
for index, name in iteritems(expected_stack):
frame = thread.GetFrameAtIndex(index)
self.assertTrue(frame.IsValid())
function_name = frame.GetFunctionName()

View File

@ -1,28 +1,11 @@
#include <stdio.h>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
#include <chrono>
#include <thread>
int main(int argc, char const *argv[]) {
int temp;
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
int prctl_result;
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
(void) prctl_result;
#endif
#endif
lldb_enable_attach();
// Waiting to be attached by the debugger.
temp = 0;

View File

@ -2,10 +2,6 @@
#include <unistd.h>
#include <sys/wait.h>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
volatile int release_child_flag = 0;
int main(int argc, char const *argv[])
@ -61,18 +57,7 @@ int main(int argc, char const *argv[])
}
else
{ // child
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
(void) prctl_result;
#endif
#endif
lldb_enable_attach();
while (! release_child_flag) // Wait for debugger to attach
sleep(1);

View File

@ -8,10 +8,6 @@
//===----------------------------------------------------------------------===//
#include <stdio.h>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
#include <chrono>
#include <thread>
@ -19,18 +15,7 @@ long double outermost_return_long_double (long double my_long_double);
int main (int argc, char const *argv[])
{
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
static_cast<void> (prctl_result);
#endif
#endif
lldb_enable_attach();
char my_string[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 0};
double my_double = 1234.5678;

View File

@ -4,10 +4,6 @@
using std::chrono::microseconds;
#if defined(__linux__)
#include <sys/prctl.h>
#endif
volatile int g_thread_2_continuing = 0;
void *
@ -42,20 +38,7 @@ thread_2_func (void *input)
int main(int argc, char const *argv[])
{
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
int prctl_result;
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
(void) prctl_result;
#endif
#endif
lldb_enable_attach();
// Create a new thread
std::thread thread_1(thread_1_func, nullptr);

View File

@ -33,9 +33,7 @@ def test(self):
# The stop reason of the thread should be breakpoint 1.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 1",
substrs = ['stopped',
'* thread #1',
'stop reason = breakpoint 1'])
substrs=['stopped', 'main.cpp:{}'.format(self.mark3), 'stop reason = breakpoint 1'])
self.do_min_test(self.mark3, self.mark1, "i", "4"); # Try the int path, force it to return 'a'
self.do_min_test(self.mark3, self.mark2, "i", "5"); # Try the int path, force it to return 'b'

View File

@ -19,7 +19,6 @@ class ThreadStateTestCase(TestBase):
@expectedFailureDarwin("rdar://15367566")
@expectedFailureFreeBSD('llvm.org/pr15824')
@expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
@expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
def test_state_after_breakpoint(self):
"""Test thread state after breakpoint."""
self.build(dictionary=self.getBuildFlags(use_cpp11=False))

View File

@ -20,7 +20,6 @@ class ThreadSpecificBreakPlusConditionTestCase(TestBase):
@skipIfFreeBSD # test frequently times out or hangs
@expectedFailureFreeBSD('llvm.org/pr18522') # hits break in another thread in testrun
@add_test_categories(['pyapi'])
@expectedFailureWindows # Thread specific breakpoints cause the inferior to crash.
@expectedFlakeyLinux # this test fails 6/100 dosep runs
def test_python(self):
"""Test that we obey thread conditioned breakpoints."""

View File

@ -14,7 +14,7 @@
class NoreturnUnwind(TestBase):
mydir = TestBase.compute_mydir(__file__)
@expectedFailurei386 #xfail to get buildbot green, failing config: i386 binary running on ubuntu 14.04 x86_64
@expectedFailurei386("llvm.org/pr25338")
@skipIfWindows # clang-cl does not support gcc style attributes.
def test (self):
"""Test that we can backtrace correctly with 'noreturn' functions on the stack"""

View File

@ -17,6 +17,7 @@ def getCategories(self):
return ['basic_process']
@expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported
@expectedFailureLinux(bugnumber="llvm.org/pr26031", archs=['arm'])
@expectedFailureWindows("llvm.org/pr24446")
def test(self):
"""Test stepping over watchpoints."""

View File

@ -27,6 +27,7 @@ def setUp(self):
# Build dictionary to have unique executable names for each test method.
@expectedFailureAndroid(archs=['arm', 'aarch64']) # Watchpoints not supported
@expectedFailureLinux(bugnumber="llvm.org/pr26031", archs=['arm'])
@expectedFailureWindows("llvm.org/pr24446") # WINDOWS XFAIL TRIAGE - Watchpoints not supported on Windows
def test_watchlocation_using_watchpoint_set(self):
"""Test watching a location with 'watchpoint set expression -w write -s size' option."""

View File

@ -0,0 +1,6 @@
LEVEL = ../../../make
OBJC_SOURCES := main.m
LDFLAGS = $(CFLAGS) -lobjc -framework Foundation
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,53 @@
"""Test that a global ObjC object found before the process is started updates correctly."""
from __future__ import print_function
import os, time
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class TestObjCGlobalVar(TestBase):
mydir = TestBase.compute_mydir(__file__)
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
self.main_source = lldb.SBFileSpec("main.m")
@skipUnlessDarwin
@add_test_categories(['pyapi'])
def test_with_python_api(self):
"""Test that a global ObjC object found before the process is started updates correctly."""
self.build()
exe = os.path.join(os.getcwd(), "a.out")
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
bkpt = target.BreakpointCreateBySourceRegex ('NSLog', self.main_source)
self.assertTrue(bkpt, VALID_BREAKPOINT)
# Before we launch, make an SBValue for our global object pointer:
g_obj_ptr = target.FindFirstGlobalVariable("g_obj_ptr")
self.assertTrue(g_obj_ptr.GetError().Success(), "Made the g_obj_ptr")
self.assertTrue(g_obj_ptr.GetValueAsUnsigned(10) == 0, "g_obj_ptr is initially null")
# Now launch the process, and do not stop at entry point.
process = target.LaunchSimple (None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
# The stop reason of the thread should be breakpoint.
threads = lldbutil.get_threads_stopped_at_breakpoint (process, bkpt)
if len(threads) != 1:
self.fail ("Failed to stop at breakpoint 1.")
thread = threads[0]
dyn_value = g_obj_ptr.GetDynamicValue(lldb.eDynamicCanRunTarget)
self.assertTrue(dyn_value.GetError().Success(), "Dynamic value is valid")
self.assertTrue(dyn_value.GetObjectDescription() == "Some NSString")

View File

@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
id g_obj_ptr = nil;
int
main()
{
g_obj_ptr = @"Some NSString";
NSLog(@"My string was %@.", g_obj_ptr);
return 0;
}

View File

@ -3,7 +3,6 @@
# System modules
import os
import sys
# Third-party modules
@ -23,6 +22,7 @@ def source_type(filename):
'.mm' : 'OBJCXX_SOURCES'
}.get(extension, None)
class CommandParser:
def __init__(self):
self.breakpoints = []
@ -116,11 +116,11 @@ def BuildMakefile(self):
if ('CXX_SOURCES' in list(categories.keys())):
makefile.write("CXXFLAGS += -std=c++11\n")
makefile.write("\ncleanup:\n\trm -f Makefile *.d\n\n")
makefile.write("include $(LEVEL)/Makefile.rules\n")
makefile.flush()
makefile.close()
@skipUnlessDarwin
def __test_with_dsym(self):
self.using_dsym = True

View File

@ -696,10 +696,11 @@ def expectedFailurei386(bugnumber=None):
def expectedFailurex86_64(bugnumber=None):
return expectedFailureArch('x86_64', bugnumber)
def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None):
def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None):
def fn(self):
return (self.getPlatform() in oslist and
self.expectedCompiler(compilers) and
(archs is None or self.getArchitecture() in archs) and
(debug_info is None or self.debug_info in debug_info))
return expectedFailure(fn, bugnumber)
@ -716,8 +717,8 @@ def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None):
def expectedFailureFreeBSD(bugnumber=None, compilers=None, debug_info=None):
return expectedFailureOS(['freebsd'], bugnumber, compilers, debug_info=debug_info)
def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None):
return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info)
def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None, archs=None):
return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info, archs=archs)
def expectedFailureNetBSD(bugnumber=None, compilers=None, debug_info=None):
return expectedFailureOS(['netbsd'], bugnumber, compilers, debug_info=debug_info)

View File

@ -17,3 +17,28 @@
// declared. This may not be necessary after MSVC 12.
#include <eh.h>
#endif
// On some systems (e.g., some versions of linux) it is not possible to attach to a process
// without it giving us special permissions. This defines the lldb_enable_attach macro, which
// should perform any such actions, if needed by the platform. This is a macro instead of a
// function to avoid the need for complex linking of the test programs.
#if defined(__linux__)
#include <sys/prctl.h>
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
// For now we execute on best effort basis. If this fails for some reason, so be it.
#define lldb_enable_attach() \
do \
{ \
const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); \
(void)prctl_result; \
} while (0)
#endif
#else // not linux
#define lldb_enable_attach()
#endif

View File

@ -21,11 +21,18 @@ class DisassembleRawDataTestCase(TestBase):
def test_disassemble_raw_data(self):
"""Test disassembling raw bytes with the API."""
# Create a target from the debugger.
arch = self.getArchitecture()
if re.match("mips*el",arch):
target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "mipsel")
raw_bytes = bytearray([0x21,0xf0, 0xa0, 0x03])
elif re.match("mips",arch):
target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "mips")
raw_bytes = bytearray([0x03,0xa0, 0xf0, 0x21])
else:
target = self.dbg.CreateTargetWithFileAndTargetTriple ("", "x86_64")
self.assertTrue(target, VALID_TARGET)
raw_bytes = bytearray([0x48, 0x89, 0xe5])
self.assertTrue(target, VALID_TARGET)
insts = target.GetInstructions(lldb.SBAddress(0, target), raw_bytes)
inst = insts.GetInstructionAtIndex(0)
@ -34,6 +41,9 @@ def test_disassemble_raw_data(self):
print()
print("Raw bytes: ", [hex(x) for x in raw_bytes])
print("Disassembled%s" % str(inst))
if re.match("mips",arch):
self.assertTrue (inst.GetMnemonic(target) == "move")
self.assertTrue (inst.GetOperands(target) == '$' + "fp, " + '$' + "sp")
else:
self.assertTrue (inst.GetMnemonic(target) == "movq")
self.assertTrue (inst.GetOperands(target) == '%' + "rsp, " + '%' + "rbp")

View File

@ -13,6 +13,7 @@
from lldbsuite.test.lldbtest import *
@skipIfDarwin # llvm.org/pr25924, sometimes generating SIGSEGV
@skipIfLinux # llvm.org/pr25924, sometimes generating SIGSEGV
class EventAPITestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@ -25,7 +26,6 @@ def setUp(self):
@add_test_categories(['pyapi'])
@expectedFailureLinux("llvm.org/pr23730") # Flaky, fails ~1/10 cases
@skipIfLinux # skip to avoid crashes
def test_listen_for_and_print_event(self):
"""Exercise SBEvent API."""
self.build()
@ -176,7 +176,7 @@ def run(self):
@skipIfFreeBSD # llvm.org/pr21325
@add_test_categories(['pyapi'])
@expectedFlakeyLinux("llvm.org/pr23617") # Flaky, fails ~1/10 cases
@expectedFailureLinux("llvm.org/pr23617") # Flaky, fails ~1/10 cases
@expectedFailureWindows("llvm.org/pr24778")
def test_add_listener_to_broadcaster(self):
"""Exercise some SBBroadcaster APIs."""

View File

@ -1,25 +1,8 @@
#include <stdio.h>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
int main(int argc, char const *argv[]) {
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor process can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
int prctl_result;
// For now we execute on best effort basis. If this fails for
// some reason, so be it.
prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
(void) prctl_result;
#endif
#endif
int main(int argc, char const *argv[])
{
lldb_enable_attach();
printf("Hello world.\n"); // Set break point at this line.
if (argc == 1)

View File

@ -16,6 +16,8 @@ class ModuleAndSectionAPIsTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
# Py3 asserts due to a bug in SWIG. A fix for this was upstreamed into SWIG 3.0.8.
@skipIf(py_version=['>=', (3,0)], swig_version=['<', (3,0,8)])
@add_test_categories(['pyapi'])
def test_module_and_section(self):
"""Test module and section APIs."""

View File

@ -28,6 +28,7 @@ def setUp(self):
@expectedFailureWindows("llvm.org/pr24772")
@add_test_categories(['pyapi'])
@expectedFlakeyLinux("llvm.org/pr25652")
def test_change_value(self):
"""Exercise the SBValue::SetValueFromCString API."""
d = {'EXE': self.exe_name}

View File

@ -25,6 +25,8 @@ def setUp(self):
# Find the line number to break at.
self.line = line_number('main.cpp', '// Break at this line')
# Py3 asserts due to a bug in SWIG. A fix for this was upstreamed into SWIG 3.0.8.
@skipIf(py_version=['>=', (3,0)], swig_version=['<', (3,0,8)])
@add_test_categories(['pyapi'])
def test(self):
"""Exercise SBValue API linked_list_iter."""

View File

@ -44,7 +44,8 @@ def unique_string_match(yourentry, list):
def is_supported_on_platform(category, platform):
if category == "dwo":
return platform in ["linux", "freebsd", "windows"]
# -gsplit-dwarf is not implemented by clang on Windows.
return platform in ["linux", "freebsd"]
elif category == "dsym":
return platform in ["darwin", "macosx", "ios"]
return True

View File

@ -20,10 +20,6 @@ int pthread_threadid_np(pthread_t,__uint64_t*);
#include <sys/syscall.h>
#endif
#if defined(__linux__)
#include <sys/prctl.h>
#endif
static const char *const RETVAL_PREFIX = "retval:";
static const char *const SLEEP_PREFIX = "sleep:";
static const char *const STDERR_PREFIX = "stderr:";
@ -210,16 +206,7 @@ thread_func (void *arg)
int main (int argc, char **argv)
{
#if defined(__linux__)
// Immediately enable any ptracer so that we can allow the stub attach
// operation to succeed. Some Linux kernels are locked down so that
// only an ancestor can be a ptracer of a process. This disables that
// restriction. Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
const int prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
static_cast<void> (prctl_result);
#endif
#endif
lldb_enable_attach();
std::vector<pthread_t> threads;
std::unique_ptr<uint8_t[]> heap_array_up;

View File

@ -26,14 +26,16 @@
}
%typemap(in) lldb::tid_t {
if (PyInt_Check($input))
$1 = PyInt_AsLong($input);
else if (PyLong_Check($input))
$1 = PyLong_AsLongLong($input);
using namespace lldb_private;
if (PythonInteger::Check($input))
{
PythonInteger py_int(PyRefType::Borrowed, $input);
$1 = static_cast<lldb::tid_t>(py_int.GetInteger());
}
else
{
PyErr_SetString(PyExc_ValueError, "Expecting an integer");
return NULL;
return nullptr;
}
}

View File

@ -550,6 +550,7 @@ class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach
result.AppendMessage(stream.GetData());
result.SetStatus (eReturnStatusSuccessFinishNoResult);
result.SetDidChangeProcessState (true);
result.SetAbnormalStopWasExpected(true);
}
else
{

View File

@ -12,7 +12,6 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include <string>

View File

@ -409,13 +409,13 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6
arch_32.SetTriple(triple);
break;
case llvm::Triple::aarch64:
case llvm::Triple::ppc64:
case llvm::Triple::x86_64:
arch_64.SetTriple(triple);
arch_32.SetTriple(triple.get32BitArchVariant());
break;
case llvm::Triple::aarch64:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::sparcv9:

View File

@ -3038,7 +3038,10 @@ CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &
for (ThreadSP thread_sp : process_sp->GetThreadList().Threads())
{
StopReason reason = thread_sp->GetStopReason();
if (reason == eStopReasonSignal || reason == eStopReasonException || reason == eStopReasonInstrumentation)
if ((reason == eStopReasonSignal
|| reason == eStopReasonException
|| reason == eStopReasonInstrumentation)
&& !result.GetAbnormalStopWasExpected())
{
should_stop = true;
break;

View File

@ -47,7 +47,8 @@ CommandReturnObject::CommandReturnObject () :
m_err_stream (),
m_status (eReturnStatusStarted),
m_did_change_process_state (false),
m_interactive (true)
m_interactive (true),
m_abnormal_stop_was_expected(false)
{
}

View File

@ -206,6 +206,7 @@ ABISysV_mips64::PrepareTrivialCall (Thread &thread,
const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0);
if (log)
log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
@ -228,6 +229,13 @@ ABISysV_mips64::PrepareTrivialCall (Thread &thread,
if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
return false;
if (log)
log->Printf("Writing r25: 0x%" PRIx64, (uint64_t)func_addr);
// All callers of position independent functions must place the address of the called function in t9 (r25)
if (!reg_ctx->WriteRegisterFromUnsigned (r25_info, func_addr))
return false;
return true;
}

View File

@ -107,6 +107,7 @@ DYLDRendezvous::DYLDRendezvous(Process *process)
m_rendezvous_addr(LLDB_INVALID_ADDRESS),
m_current(),
m_previous(),
m_loaded_modules(),
m_soentries(),
m_added_soentries(),
m_removed_soentries()
@ -181,6 +182,9 @@ DYLDRendezvous::Resolve()
m_previous = m_current;
m_current = info;
if (UpdateSOEntries (true))
return true;
return UpdateSOEntries();
}
@ -191,18 +195,23 @@ DYLDRendezvous::IsValid()
}
bool
DYLDRendezvous::UpdateSOEntries()
DYLDRendezvous::UpdateSOEntries(bool fromRemote)
{
SOEntry entry;
LoadedModuleInfoList module_list;
if (m_current.map_addr == 0)
// If we can't get the SO info from the remote, return failure.
if (fromRemote && m_process->LoadModules (module_list) == 0)
return false;
if (!fromRemote && m_current.map_addr == 0)
return false;
// When the previous and current states are consistent this is the first
// time we have been asked to update. Just take a snapshot of the currently
// loaded modules.
if (m_previous.state == eConsistent && m_current.state == eConsistent)
return TakeSnapshot(m_soentries);
return fromRemote ? SaveSOEntriesFromRemote(module_list) : TakeSnapshot(m_soentries);
// If we are about to add or remove a shared object clear out the current
// state and take a snapshot of the currently loaded images.
@ -215,6 +224,9 @@ DYLDRendezvous::UpdateSOEntries()
return false;
m_soentries.clear();
if (fromRemote)
return SaveSOEntriesFromRemote(module_list);
m_added_soentries.clear();
m_removed_soentries.clear();
return TakeSnapshot(m_soentries);
@ -224,15 +236,133 @@ DYLDRendezvous::UpdateSOEntries()
// Otherwise check the previous state to determine what to expect and update
// accordingly.
if (m_previous.state == eAdd)
return UpdateSOEntriesForAddition();
return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries();
else if (m_previous.state == eDelete)
return UpdateSOEntriesForDeletion();
return fromRemote ? RemoveSOEntriesFromRemote(module_list) : RemoveSOEntries();
return false;
}
bool
DYLDRendezvous::UpdateSOEntriesForAddition()
DYLDRendezvous::FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo,
SOEntry &entry)
{
addr_t link_map_addr;
addr_t base_addr;
addr_t dyn_addr;
std::string name;
if (!modInfo.get_link_map (link_map_addr) ||
!modInfo.get_base (base_addr) ||
!modInfo.get_dynamic (dyn_addr) ||
!modInfo.get_name (name))
return false;
entry.link_addr = link_map_addr;
entry.base_addr = base_addr;
entry.dyn_addr = dyn_addr;
entry.file_spec.SetFile(name, false);
UpdateBaseAddrIfNecessary(entry, name);
// not needed if we're using ModuleInfos
entry.next = 0;
entry.prev = 0;
entry.path_addr = 0;
return true;
}
bool
DYLDRendezvous::SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list)
{
for (auto const & modInfo : module_list.m_list)
{
SOEntry entry;
if (!FillSOEntryFromModuleInfo(modInfo, entry))
return false;
// Only add shared libraries and not the executable.
if (!SOEntryIsMainExecutable(entry))
m_soentries.push_back(entry);
}
m_loaded_modules = module_list;
return true;
}
bool
DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list)
{
for (auto const & modInfo : module_list.m_list)
{
bool found = false;
for (auto const & existing : m_loaded_modules.m_list)
{
if (modInfo == existing)
{
found = true;
break;
}
}
if (found)
continue;
SOEntry entry;
if (!FillSOEntryFromModuleInfo(modInfo, entry))
return false;
// Only add shared libraries and not the executable.
if (!SOEntryIsMainExecutable(entry))
m_soentries.push_back(entry);
}
m_loaded_modules = module_list;
return true;
}
bool
DYLDRendezvous::RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list)
{
for (auto const & existing : m_loaded_modules.m_list)
{
bool found = false;
for (auto const & modInfo : module_list.m_list)
{
if (modInfo == existing)
{
found = true;
break;
}
}
if (found)
continue;
SOEntry entry;
if (!FillSOEntryFromModuleInfo(existing, entry))
return false;
// Only add shared libraries and not the executable.
if (!SOEntryIsMainExecutable(entry))
{
auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
if (pos == m_soentries.end())
return false;
m_soentries.erase(pos);
}
}
m_loaded_modules = module_list;
return true;
}
bool
DYLDRendezvous::AddSOEntries()
{
SOEntry entry;
iterator pos;
@ -263,7 +393,7 @@ DYLDRendezvous::UpdateSOEntriesForAddition()
}
bool
DYLDRendezvous::UpdateSOEntriesForDeletion()
DYLDRendezvous::RemoveSOEntries()
{
SOEntryList entry_list;
iterator pos;
@ -291,7 +421,8 @@ DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry)
// FreeBSD and on Android it is the full path to the executable.
auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
switch (triple.getOS()) {
switch (triple.getOS())
{
case llvm::Triple::FreeBSD:
return entry.file_spec == m_exe_file_spec;
case llvm::Triple::Linux:
@ -386,6 +517,21 @@ isLoadBiasIncorrect(Target& target, const std::string& file_path)
return false;
}
void
DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path)
{
// If the load bias reported by the linker is incorrect then fetch the load address of the file
// from the proc file system.
if (isLoadBiasIncorrect(m_process->GetTarget(), file_path))
{
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
bool is_loaded = false;
Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
if (error.Success() && is_loaded)
entry.base_addr = load_addr;
}
}
bool
DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
{
@ -427,16 +573,7 @@ DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
std::string file_path = ReadStringFromMemory(entry.path_addr);
entry.file_spec.SetFile(file_path, false);
// If the load bias reported by the linker is incorrect then fetch the load address of the file
// from the proc file system.
if (isLoadBiasIncorrect(m_process->GetTarget(), file_path))
{
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
bool is_loaded = false;
Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
if (error.Success() && is_loaded)
entry.base_addr = load_addr;
}
UpdateBaseAddrIfNecessary(entry, file_path);
return true;
}

View File

@ -20,6 +20,10 @@
#include "lldb/lldb-types.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/LoadedModuleInfoList.h"
using lldb_private::LoadedModuleInfoList;
namespace lldb_private {
class Process;
}
@ -201,6 +205,9 @@ class DYLDRendezvous {
Rendezvous m_current;
Rendezvous m_previous;
/// List of currently loaded SO modules
LoadedModuleInfoList m_loaded_modules;
/// List of SOEntry objects corresponding to the current link map state.
SOEntryList m_soentries;
@ -240,13 +247,29 @@ class DYLDRendezvous {
/// Updates the current set of SOEntries, the set of added entries, and the
/// set of removed entries.
bool
UpdateSOEntries();
UpdateSOEntries(bool fromRemote = false);
bool
UpdateSOEntriesForAddition();
FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo,
SOEntry &entry);
bool
UpdateSOEntriesForDeletion();
SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list);
bool
AddSOEntriesFromRemote(LoadedModuleInfoList &module_list);
bool
RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list);
bool
AddSOEntries();
bool
RemoveSOEntries();
void
UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
bool
SOEntryIsMainExecutable(const SOEntry &entry);

View File

@ -36,6 +36,7 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
@ -570,6 +571,63 @@ FindCodeSymbolInContext
}
}
ConstString
FindBestAlternateMangledName
(
const ConstString &demangled,
const LanguageType &lang_type,
SymbolContext &sym_ctx
)
{
CPlusPlusLanguage::MethodName cpp_name(demangled);
std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
if (!scope_qualified_name.size())
return ConstString();
if (!sym_ctx.module_sp)
return ConstString();
SymbolVendor *sym_vendor = sym_ctx.module_sp->GetSymbolVendor();
if (!sym_vendor)
return ConstString();
lldb_private::SymbolFile *sym_file = sym_vendor->GetSymbolFile();
if (!sym_file)
return ConstString();
std::vector<ConstString> alternates;
sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
std::vector<ConstString> param_and_qual_matches;
std::vector<ConstString> param_matches;
for (size_t i = 0; i < alternates.size(); i++)
{
ConstString alternate_mangled_name = alternates[i];
Mangled mangled(alternate_mangled_name, true);
ConstString demangled = mangled.GetDemangledName(lang_type);
CPlusPlusLanguage::MethodName alternate_cpp_name(demangled);
if (!cpp_name.IsValid())
continue;
if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments())
{
if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
param_and_qual_matches.push_back(alternate_mangled_name);
else
param_matches.push_back(alternate_mangled_name);
}
}
if (param_and_qual_matches.size())
return param_and_qual_matches[0]; // It is assumed that there will be only one!
else if (param_matches.size())
return param_matches[0]; // Return one of them as a best match
else
return ConstString();
}
bool
ClangExpressionDeclMap::GetFunctionAddress
(
@ -603,11 +661,20 @@ ClangExpressionDeclMap::GetFunctionAddress
if (Language::LanguageIsCPlusPlus(lang_type) &&
CPlusPlusLanguage::IsCPPMangledName(name.AsCString()))
{
// 1. Demangle the name
Mangled mangled(name, true);
ConstString demangled = mangled.GetDemangledName(lang_type);
if (demangled)
{
ConstString best_alternate_mangled_name = FindBestAlternateMangledName(demangled, lang_type, sc);
if (best_alternate_mangled_name)
{
FindCodeSymbolInContext(
best_alternate_mangled_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
sc_list_size = sc_list.GetSize();
}
if (sc_list_size == 0)
{
FindCodeSymbolInContext(
demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list);
@ -616,6 +683,7 @@ ClangExpressionDeclMap::GetFunctionAddress
}
}
}
}
if (sc_list_size == 0)
{

View File

@ -36,7 +36,6 @@
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/CPPLanguageRuntime.h"
#include <map>
@ -230,36 +229,6 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun,
{
std::vector<lldb_private::ConstString> alternates;
bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
if (!found_it)
{
if (log)
log->Printf("Address of function \"%s\" not found.\n", name.GetCString());
// Check for an alternate mangling for names from the standard library.
// For example, "std::basic_string<...>" has an alternate mangling scheme per
// the Itanium C++ ABI.
lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP();
if (process_sp)
{
lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime();
if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates))
{
for (size_t i = 0; i < alternates.size(); ++i)
{
const lldb_private::ConstString &alternate_name = alternates[i];
if (log)
log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"",
name.GetCString(), alternate_name.GetCString());
if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr)))
{
if (log)
log->Printf("Found address of function \"%s\" with alternate name \"%s\"",
name.GetCString(), alternate_name.GetCString());
break;
}
}
}
}
}
if (!found_it)
{

File diff suppressed because it is too large Load Diff

View File

@ -133,122 +133,38 @@ class EmulateInstructionMIPS64 : public lldb_private::EmulateInstruction
Emulate_LDST_Reg (llvm::MCInst& insn);
bool
Emulate_BEQ (llvm::MCInst& insn);
Emulate_BXX_3ops (llvm::MCInst& insn);
bool
Emulate_BNE (llvm::MCInst& insn);
Emulate_BXX_3ops_C (llvm::MCInst& insn);
bool
Emulate_BEQL (llvm::MCInst& insn);
Emulate_BXX_2ops (llvm::MCInst& insn);
bool
Emulate_BNEL (llvm::MCInst& insn);
Emulate_BXX_2ops_C (llvm::MCInst& insn);
bool
Emulate_BGEZALL (llvm::MCInst& insn);
Emulate_Bcond_Link_C (llvm::MCInst& insn);
bool
Emulate_Bcond_Link (llvm::MCInst& insn);
bool
Emulate_FP_branch (llvm::MCInst& insn);
bool
Emulate_3D_branch (llvm::MCInst& insn);
bool
Emulate_BAL (llvm::MCInst& insn);
bool
Emulate_BGEZAL (llvm::MCInst& insn);
bool
Emulate_BALC (llvm::MCInst& insn);
bool
Emulate_BC (llvm::MCInst& insn);
bool
Emulate_BGEZ (llvm::MCInst& insn);
bool
Emulate_BLEZALC (llvm::MCInst& insn);
bool
Emulate_BGEZALC (llvm::MCInst& insn);
bool
Emulate_BLTZALC (llvm::MCInst& insn);
bool
Emulate_BGTZALC (llvm::MCInst& insn);
bool
Emulate_BEQZALC (llvm::MCInst& insn);
bool
Emulate_BNEZALC (llvm::MCInst& insn);
bool
Emulate_BEQC (llvm::MCInst& insn);
bool
Emulate_BNEC (llvm::MCInst& insn);
bool
Emulate_BLTC (llvm::MCInst& insn);
bool
Emulate_BGEC (llvm::MCInst& insn);
bool
Emulate_BLTUC (llvm::MCInst& insn);
bool
Emulate_BGEUC (llvm::MCInst& insn);
bool
Emulate_BLTZC (llvm::MCInst& insn);
bool
Emulate_BLEZC (llvm::MCInst& insn);
bool
Emulate_BGEZC (llvm::MCInst& insn);
bool
Emulate_BGTZC (llvm::MCInst& insn);
bool
Emulate_BEQZC (llvm::MCInst& insn);
bool
Emulate_BNEZC (llvm::MCInst& insn);
bool
Emulate_BGEZL (llvm::MCInst& insn);
bool
Emulate_BGTZ (llvm::MCInst& insn);
bool
Emulate_BGTZL (llvm::MCInst& insn);
bool
Emulate_BLEZ (llvm::MCInst& insn);
bool
Emulate_BLEZL (llvm::MCInst& insn);
bool
Emulate_BLTZ (llvm::MCInst& insn);
bool
Emulate_BLTZAL (llvm::MCInst& insn);
bool
Emulate_BLTZALL (llvm::MCInst& insn);
bool
Emulate_BLTZL (llvm::MCInst& insn);
bool
Emulate_BOVC (llvm::MCInst& insn);
bool
Emulate_BNVC (llvm::MCInst& insn);
bool
Emulate_J (llvm::MCInst& insn);
@ -267,36 +183,12 @@ class EmulateInstructionMIPS64 : public lldb_private::EmulateInstruction
bool
Emulate_JR (llvm::MCInst& insn);
bool
Emulate_BC1F (llvm::MCInst& insn);
bool
Emulate_BC1T (llvm::MCInst& insn);
bool
Emulate_BC1FL (llvm::MCInst& insn);
bool
Emulate_BC1TL (llvm::MCInst& insn);
bool
Emulate_BC1EQZ (llvm::MCInst& insn);
bool
Emulate_BC1NEZ (llvm::MCInst& insn);
bool
Emulate_BC1ANY2F (llvm::MCInst& insn);
bool
Emulate_BC1ANY2T (llvm::MCInst& insn);
bool
Emulate_BC1ANY4F (llvm::MCInst& insn);
bool
Emulate_BC1ANY4T (llvm::MCInst& insn);
bool
Emulate_BNZB (llvm::MCInst& insn);

View File

@ -296,6 +296,22 @@ CPlusPlusLanguage::MethodName::GetQualifiers ()
return m_qualifiers;
}
std::string
CPlusPlusLanguage::MethodName::GetScopeQualifiedName ()
{
if (!m_parsed)
Parse();
if (m_basename.empty() || m_context.empty())
return std::string();
std::string res;
res += m_context;
res += "::";
res += m_basename;
return res;
}
bool
CPlusPlusLanguage::IsCPPMangledName (const char *name)
{

View File

@ -90,6 +90,9 @@ class CPlusPlusLanguage :
return m_full;
}
std::string
GetScopeQualifiedName ();
llvm::StringRef
GetBasename ();

View File

@ -319,46 +319,6 @@ ItaniumABILanguageRuntime::IsVTableName (const char *name)
return false;
}
static std::map<ConstString, std::vector<ConstString> >&
GetAlternateManglingPrefixes()
{
static std::map<ConstString, std::vector<ConstString> > g_alternate_mangling_prefixes;
return g_alternate_mangling_prefixes;
}
size_t
ItaniumABILanguageRuntime::GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates)
{
if (!mangled)
return static_cast<size_t>(0);
alternates.clear();
const char *mangled_cstr = mangled.AsCString();
std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes();
for (std::map<ConstString, std::vector<ConstString> >::iterator it = alternate_mangling_prefixes.begin();
it != alternate_mangling_prefixes.end();
++it)
{
const char *prefix_cstr = it->first.AsCString();
if (strncmp(mangled_cstr, prefix_cstr, strlen(prefix_cstr)) == 0)
{
const std::vector<ConstString> &alternate_prefixes = it->second;
for (size_t i = 0; i < alternate_prefixes.size(); ++i)
{
std::string alternate_mangling(alternate_prefixes[i].AsCString());
alternate_mangling.append(mangled_cstr + strlen(prefix_cstr));
alternates.push_back(ConstString(alternate_mangling.c_str()));
}
return alternates.size();
}
}
return static_cast<size_t>(0);
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
@ -382,17 +342,6 @@ ItaniumABILanguageRuntime::Initialize()
PluginManager::RegisterPlugin (GetPluginNameStatic(),
"Itanium ABI for the C++ language",
CreateInstance);
// Alternate manglings for std::basic_string<...>
std::vector<ConstString> basic_string_alternates;
basic_string_alternates.push_back(ConstString("_ZNSs"));
basic_string_alternates.push_back(ConstString("_ZNKSs"));
std::map<ConstString, std::vector<ConstString> >& alternate_mangling_prefixes = GetAlternateManglingPrefixes();
alternate_mangling_prefixes[ConstString("_ZNSbIcSt17char_traits<char>St15allocator<char>E")] =
basic_string_alternates;
alternate_mangling_prefixes[ConstString("_ZNKSbIcSt17char_traits<char>St15allocator<char>E")] =
basic_string_alternates;
}
void

View File

@ -80,9 +80,6 @@ namespace lldb_private {
lldb::SearchFilterSP
CreateExceptionSearchFilter() override;
size_t
GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------

View File

@ -69,7 +69,20 @@ AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj)
if (!valobj.ResolveValue(val.GetScalar()))
return false;
ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
// Value Objects may not have a process in their ExecutionContextRef. But we need to have one
// in the ref we pass down to eventually call description. Get it from the target if it isn't
// present.
ExecutionContext exe_ctx;
if (valobj.GetProcessSP())
{
exe_ctx = ExecutionContext(valobj.GetExecutionContextRef());
}
else
{
exe_ctx.SetContext(valobj.GetTargetSP(), true);
if (!exe_ctx.HasProcessScope())
return false;
}
return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope());
}

View File

@ -405,10 +405,19 @@ AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
Address &address,
Value::ValueType &value_type)
{
// The Runtime is attached to a particular process, you shouldn't pass in a value from another process.
assert (in_value.GetProcessSP().get() == m_process);
// We should never get here with a null process...
assert (m_process != NULL);
// The Runtime is attached to a particular process, you shouldn't pass in a value from another process.
// Note, however, the process might be NULL (e.g. if the value was made with SBTarget::EvaluateExpression...)
// in which case it is sufficient if the target's match:
Process *process = in_value.GetProcessSP().get();
if (process)
assert (process == m_process);
else
assert (in_value.GetTargetSP().get() == m_process->CalculateTarget().get());
class_type_or_name.Clear();
value_type = Value::ValueType::eValueTypeScalar;

View File

@ -235,16 +235,28 @@ struct RenderScriptRuntime::AllocationDetails
}
};
// Header for reading and writing allocation contents
// to a binary file.
// The FileHeader struct specifies the header we use for writing allocations to a binary file.
// Our format begins with the ASCII characters "RSAD", identifying the file as an allocation dump.
// Member variables dims and hdr_size are then written consecutively, immediately followed by an instance of
// the ElementHeader struct. Because Elements can contain subelements, there may be more than one instance
// of the ElementHeader struct. With this first instance being the root element, and the other instances being
// the root's descendants. To identify which instances are an ElementHeader's children, each struct
// is immediately followed by a sequence of consecutive offsets to the start of its child structs.
// These offsets are 4 bytes in size, and the 0 offset signifies no more children.
struct FileHeader
{
uint8_t ident[4]; // ASCII 'RSAD' identifying the file
uint16_t hdr_size; // Header size in bytes, for backwards compatability
uint32_t dims[3]; // Dimensions
uint16_t hdr_size; // Header size in bytes, including all element headers
};
struct ElementHeader
{
uint16_t type; // DataType enum
uint32_t kind; // DataKind enum
uint32_t dims[3]; // Dimensions
uint32_t element_size; // Size of a single element, including padding
uint16_t vector_size; // Vector width
uint32_t array_size; // Number of elements in array
};
// Monotonically increasing from 1
@ -286,7 +298,6 @@ struct RenderScriptRuntime::AllocationDetails
}
};
const ConstString &
RenderScriptRuntime::Element::GetFallbackStructName()
{
@ -2084,37 +2095,62 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const
// Cast start of buffer to FileHeader and use pointer to read metadata
void* file_buffer = data_sp->GetBytes();
const AllocationDetails::FileHeader* head = static_cast<AllocationDetails::FileHeader*>(file_buffer);
if (file_buffer == NULL || data_sp->GetByteSize() <
(sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader)))
{
strm.Printf("Error: File %s does not contain enough data for header", filename);
strm.EOL();
return false;
}
const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer);
// Advance buffer past header
file_buffer = static_cast<uint8_t*>(file_buffer) + head->hdr_size;
// Check file starts with ascii characters "RSAD"
if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A'
|| file_header->ident[3] != 'D')
{
strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?");
strm.EOL();
return false;
}
// Look at the type of the root element in the header
AllocationDetails::ElementHeader root_element_header;
memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader),
sizeof(AllocationDetails::ElementHeader));
if (log)
log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u",
head->type, head->element_size);
root_element_header.type, root_element_header.element_size);
// Check if the target allocation and file both have the same number of bytes for an Element
if (*alloc->element.datum_size.get() != head->element_size)
if (*alloc->element.datum_size.get() != root_element_header.element_size)
{
strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes",
head->element_size, *alloc->element.datum_size.get());
root_element_header.element_size, *alloc->element.datum_size.get());
strm.EOL();
}
// Check if the target allocation and file both have the same integral type
const unsigned int type = static_cast<unsigned int>(*alloc->element.type.get());
if (type != head->type)
// Check if the target allocation and file both have the same type
const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get());
const unsigned int file_type = root_element_header.type;
if (file_type > Element::RS_TYPE_FONT)
{
strm.Printf("Warning: File has unknown allocation type");
strm.EOL();
}
else if (alloc_type != file_type)
{
// Enum value isn't monotonous, so doesn't always index RsDataTypeToString array
unsigned int printable_target_type_index = type;
unsigned int printable_head_type_index = head->type;
if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
unsigned int printable_target_type_index = alloc_type;
unsigned int printable_head_type_index = file_type;
if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT)
printable_target_type_index = static_cast<Element::DataType>(
(type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
(alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
if (head->type >= Element::RS_TYPE_ELEMENT && head->type <= Element::RS_TYPE_FONT)
if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT)
printable_head_type_index = static_cast<Element::DataType>(
(head->type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
(file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
@ -2124,8 +2160,11 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const
strm.EOL();
}
// Advance buffer past header
file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size;
// Calculate size of allocation data in file
size_t length = data_sp->GetByteSize() - head->hdr_size;
size_t length = data_sp->GetByteSize() - file_header->hdr_size;
// Check if the target allocation and file both have the same total data size.
const unsigned int alloc_size = *alloc->size.get();
@ -2154,6 +2193,62 @@ RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const
return true;
}
// Function takes as parameters a byte buffer, which will eventually be written to file as the element header,
// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset.
// Return value is the new offset after writing the element into the buffer.
// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children.
size_t
RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem)
{
// File struct for an element header with all the relevant details copied from elem.
// We assume members are valid already.
AllocationDetails::ElementHeader elem_header;
elem_header.type = *elem.type.get();
elem_header.kind = *elem.type_kind.get();
elem_header.element_size = *elem.datum_size.get();
elem_header.vector_size = *elem.type_vec_size.get();
elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0;
const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
// Copy struct into buffer and advance offset
// We assume that header_buffer has been checked for NULL before this method is called
memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
offset += elem_header_size;
// Starting offset of child ElementHeader struct
size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t));
for (const RenderScriptRuntime::Element& child : elem.children)
{
// Recursively populate the buffer with the element header structs of children.
// Then save the offsets where they were set after the parent element header.
memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
offset += sizeof(uint32_t);
child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
}
// Zero indicates no more children
memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
return child_offset;
}
// Given an Element object this function returns the total size needed in the file header to store the element's details.
// Taking into account the size of the element header struct, plus the offsets to all the element's children.
// Function is recursive so that the size of all ancestors is taken into account.
size_t
RenderScriptRuntime::CalculateElementHeaderSize(const Element& elem)
{
size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator
size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details
// Calculate recursively for all descendants
for (const Element& child : elem.children)
size += CalculateElementHeaderSize(child);
return size;
}
// Function copies allocation contents into a binary file.
// This file can then be loaded later into a different allocation.
// There is a header, FileHeader, before the allocation data containing meta-data.
@ -2209,17 +2304,44 @@ RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const
// Create the file header
AllocationDetails::FileHeader head;
head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D';
head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader));
head.type = static_cast<uint16_t>(*alloc->element.type.get());
head.kind = static_cast<uint32_t>(*alloc->element.type_kind.get());
head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
head.element_size = static_cast<uint32_t>(*alloc->element.datum_size.get());
const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large");
head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size);
// Write the file header
size_t num_bytes = sizeof(AllocationDetails::FileHeader);
Error err = file.Write(static_cast<const void*>(&head), num_bytes);
if (log)
log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes);
Error err = file.Write(&head, num_bytes);
if (!err.Success())
{
strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
strm.EOL();
return false;
}
// Create the headers describing the element type of the allocation.
std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]);
if (element_header_buffer == nullptr)
{
strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size);
strm.EOL();
return false;
}
PopulateElementHeaders(element_header_buffer, 0, alloc->element);
// Write headers for allocation element type to file
num_bytes = element_header_size;
if (log)
log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes);
err = file.Write(element_header_buffer.get(), num_bytes);
if (!err.Success())
{
strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
@ -2230,7 +2352,7 @@ RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const
// Write allocation data to file
num_bytes = static_cast<size_t>(*alloc->size.get());
if (log)
log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%" PRIx64 " bytes from %p", (uint64_t) num_bytes, (void*) buffer.get());
log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes);
err = file.Write(buffer.get(), num_bytes);
if (!err.Success())

View File

@ -207,10 +207,6 @@ class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime
void Status(Stream &strm) const;
size_t GetAlternateManglings(const ConstString &mangled, std::vector<ConstString> &alternates) override {
return static_cast<size_t>(0);
}
void ModulesDidLoad(const ModuleList &module_list) override;
bool LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr);
@ -335,6 +331,9 @@ class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime
static bool GetFrameVarAsUnsigned(const lldb::StackFrameSP, const char* var_name, uint64_t& val);
void FindStructTypeName(Element& elem, StackFrame* frame_ptr);
size_t PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem);
size_t CalculateElementHeaderSize(const Element& elem);
//
// Helper functions for jitting the runtime
//

View File

@ -330,15 +330,15 @@ mipsVariantFromElfFlags(const elf::elf_word e_flags, uint32_t endian)
{
case llvm::ELF::EF_MIPS_ARCH_1:
case llvm::ELF::EF_MIPS_ARCH_2:
case llvm::ELF::EF_MIPS_ARCH_3:
case llvm::ELF::EF_MIPS_ARCH_4:
case llvm::ELF::EF_MIPS_ARCH_5:
case llvm::ELF::EF_MIPS_ARCH_32:
return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32el : ArchSpec::eMIPSSubType_mips32;
case llvm::ELF::EF_MIPS_ARCH_32R2:
return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r2el : ArchSpec::eMIPSSubType_mips32r2;
case llvm::ELF::EF_MIPS_ARCH_32R6:
return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips32r6el : ArchSpec::eMIPSSubType_mips32r6;
case llvm::ELF::EF_MIPS_ARCH_3:
case llvm::ELF::EF_MIPS_ARCH_4:
case llvm::ELF::EF_MIPS_ARCH_5:
case llvm::ELF::EF_MIPS_ARCH_64:
return (endian == ELFDATA2LSB) ? ArchSpec::eMIPSSubType_mips64el : ArchSpec::eMIPSSubType_mips64;
case llvm::ELF::EF_MIPS_ARCH_64R2:
@ -954,9 +954,6 @@ ObjectFileELF::GetAddressByteSize() const
return m_data.GetAddressByteSize();
}
// Top 16 bits of the `Symbol` flags are available.
#define ARM_ELF_SYM_IS_THUMB (1 << 16)
AddressClass
ObjectFileELF::GetAddressClass (addr_t file_addr)
{
@ -2190,7 +2187,6 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
// symbol.st_value to produce the final symbol_value
// that we store in the symtab.
symbol_value_offset = -1;
additional_flags = ARM_ELF_SYM_IS_THUMB;
m_address_class_map[symbol.st_value^1] = eAddressClassCodeAlternateISA;
}
else

View File

@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#if defined(__arm__)
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
#include "NativeRegisterContextLinux_arm.h"
@ -16,8 +16,12 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/RegisterValue.h"
#include "Plugins/Process/Linux/Procfs.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
#include <elf.h>
#include <sys/socket.h>
#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
#ifndef PTRACE_GETVFPREGS
@ -169,6 +173,8 @@ g_reg_sets_arm[k_num_register_sets] =
{ "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm }
};
#if defined(__arm__)
NativeRegisterContextLinux*
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch,
NativeThreadProtocol &native_thread,
@ -177,6 +183,8 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec&
return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
}
#endif // defined(__arm__)
NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch,
NativeThreadProtocol &native_thread,
uint32_t concrete_frame_idx) :
@ -919,14 +927,14 @@ NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_inde
ctrl_buf = &m_hwp_regs[hwb_index].control;
error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 1),
m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 1),
addr_buf, sizeof(unsigned int));
if (error.Fail())
return error;
error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
m_thread.GetID(), (PTRACE_TYPE_ARG3) -((hwb_index << 1) + 2),
m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) -((hwb_index << 1) + 2),
ctrl_buf, sizeof(unsigned int));
}
else
@ -935,14 +943,14 @@ NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, int hwb_inde
ctrl_buf = &m_hwp_regs[hwb_index].control;
error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 1),
m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 1),
addr_buf, sizeof(unsigned int));
if (error.Fail())
return error;
error = NativeProcessLinux::PtraceWrapper(PTRACE_SETHBPREGS,
m_thread.GetID(), (PTRACE_TYPE_ARG3) ((hwb_index << 1) + 2),
m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t) ((hwb_index << 1) + 2),
ctrl_buf, sizeof(unsigned int));
}
@ -956,12 +964,34 @@ NativeRegisterContextLinux_arm::CalculateFprOffset(const RegisterInfo* reg_info)
return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset;
}
Error
NativeRegisterContextLinux_arm::DoReadRegisterValue(uint32_t offset,
const char* reg_name,
uint32_t size,
RegisterValue &value)
{
// PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android devices (always return
// "Bad address"). To avoid using PTRACE_PEEKUSER we read out the full GPR register set instead.
// This approach is about 4 times slower but the performance overhead is negligible in
// comparision to processing time in lldb-server.
assert(offset % 4 == 0 && "Try to write a register with unaligned offset");
if (offset + sizeof(uint32_t) > sizeof(m_gpr_arm))
return Error("Register isn't fit into the size of the GPR area");
Error error = DoReadGPR(m_gpr_arm, sizeof(m_gpr_arm));
if (error.Fail())
return error;
value.SetUInt32(m_gpr_arm[offset / sizeof(uint32_t)]);
return Error();
}
Error
NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
const char* reg_name,
const RegisterValue &value)
{
// PTRACE_POKEUSER don't work in the aarch64 liux kernel used on android devices (always return
// PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android devices (always return
// "Bad address"). To avoid using PTRACE_POKEUSER we read out the full GPR register set, modify
// the requested register and write it back. This approach is about 4 times slower but the
// performance overhead is negligible in comparision to processing time in lldb-server.
@ -994,24 +1024,68 @@ NativeRegisterContextLinux_arm::DoWriteRegisterValue(uint32_t offset,
return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm));
}
Error
NativeRegisterContextLinux_arm::DoReadGPR(void *buf, size_t buf_size)
{
#ifdef __arm__
return NativeRegisterContextLinux::DoReadGPR(buf, buf_size);
#else // __aarch64__
struct iovec ioVec;
ioVec.iov_base = buf;
ioVec.iov_len = buf_size;
return ReadRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
#endif // __arm__
}
Error
NativeRegisterContextLinux_arm::DoWriteGPR(void *buf, size_t buf_size)
{
#ifdef __arm__
return NativeRegisterContextLinux::DoWriteGPR(buf, buf_size);
#else // __aarch64__
struct iovec ioVec;
ioVec.iov_base = buf;
ioVec.iov_len = buf_size;
return WriteRegisterSet(&ioVec, buf_size, NT_PRSTATUS);
#endif // __arm__
}
Error
NativeRegisterContextLinux_arm::DoReadFPR(void *buf, size_t buf_size)
{
#ifdef __arm__
return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS,
m_thread.GetID(),
nullptr,
buf,
buf_size);
#else // __aarch64__
struct iovec ioVec;
ioVec.iov_base = buf;
ioVec.iov_len = buf_size;
return ReadRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
#endif // __arm__
}
Error
NativeRegisterContextLinux_arm::DoWriteFPR(void *buf, size_t buf_size)
{
#ifdef __arm__
return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS,
m_thread.GetID(),
nullptr,
buf,
buf_size);
#else // __aarch64__
struct iovec ioVec;
ioVec.iov_base = buf;
ioVec.iov_len = buf_size;
return WriteRegisterSet(&ioVec, buf_size, NT_ARM_VFP);
#endif // __arm__
}
#endif // defined(__arm__)
#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)

View File

@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#if defined(__arm__) // arm register context only needed on arm devices
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
#ifndef lldb_NativeRegisterContextLinux_arm_h
#define lldb_NativeRegisterContextLinux_arm_h
@ -90,11 +90,23 @@ namespace process_linux {
};
protected:
Error
DoReadRegisterValue(uint32_t offset,
const char* reg_name,
uint32_t size,
RegisterValue &value) override;
Error
DoWriteRegisterValue(uint32_t offset,
const char* reg_name,
const RegisterValue &value) override;
Error
DoReadGPR(void *buf, size_t buf_size) override;
Error
DoWriteGPR(void *buf, size_t buf_size) override;
Error
DoReadFPR(void *buf, size_t buf_size) override;
@ -182,4 +194,4 @@ namespace process_linux {
#endif // #ifndef lldb_NativeRegisterContextLinux_arm_h
#endif // defined(__arm__)
#endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)

View File

@ -9,6 +9,7 @@
#if defined (__arm64__) || defined (__aarch64__)
#include "NativeRegisterContextLinux_arm.h"
#include "NativeRegisterContextLinux_arm64.h"
// C Includes
@ -23,6 +24,7 @@
#include "Plugins/Process/Linux/NativeProcessLinux.h"
#include "Plugins/Process/Linux/Procfs.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
// System includes - They have to be included after framework includes because they define some
@ -142,7 +144,19 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec&
NativeThreadProtocol &native_thread,
uint32_t concrete_frame_idx)
{
Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS);
switch (target_arch.GetMachine())
{
case llvm::Triple::arm:
return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx);
case llvm::Triple::aarch64:
return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx);
default:
if (log)
log->Printf("NativeRegisterContextLinux::%s() have no register context for architecture: %s\n", __FUNCTION__,
target_arch.GetTriple().getArchName().str().c_str());
return nullptr;
}
}
NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch,

View File

@ -1388,7 +1388,15 @@ NativeRegisterContextLinux_mips64::DoReadRegisterValue(uint32_t offset,
{
lldb_private::ArchSpec arch;
if (m_thread.GetProcess()->GetArchitecture(arch))
value.SetBytes((void *)(((unsigned char *)&regs) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips)), arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8, arch.GetByteOrder());
{
void* target_address = ((uint8_t*)&regs) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips);
uint32_t target_size;
if ((::strcmp(reg_name, "sr") == 0) || (::strcmp(reg_name, "cause") == 0) || (::strcmp(reg_name, "config5") == 0))
target_size = 4;
else
target_size = arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8;
value.SetBytes(target_address, target_size, arch.GetByteOrder());
}
else
error.SetErrorString("failed to get architecture");
}

View File

@ -72,6 +72,7 @@ lldb_private::InferiorCallMmap (Process *process,
options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
options.SetTrapExceptions(false);
addr_t prot_arg, flags_arg = 0;
if (prot == eMmapProtNone)
@ -172,6 +173,7 @@ lldb_private::InferiorCallMunmap (Process *process,
options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
options.SetTrapExceptions(false);
AddressRange munmap_range;
if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
@ -214,7 +216,8 @@ lldb_private::InferiorCallMunmap (Process *process,
bool
lldb_private::InferiorCall (Process *process,
const Address *address,
addr_t &returned_func)
addr_t &returned_func,
bool trap_exceptions)
{
Thread *thread = process->GetThreadList().GetSelectedThread().get();
if (thread == NULL || address == NULL)
@ -227,6 +230,7 @@ lldb_private::InferiorCall (Process *process,
options.SetTryAllThreads(true);
options.SetDebug (false);
options.SetTimeoutUsec(500000);
options.SetTrapExceptions(trap_exceptions);
ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();

View File

@ -31,7 +31,8 @@ bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func,
bool trap_exceptions = false);
} // namespace lldb_private

View File

@ -265,10 +265,33 @@ RegisterContextLLDB::InitializeZerothFrame()
if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
{
UnwindLogMsg ("could not read CFA register for this frame.");
// Try the fall back unwind plan since the
// full unwind plan failed.
FuncUnwindersSP func_unwinders_sp;
UnwindPlanSP call_site_unwind_plan;
bool cfa_status = false;
if (m_sym_ctx_valid)
{
func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
}
if(func_unwinders_sp.get() != nullptr)
call_site_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(process->GetTarget(), m_current_offset_backed_up_one);
if (call_site_unwind_plan.get() != nullptr)
{
m_fallback_unwind_plan_sp = call_site_unwind_plan;
if(TryFallbackUnwindPlan())
cfa_status = true;
}
if (!cfa_status)
{
UnwindLogMsg ("could not read CFA value for first frame.");
m_frame_type = eNotAValidFrame;
return;
}
}
UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
(uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),

View File

@ -550,14 +550,26 @@ ProcessWindowsLive::RefreshStateAfterStop()
if (!stop_thread)
return;
switch (active_exception->GetExceptionCode())
{
case EXCEPTION_SINGLE_STEP:
{
stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
stop_thread->SetStopInfo(stop_info);
WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u",
stop_thread->GetID());
stop_thread->SetStopInfo(stop_info);
return;
}
case EXCEPTION_BREAKPOINT:
{
RegisterContextSP register_context = stop_thread->GetRegisterContext();
// The current EIP is AFTER the BP opcode, which is one byte.
uint64_t pc = register_context->GetPC() - 1;
if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT)
{
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
if (site)
{
WINLOG_IFANY(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
@ -581,25 +593,31 @@ ProcessWindowsLive::RefreshStateAfterStop()
"Breakpoint site %d is not valid for this thread, creating empty stop info.",
site->GetID());
}
}
stop_thread->SetStopInfo(stop_info);
}
else if (active_exception->GetExceptionCode() == EXCEPTION_SINGLE_STEP)
{
stop_info = StopInfo::CreateStopReasonToTrace(*stop_thread);
stop_thread->SetStopInfo(stop_info);
WINLOG_IFANY(WINDOWS_LOG_EXCEPTION | WINDOWS_LOG_STEP, "RefreshStateAfterStop single stepping thread %u",
stop_thread->GetID());
return;
}
else
{
// The thread hit a hard-coded breakpoint like an `int 3` or `__debugbreak()`.
WINLOG_IFALL(WINDOWS_LOG_BREAKPOINTS | WINDOWS_LOG_EXCEPTION,
"No breakpoint site matches for this thread. __debugbreak()? "
"Creating stop info with the exception.");
// FALLTHROUGH: We'll treat this as a generic exception record in the default case.
}
}
default:
{
std::string desc;
llvm::raw_string_ostream desc_stream(desc);
desc_stream << "Exception " << llvm::format_hex(active_exception->GetExceptionCode(), 8)
<< " encountered at address " << llvm::format_hex(pc, 8);
<< " encountered at address "
<< llvm::format_hex(active_exception->GetExceptionAddress(), 8);
stop_info = StopInfo::CreateStopReasonWithException(*stop_thread, desc_stream.str().c_str());
stop_thread->SetStopInfo(stop_info);
WINLOG_IFALL(WINDOWS_LOG_EXCEPTION, desc_stream.str().c_str());
return;
}
}
}

View File

@ -101,6 +101,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() :
m_supports_QEnvironment (true),
m_supports_QEnvironmentHexEncoded (true),
m_supports_qSymbol (true),
m_qSymbol_requests_done (false),
m_supports_qModuleInfo (true),
m_supports_jThreadsInfo (true),
m_curr_pid (LLDB_INVALID_PROCESS_ID),
m_curr_tid (LLDB_INVALID_THREAD_ID),
@ -376,6 +378,8 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec)
m_supports_QEnvironment = true;
m_supports_QEnvironmentHexEncoded = true;
m_supports_qSymbol = true;
m_qSymbol_requests_done = false;
m_supports_qModuleInfo = true;
m_host_arch.Clear();
m_os_version_major = UINT32_MAX;
m_os_version_minor = UINT32_MAX;
@ -4284,6 +4288,9 @@ GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec,
const lldb_private::ArchSpec& arch_spec,
ModuleSpec &module_spec)
{
if (!m_supports_qModuleInfo)
return false;
std::string module_path = module_file_spec.GetPath (false);
if (module_path.empty ())
return false;
@ -4299,9 +4306,15 @@ GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec,
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success)
return false;
if (response.IsErrorResponse () || response.IsUnsupportedResponse ())
if (response.IsErrorResponse ())
return false;
if (response.IsUnsupportedResponse ())
{
m_supports_qModuleInfo = false;
return false;
}
std::string name;
std::string value;
bool success;
@ -4432,11 +4445,42 @@ GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString ob
// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded).
// LLDB may provide the value by sending another qSymbol packet
// in the form of"qSymbol:<sym_value>:<sym_name>".
//
// Three examples:
//
// lldb sends: qSymbol::
// lldb receives: OK
// Remote gdb stub does not need to know the addresses of any symbols, lldb does not
// need to ask again in this session.
//
// lldb sends: qSymbol::
// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473
// lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473
// lldb receives: OK
// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does not know
// the address at this time. lldb needs to send qSymbol:: again when it has more
// solibs loaded.
//
// lldb sends: qSymbol::
// lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473
// lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473
// lldb receives: OK
// Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says that it
// is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it does not
// need any more symbols. lldb does not need to ask again in this session.
void
GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process)
{
if (m_supports_qSymbol)
// Set to true once we've resolved a symbol to an address for the remote stub.
// If we get an 'OK' response after this, the remote stub doesn't need any more
// symbols and we can stop asking.
bool symbol_response_provided = false;
// Is this the inital qSymbol:: packet?
bool first_qsymbol_query = true;
if (m_supports_qSymbol && m_qSymbol_requests_done == false)
{
Mutex::Locker locker;
if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex"))
@ -4448,9 +4492,15 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process)
{
if (response.IsOKResponse())
{
if (symbol_response_provided || first_qsymbol_query)
{
m_qSymbol_requests_done = true;
}
// We are done serving symbols requests
return;
}
first_qsymbol_query = false;
if (response.IsUnsupportedResponse())
{
@ -4530,7 +4580,14 @@ GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process)
packet.Clear();
packet.PutCString("qSymbol:");
if (symbol_load_addr != LLDB_INVALID_ADDRESS)
{
packet.Printf("%" PRIx64, symbol_load_addr);
symbol_response_provided = true;
}
else
{
symbol_response_provided = false;
}
packet.PutCString(":");
packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size());
continue; // go back to the while loop and send "packet" and wait for another response

View File

@ -619,6 +619,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteCommunication
m_supports_QEnvironment:1,
m_supports_QEnvironmentHexEncoded:1,
m_supports_qSymbol:1,
m_qSymbol_requests_done:1,
m_supports_qModuleInfo:1,
m_supports_jThreadsInfo:1;
lldb::pid_t m_curr_pid;

View File

@ -173,118 +173,6 @@ namespace {
} // anonymous namespace end
class ProcessGDBRemote::GDBLoadedModuleInfoList
{
public:
class LoadedModuleInfo
{
public:
enum e_data_point
{
e_has_name = 0,
e_has_base ,
e_has_dynamic ,
e_has_link_map ,
e_num
};
LoadedModuleInfo ()
{
for (uint32_t i = 0; i < e_num; ++i)
m_has[i] = false;
}
void set_name (const std::string & name)
{
m_name = name;
m_has[e_has_name] = true;
}
bool get_name (std::string & out) const
{
out = m_name;
return m_has[e_has_name];
}
void set_base (const lldb::addr_t base)
{
m_base = base;
m_has[e_has_base] = true;
}
bool get_base (lldb::addr_t & out) const
{
out = m_base;
return m_has[e_has_base];
}
void set_base_is_offset (bool is_offset)
{
m_base_is_offset = is_offset;
}
bool get_base_is_offset(bool & out) const
{
out = m_base_is_offset;
return m_has[e_has_base];
}
void set_link_map (const lldb::addr_t addr)
{
m_link_map = addr;
m_has[e_has_link_map] = true;
}
bool get_link_map (lldb::addr_t & out) const
{
out = m_link_map;
return m_has[e_has_link_map];
}
void set_dynamic (const lldb::addr_t addr)
{
m_dynamic = addr;
m_has[e_has_dynamic] = true;
}
bool get_dynamic (lldb::addr_t & out) const
{
out = m_dynamic;
return m_has[e_has_dynamic];
}
bool has_info (e_data_point datum)
{
assert (datum < e_num);
return m_has[datum];
}
protected:
bool m_has[e_num];
std::string m_name;
lldb::addr_t m_link_map;
lldb::addr_t m_base;
bool m_base_is_offset;
lldb::addr_t m_dynamic;
};
GDBLoadedModuleInfoList ()
: m_list ()
, m_link_map (LLDB_INVALID_ADDRESS)
{}
void add (const LoadedModuleInfo & mod)
{
m_list.push_back (mod);
}
void clear ()
{
m_list.clear ();
}
std::vector<LoadedModuleInfo> m_list;
lldb::addr_t m_link_map;
};
// TODO Randomly assigning a port is unsafe. We should get an unused
// ephemeral port from the kernel and make sure we reserve it before passing
// it to debugserver.
@ -2034,6 +1922,8 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
const std::vector<addr_t> &exc_data,
addr_t thread_dispatch_qaddr,
bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid
LazyBool associated_with_dispatch_queue,
addr_t dispatch_queue_t,
std::string &queue_name,
QueueKind queue_kind,
uint64_t queue_serial)
@ -2074,10 +1964,15 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
// Check if the GDB server was able to provide the queue name, kind and serial number
if (queue_vars_valid)
gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial);
gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, dispatch_queue_t, associated_with_dispatch_queue);
else
gdb_thread->ClearQueueInfo();
gdb_thread->SetAssociatedWithLibdispatchQueue (associated_with_dispatch_queue);
if (dispatch_queue_t != LLDB_INVALID_ADDRESS)
gdb_thread->SetQueueLibdispatchQueueAddress (dispatch_queue_t);
// Make sure we update our thread stop reason just once
if (!thread_sp->StopInfoIsUpToDate())
{
@ -2248,9 +2143,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
static ConstString g_key_metype("metype");
static ConstString g_key_medata("medata");
static ConstString g_key_qaddr("qaddr");
static ConstString g_key_dispatch_queue_t("dispatch_queue_t");
static ConstString g_key_associated_with_dispatch_queue("associated_with_dispatch_queue");
static ConstString g_key_queue_name("qname");
static ConstString g_key_queue_kind("qkind");
static ConstString g_key_queue_serial("qserial");
static ConstString g_key_queue_serial_number("qserialnum");
static ConstString g_key_registers("registers");
static ConstString g_key_memory("memory");
static ConstString g_key_address("address");
@ -2270,9 +2167,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
ExpeditedRegisterMap expedited_register_map;
bool queue_vars_valid = false;
addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS;
LazyBool associated_with_dispatch_queue = eLazyBoolCalculate;
std::string queue_name;
QueueKind queue_kind = eQueueKindUnknown;
uint64_t queue_serial = 0;
uint64_t queue_serial_number = 0;
// Iterate through all of the thread dictionary key/value pairs from the structured data dictionary
thread_dict->ForEach([this,
@ -2286,9 +2185,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
&exc_data,
&thread_dispatch_qaddr,
&queue_vars_valid,
&associated_with_dispatch_queue,
&dispatch_queue_t,
&queue_name,
&queue_kind,
&queue_serial]
&queue_serial_number]
(ConstString key, StructuredData::Object* object) -> bool
{
if (key == g_key_tid)
@ -2340,12 +2241,27 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
queue_kind = eQueueKindConcurrent;
}
}
else if (key == g_key_queue_serial)
else if (key == g_key_queue_serial_number)
{
queue_serial = object->GetIntegerValue(0);
if (queue_serial != 0)
queue_serial_number = object->GetIntegerValue(0);
if (queue_serial_number != 0)
queue_vars_valid = true;
}
else if (key == g_key_dispatch_queue_t)
{
dispatch_queue_t = object->GetIntegerValue(0);
if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS)
queue_vars_valid = true;
}
else if (key == g_key_associated_with_dispatch_queue)
{
queue_vars_valid = true;
bool associated = object->GetBooleanValue ();
if (associated)
associated_with_dispatch_queue = eLazyBoolYes;
else
associated_with_dispatch_queue = eLazyBoolNo;
}
else if (key == g_key_reason)
{
reason = object->GetStringValue();
@ -2416,9 +2332,11 @@ ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
exc_data,
thread_dispatch_qaddr,
queue_vars_valid,
associated_with_dispatch_queue,
dispatch_queue_t,
queue_name,
queue_kind,
queue_serial);
queue_serial_number);
}
StateType
@ -2461,9 +2379,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
std::vector<addr_t> exc_data;
addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid
addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS;
LazyBool associated_with_dispatch_queue = eLazyBoolCalculate;
std::string queue_name;
QueueKind queue_kind = eQueueKindUnknown;
uint64_t queue_serial = 0;
uint64_t queue_serial_number = 0;
ExpeditedRegisterMap expedited_register_map;
while (stop_packet.GetNameColonValue(key, value))
{
@ -2554,6 +2474,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
{
thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16);
}
else if (key.compare("dispatch_queue_t") == 0)
{
queue_vars_valid = true;
dispatch_queue_t = StringConvert::ToUInt64 (value.c_str(), 0, 16);
}
else if (key.compare("qname") == 0)
{
queue_vars_valid = true;
@ -2577,10 +2502,10 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
queue_kind = eQueueKindConcurrent;
}
}
else if (key.compare("qserial") == 0)
else if (key.compare("qserialnum") == 0)
{
queue_serial = StringConvert::ToUInt64 (value.c_str(), 0, 0);
if (queue_serial != 0)
queue_serial_number = StringConvert::ToUInt64 (value.c_str(), 0, 0);
if (queue_serial_number != 0)
queue_vars_valid = true;
}
else if (key.compare("reason") == 0)
@ -2678,9 +2603,11 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
exc_data,
thread_dispatch_qaddr,
queue_vars_valid,
associated_with_dispatch_queue,
dispatch_queue_t,
queue_name,
queue_kind,
queue_serial);
queue_serial_number);
return eStateStopped;
}
@ -3051,7 +2978,7 @@ ProcessGDBRemote::GetImageInfoAddress()
// the loaded module list can also provides a link map address
if (addr == LLDB_INVALID_ADDRESS)
{
GDBLoadedModuleInfoList list;
LoadedModuleInfoList list;
if (GetLoadedModuleList (list).Success())
addr = list.m_link_map;
}
@ -4703,7 +4630,7 @@ ProcessGDBRemote::GetGDBServerRegisterInfo ()
}
Error
ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list)
{
// Make sure LLDB has an XML parser it can use first
if (!XMLDocument::XMLEnabled())
@ -4747,7 +4674,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
GDBLoadedModuleInfoList::LoadedModuleInfo module;
LoadedModuleInfoList::LoadedModuleInfo module;
library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
@ -4817,7 +4744,7 @@ ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
return Error();
root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
GDBLoadedModuleInfoList::LoadedModuleInfo module;
LoadedModuleInfoList::LoadedModuleInfo module;
llvm::StringRef name = library.GetAttributeValue("name");
module.set_name(name.str());
@ -4879,19 +4806,18 @@ ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_a
}
size_t
ProcessGDBRemote::LoadModules ()
ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list)
{
using lldb_private::process_gdb_remote::ProcessGDBRemote;
// request a list of loaded libraries from GDBServer
GDBLoadedModuleInfoList module_list;
if (GetLoadedModuleList (module_list).Fail())
return 0;
// get a list of all the modules
ModuleList new_modules;
for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list)
for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list)
{
std::string mod_name;
lldb::addr_t mod_base;
@ -4942,6 +4868,14 @@ ProcessGDBRemote::LoadModules ()
}
return new_modules.GetSize();
}
size_t
ProcessGDBRemote::LoadModules ()
{
LoadedModuleInfoList module_list;
return LoadModules (module_list);
}
Error

View File

@ -27,6 +27,7 @@
#include "lldb/Core/StringList.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Host/HostThread.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/Utility/StringExtractor.h"
@ -244,6 +245,9 @@ class ProcessGDBRemote : public Process
uint32_t &minor,
uint32_t &update) override;
size_t
LoadModules(LoadedModuleInfoList &module_list) override;
size_t
LoadModules() override;
@ -261,8 +265,6 @@ class ProcessGDBRemote : public Process
friend class GDBRemoteCommunicationClient;
friend class GDBRemoteRegisterContext;
class GDBLoadedModuleInfoList;
//------------------------------------------------------------------
/// Broadcaster event bits definitions.
//------------------------------------------------------------------
@ -429,6 +431,8 @@ class ProcessGDBRemote : public Process
const std::vector<lldb::addr_t> &exc_data,
lldb::addr_t thread_dispatch_qaddr,
bool queue_vars_valid,
lldb_private::LazyBool associated_with_libdispatch_queue,
lldb::addr_t dispatch_queue_t,
std::string &queue_name,
lldb::QueueKind queue_kind,
uint64_t queue_serial);
@ -461,7 +465,7 @@ class ProcessGDBRemote : public Process
// Query remote GDBServer for a detailed loaded library list
Error
GetLoadedModuleList (GDBLoadedModuleInfoList &);
GetLoadedModuleList (LoadedModuleInfoList &);
lldb::ModuleSP
LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr, bool value_is_offset);

View File

@ -41,8 +41,10 @@ ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) :
m_thread_name (),
m_dispatch_queue_name (),
m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
m_queue_kind(eQueueKindUnknown),
m_queue_serial(0)
m_dispatch_queue_t (LLDB_INVALID_ADDRESS),
m_queue_kind (eQueueKindUnknown),
m_queue_serial_number (LLDB_INVALID_QUEUE_ID),
m_associated_with_libdispatch_queue (eLazyBoolCalculate)
{
ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
this,
@ -73,15 +75,19 @@ ThreadGDBRemote::ClearQueueInfo ()
{
m_dispatch_queue_name.clear();
m_queue_kind = eQueueKindUnknown;
m_queue_serial = 0;
m_queue_serial_number = 0;
m_dispatch_queue_t = LLDB_INVALID_ADDRESS;
m_associated_with_libdispatch_queue = eLazyBoolCalculate;
}
void
ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial)
ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial, addr_t dispatch_queue_t, LazyBool associated_with_libdispatch_queue)
{
m_dispatch_queue_name = queue_name;
m_queue_kind = queue_kind;
m_queue_serial = queue_serial;
m_queue_serial_number = queue_serial;
m_dispatch_queue_t = dispatch_queue_t;
m_associated_with_libdispatch_queue = associated_with_libdispatch_queue;
}
@ -100,7 +106,10 @@ ThreadGDBRemote::GetQueueName ()
}
// Always re-fetch the dispatch queue name since it can change
if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
if (m_associated_with_libdispatch_queue == eLazyBoolNo)
return nullptr;
if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
{
ProcessSP process_sp (GetProcess());
if (process_sp)
@ -118,6 +127,35 @@ ThreadGDBRemote::GetQueueName ()
return NULL;
}
QueueKind
ThreadGDBRemote::GetQueueKind ()
{
// If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...)
// with valid information that was gleaned from the stop reply packet. In this case we trust
// that the info is valid in m_dispatch_queue_name without refetching it
if (CachedQueueInfoIsValid())
{
return m_queue_kind;
}
if (m_associated_with_libdispatch_queue == eLazyBoolNo)
return eQueueKindUnknown;
if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
{
ProcessSP process_sp (GetProcess());
if (process_sp)
{
SystemRuntime *runtime = process_sp->GetSystemRuntime ();
if (runtime)
m_queue_kind = runtime->GetQueueKind (m_thread_dispatch_qaddr);
return m_queue_kind;
}
}
return eQueueKindUnknown;
}
queue_id_t
ThreadGDBRemote::GetQueueID ()
{
@ -125,9 +163,12 @@ ThreadGDBRemote::GetQueueID ()
// with valid information that was gleaned from the stop reply packet. In this case we trust
// that the info is valid in m_dispatch_queue_name without refetching it
if (CachedQueueInfoIsValid())
return m_queue_serial;
return m_queue_serial_number;
if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
if (m_associated_with_libdispatch_queue == eLazyBoolNo)
return LLDB_INVALID_QUEUE_ID;
if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
{
ProcessSP process_sp (GetProcess());
if (process_sp)
@ -161,8 +202,9 @@ ThreadGDBRemote::GetQueue ()
addr_t
ThreadGDBRemote::GetQueueLibdispatchQueueAddress ()
{
addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS;
if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
if (m_dispatch_queue_t == LLDB_INVALID_ADDRESS)
{
if (m_thread_dispatch_qaddr != 0 && m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
{
ProcessSP process_sp (GetProcess());
if (process_sp)
@ -170,11 +212,44 @@ ThreadGDBRemote::GetQueueLibdispatchQueueAddress ()
SystemRuntime *runtime = process_sp->GetSystemRuntime ();
if (runtime)
{
dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr);
m_dispatch_queue_t = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr);
}
}
}
return dispatch_queue_t_addr;
}
return m_dispatch_queue_t;
}
void
ThreadGDBRemote::SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t)
{
m_dispatch_queue_t = dispatch_queue_t;
}
bool
ThreadGDBRemote::ThreadHasQueueInformation () const
{
if (m_thread_dispatch_qaddr != 0
&& m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS
&& m_dispatch_queue_t != LLDB_INVALID_ADDRESS
&& m_queue_kind != eQueueKindUnknown
&& m_queue_serial_number != 0)
{
return true;
}
return false;
}
LazyBool
ThreadGDBRemote::GetAssociatedWithLibdispatchQueue ()
{
return m_associated_with_libdispatch_queue;
}
void
ThreadGDBRemote::SetAssociatedWithLibdispatchQueue (LazyBool associated_with_libdispatch_queue)
{
m_associated_with_libdispatch_queue = associated_with_libdispatch_queue;
}
StructuredData::ObjectSP

View File

@ -46,6 +46,9 @@ class ThreadGDBRemote : public Thread
const char *
GetQueueName () override;
lldb::QueueKind
GetQueueKind () override;
lldb::queue_id_t
GetQueueID () override;
@ -55,6 +58,12 @@ class ThreadGDBRemote : public Thread
lldb::addr_t
GetQueueLibdispatchQueueAddress () override;
void
SetQueueLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t) override;
bool
ThreadHasQueueInformation () const override;
lldb::RegisterContextSP
GetRegisterContext () override;
@ -98,7 +107,13 @@ class ThreadGDBRemote : public Thread
ClearQueueInfo ();
void
SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial);
SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial, lldb::addr_t dispatch_queue_t, lldb_private::LazyBool associated_with_libdispatch_queue);
lldb_private::LazyBool
GetAssociatedWithLibdispatchQueue () override;
void
SetAssociatedWithLibdispatchQueue (lldb_private::LazyBool associated_with_libdispatch_queue) override;
StructuredData::ObjectSP
FetchThreadExtendedInfo () override;
@ -109,8 +124,10 @@ class ThreadGDBRemote : public Thread
std::string m_thread_name;
std::string m_dispatch_queue_name;
lldb::addr_t m_thread_dispatch_qaddr;
lldb::addr_t m_dispatch_queue_t;
lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread
uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread
uint64_t m_queue_serial_number; // Queue info from stop reply/stop info for thread
lldb_private::LazyBool m_associated_with_libdispatch_queue;
bool
PrivateSetRegisterValue (uint32_t reg,

View File

@ -77,6 +77,10 @@ PythonObject::GetObjectType() const
return PyObjectType::Dictionary;
if (PythonString::Check(m_py_obj))
return PyObjectType::String;
#if PY_MAJOR_VERSION >= 3
if (PythonBytes::Check(m_py_obj))
return PyObjectType::Bytes;
#endif
if (PythonInteger::Check(m_py_obj))
return PyObjectType::Integer;
if (PythonFile::Check(m_py_obj))
@ -210,6 +214,8 @@ PythonObject::CreateStructuredObject() const
return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();
case PyObjectType::String:
return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
case PyObjectType::Bytes:
return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();
case PyObjectType::None:
return StructuredData::ObjectSP();
default:
@ -217,6 +223,104 @@ PythonObject::CreateStructuredObject() const
}
}
//----------------------------------------------------------------------
// PythonString
//----------------------------------------------------------------------
PythonBytes::PythonBytes() : PythonObject()
{
}
PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) : PythonObject()
{
SetBytes(bytes);
}
PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) : PythonObject()
{
SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));
}
PythonBytes::PythonBytes(PyRefType type, PyObject *py_obj) : PythonObject()
{
Reset(type, py_obj); // Use "Reset()" to ensure that py_obj is a string
}
PythonBytes::PythonBytes(const PythonBytes &object) : PythonObject(object)
{
}
PythonBytes::~PythonBytes()
{
}
bool
PythonBytes::Check(PyObject *py_obj)
{
if (!py_obj)
return false;
if (PyBytes_Check(py_obj))
return true;
return false;
}
void
PythonBytes::Reset(PyRefType type, PyObject *py_obj)
{
// Grab the desired reference type so that if we end up rejecting
// `py_obj` it still gets decremented if necessary.
PythonObject result(type, py_obj);
if (!PythonBytes::Check(py_obj))
{
PythonObject::Reset();
return;
}
// Calling PythonObject::Reset(const PythonObject&) will lead to stack overflow since it calls
// back into the virtual implementation.
PythonObject::Reset(PyRefType::Borrowed, result.get());
}
llvm::ArrayRef<uint8_t>
PythonBytes::GetBytes() const
{
if (!IsValid())
return llvm::ArrayRef<uint8_t>();
Py_ssize_t size;
char *c;
PyBytes_AsStringAndSize(m_py_obj, &c, &size);
return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);
}
size_t
PythonBytes::GetSize() const
{
if (!IsValid())
return 0;
return PyBytes_Size(m_py_obj);
}
void
PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes)
{
const char *data = reinterpret_cast<const char *>(bytes.data());
PyObject *py_bytes = PyBytes_FromStringAndSize(data, bytes.size());
PythonObject::Reset(PyRefType::Owned, py_bytes);
}
StructuredData::StringSP
PythonBytes::CreateStructuredString() const
{
StructuredData::StringSP result(new StructuredData::String);
Py_ssize_t size;
char *c;
PyBytes_AsStringAndSize(m_py_obj, &c, &size);
result->SetValue(std::string(c, size));
return result;
}
//----------------------------------------------------------------------
// PythonString
//----------------------------------------------------------------------

View File

@ -23,8 +23,11 @@
#include "lldb/Host/File.h"
#include "lldb/Interpreter/OptionValue.h"
#include "llvm/ADT/ArrayRef.h"
namespace lldb_private {
class PythonBytes;
class PythonString;
class PythonList;
class PythonDictionary;
@ -71,6 +74,7 @@ enum class PyObjectType
Dictionary,
List,
String,
Bytes,
Module,
Callable,
Tuple,
@ -256,6 +260,39 @@ class PythonObject
PyObject* m_py_obj;
};
class PythonBytes : public PythonObject
{
public:
PythonBytes();
explicit PythonBytes(llvm::ArrayRef<uint8_t> bytes);
PythonBytes(const uint8_t *bytes, size_t length);
PythonBytes(PyRefType type, PyObject *o);
PythonBytes(const PythonBytes &object);
~PythonBytes() override;
static bool
Check(PyObject *py_obj);
// Bring in the no-argument base class version
using PythonObject::Reset;
void
Reset(PyRefType type, PyObject *py_obj) override;
llvm::ArrayRef<uint8_t>
GetBytes() const;
size_t
GetSize() const;
void
SetBytes(llvm::ArrayRef<uint8_t> stringbytes);
StructuredData::StringSP
CreateStructuredString() const;
};
class PythonString : public PythonObject
{
public:

View File

@ -1692,10 +1692,10 @@ ScriptInterpreterPython::OSPlugin_RegisterContextData(StructuredData::ObjectSP o
PyErr_Clear();
}
assert(PythonString::Check(py_return.get()) && "get_register_data returned unknown object type!");
assert(PythonBytes::Check(py_return.get()) && "get_register_data returned unknown object type!");
PythonString result_string(PyRefType::Borrowed, py_return.get());
return result_string.CreateStructuredString();
PythonBytes result(PyRefType::Borrowed, py_return.get());
return result.CreateStructuredString();
}
StructuredData::DictionarySP

View File

@ -33,6 +33,18 @@ struct DIERef
lldb::user_id_t
GetUID() const;
bool
operator< (const DIERef &ref) const
{
return die_offset < ref.die_offset;
}
bool
operator< (const DIERef &ref)
{
return die_offset < ref.die_offset;
}
dw_offset_t cu_offset;
dw_offset_t die_offset;
};

View File

@ -2928,7 +2928,7 @@ DWARFASTParserClang::ParseChildMembers (const SymbolContext& sc,
if (member_byte_offset >= parent_byte_size)
{
if (member_array_size != 1)
if (member_array_size != 1 && (member_array_size != 0 || member_byte_offset > parent_byte_size))
{
module_sp->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64,
die.GetID(),

View File

@ -1065,12 +1065,17 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec
const char * cu_comp_dir = resolveCompDir(cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr));
const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, DW_INVALID_OFFSET);
if (stmt_list != DW_INVALID_OFFSET)
{
// All file indexes in DWARF are one based and a file of index zero is
// supposed to be the compile unit itself.
support_files.Append (*sc.comp_unit);
return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files);
return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(),
get_debug_line_data(),
cu_comp_dir,
stmt_list,
support_files);
}
}
}
return false;
@ -2927,6 +2932,40 @@ SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inli
return sc_list.GetSize() - original_size;
}
void
SymbolFileDWARF::GetMangledNamesForFunction (const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names)
{
DWARFDebugInfo* info = DebugInfo();
uint32_t num_comp_units = 0;
if (info)
num_comp_units = info->GetNumCompileUnits();
for (uint32_t i = 0; i < num_comp_units; i++)
{
DWARFCompileUnit *cu = info->GetCompileUnitAtIndex(i);
if (cu == nullptr)
continue;
SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile();
if (dwo)
dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names);
}
NameToOffsetMap::iterator iter = m_function_scope_qualified_name_map.find(scope_qualified_name);
if (iter == m_function_scope_qualified_name_map.end())
return;
DIERefSetSP set_sp = (*iter).second;
std::set<DIERef>::iterator set_iter;
for (set_iter = set_sp->begin(); set_iter != set_sp->end(); set_iter++)
{
DWARFDIE die = DebugInfo()->GetDIE (*set_iter);
mangled_names.push_back(ConstString(die.GetMangledName()));
}
}
uint32_t
SymbolFileDWARF::FindTypes (const SymbolContext& sc,
const ConstString &name,
@ -3751,6 +3790,24 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, const DWARFDIE &die, bool *
TypeList* type_list = GetTypeList();
if (type_list)
type_list->Insert(type_sp);
if (die.Tag() == DW_TAG_subprogram)
{
DIERef die_ref = die.GetDIERef();
std::string scope_qualified_name(GetDeclContextForUID(die.GetID()).GetScopeQualifiedName().AsCString(""));
if (scope_qualified_name.size())
{
NameToOffsetMap::iterator iter = m_function_scope_qualified_name_map.find(scope_qualified_name);
if (iter != m_function_scope_qualified_name_map.end())
(*iter).second->insert(die_ref);
else
{
DIERefSetSP new_set(new std::set<DIERef>);
new_set->insert(die_ref);
m_function_scope_qualified_name_map.emplace(std::make_pair(scope_qualified_name, new_set));
}
}
}
}
}
}

View File

@ -208,6 +208,10 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::Us
bool append,
lldb_private::SymbolContextList& sc_list) override;
void
GetMangledNamesForFunction (const std::string &scope_qualified_name,
std::vector<lldb_private::ConstString> &mangled_names) override;
uint32_t
FindTypes (const lldb_private::SymbolContext& sc,
const lldb_private::ConstString &name,
@ -577,6 +581,9 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::Us
m_fetched_external_modules:1;
lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
typedef std::shared_ptr<std::set<DIERef> > DIERefSetSP;
typedef std::unordered_map<std::string, DIERefSetSP> NameToOffsetMap;
NameToOffsetMap m_function_scope_qualified_name_map;
std::unique_ptr<DWARFDebugRanges> m_ranges;
UniqueDWARFASTTypeMap m_unique_ast_type_map;
DIEToTypePtr m_die_to_type;

View File

@ -724,18 +724,30 @@ SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
// queue on thread 1 is always around.
for (ThreadSP thread_sp : m_process->Threads())
{
if (thread_sp->GetAssociatedWithLibdispatchQueue () != eLazyBoolNo)
{
if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
{
if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
{
QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
if (thread_sp->ThreadHasQueueInformation ())
{
queue_sp->SetKind (thread_sp->GetQueueKind ());
queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
queue_list.AddQueue (queue_sp);
}
else
{
queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress()));
queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
queue_list.AddQueue (queue_sp);
}
}
}
}
}
}
// Returns either an array of introspection_dispatch_item_info_ref's for the pending items on

View File

@ -104,8 +104,8 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
void
CompleteQueueItem(lldb_private::QueueItem *queue_item, lldb::addr_t item_ref) override;
virtual lldb::QueueKind
GetQueueKind (lldb::addr_t dispatch_queue_addr);
lldb::QueueKind
GetQueueKind (lldb::addr_t dispatch_queue_addr) override;
void
AddThreadExtendedInfoPacketHints(lldb_private::StructuredData::ObjectSP dict) override;

View File

@ -155,6 +155,7 @@ class AssemblyParse_x86
bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
bool ret_pattern_p ();
bool pop_rbp_pattern_p ();
bool leave_pattern_p ();
bool call_next_insn_pattern_p();
uint32_t extract_4 (uint8_t *b);
bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
@ -492,6 +493,14 @@ AssemblyParse_x86::pop_rbp_pattern_p ()
return (*p == 0x5d);
}
// leave [0xc9]
bool
AssemblyParse_x86::leave_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
return (*p == 0xc9);
}
// call $0 [0xe8 0x0 0x0 0x0 0x0]
bool
AssemblyParse_x86::call_next_insn_pattern_p ()
@ -780,8 +789,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
if (machine_regno == (int)m_machine_fp_regnum)
{
row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum,
row->GetCFAValue().GetOffset());
row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, row->GetCFAValue().GetOffset());
}
in_epilogue = true;
@ -792,12 +800,35 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// we need to add a new row of instructions.
if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum,
current_sp_bytes_offset_from_cfa);
row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
// The LEAVE instruction moves the value from rbp into rsp and pops
// a value off the stack into rbp (restoring the caller's rbp value).
// It is the opposite of ENTER, or 'push rbp, mov rsp rbp'.
else if (leave_pattern_p ())
{
// We're going to copy the value in rbp into rsp, so re-set the sp offset
// based on the CFAValue. Also, adjust it to recognize that we're popping
// the saved rbp value off the stack.
current_sp_bytes_offset_from_cfa = row->GetCFAValue().GetOffset();
current_sp_bytes_offset_from_cfa -= m_wordsize;
row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
// rbp is restored to the caller's value
saved_registers[m_machine_fp_regnum] = false;
row->RemoveRegisterInfo (m_lldb_fp_regnum);
// cfa is now in terms of rsp again.
row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, row->GetCFAValue().GetOffset());
row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
in_epilogue = true;
row_updated = true;
}
else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset)
&& nonvolatile_reg_p (machine_regno)
&& machine_regno_to_lldb_regno (machine_regno, lldb_regno)
@ -1137,15 +1168,15 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// The only case we care about is epilogue:
// [0x5d] pop %rbp/%ebp
// => [0xc3] ret
if (pop_rbp_pattern_p ())
if (pop_rbp_pattern_p () || leave_pattern_p ())
{
if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
1, error) != static_cast<size_t>(-1)
&& ret_pattern_p ())
{
row->SetOffset (offset);
row->GetCFAValue().SetIsRegisterPlusOffset (
first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
row->GetCFAValue().SetIsRegisterPlusOffset (first_row->GetCFAValue().GetRegisterNumber(),
m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);

View File

@ -4158,6 +4158,7 @@ ClangASTContext::GetTypeClass (lldb::opaque_compiler_type_t type)
case clang::Type::Decltype: break;
case clang::Type::TemplateSpecialization: break;
case clang::Type::Atomic: break;
case clang::Type::Pipe: break;
// pointer type decayed from an array or function type.
case clang::Type::Decayed: break;
@ -4891,6 +4892,7 @@ ClangASTContext::GetEncoding (lldb::opaque_compiler_type_t type, uint64_t &count
case clang::Type::TemplateSpecialization:
case clang::Type::Atomic:
case clang::Type::Adjusted:
case clang::Type::Pipe:
break;
// pointer type decayed from an array or function type.
@ -5008,6 +5010,7 @@ ClangASTContext::GetFormat (lldb::opaque_compiler_type_t type)
case clang::Type::TemplateSpecialization:
case clang::Type::Atomic:
case clang::Type::Adjusted:
case clang::Type::Pipe:
break;
// pointer type decayed from an array or function type.
@ -9969,6 +9972,18 @@ ClangASTContext::DeclContextGetName (void *opaque_decl_ctx)
return ConstString();
}
ConstString
ClangASTContext::DeclContextGetScopeQualifiedName (void *opaque_decl_ctx)
{
if (opaque_decl_ctx)
{
clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx);
if (named_decl)
return ConstString(llvm::StringRef(named_decl->getQualifiedNameAsString()));
}
return ConstString();
}
bool
ClangASTContext::DeclContextIsClassMethod (void *opaque_decl_ctx,
lldb::LanguageType *language_ptr,

View File

@ -38,6 +38,15 @@ CompilerDeclContext::GetName () const
return ConstString();
}
ConstString
CompilerDeclContext::GetScopeQualifiedName () const
{
if (IsValid())
return m_type_system->DeclContextGetScopeQualifiedName(m_opaque_decl_ctx);
else
return ConstString();
}
bool
CompilerDeclContext::IsStructUnionOrClass () const
{

View File

@ -143,6 +143,13 @@ LineTable::InsertSequence (LineSequence* sequence)
entry_collection::iterator end_pos = m_entries.end();
LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp);
// We should never insert a sequence in the middle of another sequence
if (pos != begin_pos) {
while (pos < end_pos && !((pos - 1)->is_terminal_entry))
pos++;
}
#ifdef LLDB_CONFIGURATION_DEBUG
// If we aren't inserting at the beginning, the previous entry should
// terminate a sequence.

View File

@ -134,6 +134,12 @@ SymbolFile::FindFunctions (const RegularExpression& regex, bool include_inlines,
return 0;
}
void
SymbolFile::GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names)
{
return;
}
uint32_t
SymbolFile::FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, TypeMap& types)
{

View File

@ -6515,3 +6515,65 @@ Process::ResetImageToken(size_t token)
if (token < m_image_tokens.size())
m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN;
}
Address
Process::AdvanceAddressToNextBranchInstruction (Address default_stop_addr, AddressRange range_bounds)
{
Target &target = GetTarget();
DisassemblerSP disassembler_sp;
InstructionList *insn_list = NULL;
Address retval = default_stop_addr;
if (target.GetUseFastStepping() == false)
return retval;
if (default_stop_addr.IsValid() == false)
return retval;
ExecutionContext exe_ctx (this);
const char *plugin_name = nullptr;
const char *flavor = nullptr;
const bool prefer_file_cache = true;
disassembler_sp = Disassembler::DisassembleRange(target.GetArchitecture(),
plugin_name,
flavor,
exe_ctx,
range_bounds,
prefer_file_cache);
if (disassembler_sp.get())
insn_list = &disassembler_sp->GetInstructionList();
if (insn_list == NULL)
{
return retval;
}
size_t insn_offset = insn_list->GetIndexOfInstructionAtAddress (default_stop_addr);
if (insn_offset == UINT32_MAX)
{
return retval;
}
uint32_t branch_index = insn_list->GetIndexOfNextBranchInstruction (insn_offset, target);
if (branch_index == UINT32_MAX)
{
return retval;
}
if (branch_index > insn_offset)
{
Address next_branch_insn_address = insn_list->GetInstructionAtIndex (branch_index)->GetAddress();
if (next_branch_insn_address.IsValid() && range_bounds.ContainsFileAddress (next_branch_insn_address))
{
retval = next_branch_insn_address;
}
}
if (disassembler_sp.get())
{
// FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
disassembler_sp->GetInstructionList().Clear();
}
return retval;
}

Some files were not shown because too many files have changed in this diff Show More