forked from OSchip/llvm-project
Add logic to LLDB to figure out the types of member functions of C++ classes. Add plumbing for that all the way up to the SB layer
llvm-svn: 217701
This commit is contained in:
parent
ab4fe98b4a
commit
190064ad0d
|
@ -160,6 +160,12 @@ public:
|
||||||
|
|
||||||
lldb::SBTypeList
|
lldb::SBTypeList
|
||||||
GetFunctionArgumentTypes ();
|
GetFunctionArgumentTypes ();
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
GetNumberOfMemberFunctions ();
|
||||||
|
|
||||||
|
lldb::SBType
|
||||||
|
GetMemberFunctionAtIndex (uint32_t idx);
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
GetName();
|
GetName();
|
||||||
|
|
|
@ -334,6 +334,12 @@ public:
|
||||||
ClangASTType
|
ClangASTType
|
||||||
GetFunctionReturnType () const;
|
GetFunctionReturnType () const;
|
||||||
|
|
||||||
|
size_t
|
||||||
|
GetNumMemberFunctions () const;
|
||||||
|
|
||||||
|
ClangASTType
|
||||||
|
GetMemberFunctionAtIndex (size_t idx);
|
||||||
|
|
||||||
ClangASTType
|
ClangASTType
|
||||||
GetLValueReferenceType () const;
|
GetLValueReferenceType () const;
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,12 @@ public:
|
||||||
|
|
||||||
lldb::SBTypeList
|
lldb::SBTypeList
|
||||||
GetFunctionArgumentTypes ();
|
GetFunctionArgumentTypes ();
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
GetNumberOfMemberFunctions ();
|
||||||
|
|
||||||
|
lldb::SBType
|
||||||
|
GetMemberFunctionAtIndex (uint32_t idx);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsTypeComplete ();
|
IsTypeComplete ();
|
||||||
|
|
|
@ -252,6 +252,28 @@ SBType::GetFunctionArgumentTypes ()
|
||||||
return sb_type_list;
|
return sb_type_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
SBType::GetNumberOfMemberFunctions ()
|
||||||
|
{
|
||||||
|
if (IsValid())
|
||||||
|
{
|
||||||
|
return m_opaque_sp->GetClangASTType(true).GetNumMemberFunctions();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lldb::SBType
|
||||||
|
SBType::GetMemberFunctionAtIndex (uint32_t idx)
|
||||||
|
{
|
||||||
|
SBType sb_func_type;
|
||||||
|
if (IsValid())
|
||||||
|
{
|
||||||
|
ClangASTType func_type(m_opaque_sp->GetClangASTType(true).GetMemberFunctionAtIndex(idx));
|
||||||
|
sb_func_type = SBType(func_type);
|
||||||
|
}
|
||||||
|
return sb_func_type;
|
||||||
|
}
|
||||||
|
|
||||||
lldb::SBType
|
lldb::SBType
|
||||||
SBType::GetUnqualifiedType()
|
SBType::GetUnqualifiedType()
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "lldb/Target/ExecutionContext.h"
|
#include "lldb/Target/ExecutionContext.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
using namespace lldb;
|
using namespace lldb;
|
||||||
|
@ -1741,6 +1742,68 @@ ClangASTType::GetFunctionReturnType () const
|
||||||
return ClangASTType();
|
return ClangASTType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ClangASTType::GetNumMemberFunctions () const
|
||||||
|
{
|
||||||
|
size_t num_functions = 0;
|
||||||
|
if (IsValid())
|
||||||
|
{
|
||||||
|
clang::QualType qual_type(GetCanonicalQualType());
|
||||||
|
switch (qual_type->getTypeClass()) {
|
||||||
|
case clang::Type::Record:
|
||||||
|
if (GetCompleteQualType (m_ast, qual_type))
|
||||||
|
{
|
||||||
|
const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||||
|
const clang::RecordDecl *record_decl = record_type->getDecl();
|
||||||
|
assert(record_decl);
|
||||||
|
const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
|
||||||
|
if (cxx_record_decl)
|
||||||
|
num_functions = std::distance(cxx_record_decl->method_begin(), cxx_record_decl->method_end());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num_functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangASTType
|
||||||
|
ClangASTType::GetMemberFunctionAtIndex (size_t idx)
|
||||||
|
{
|
||||||
|
if (IsValid())
|
||||||
|
{
|
||||||
|
clang::QualType qual_type(GetCanonicalQualType());
|
||||||
|
switch (qual_type->getTypeClass()) {
|
||||||
|
case clang::Type::Record:
|
||||||
|
if (GetCompleteQualType (m_ast, qual_type))
|
||||||
|
{
|
||||||
|
const clang::RecordType *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
|
||||||
|
const clang::RecordDecl *record_decl = record_type->getDecl();
|
||||||
|
assert(record_decl);
|
||||||
|
const clang::CXXRecordDecl *cxx_record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
|
||||||
|
if (cxx_record_decl)
|
||||||
|
{
|
||||||
|
auto method_iter = cxx_record_decl->method_begin();
|
||||||
|
auto method_end = cxx_record_decl->method_end();
|
||||||
|
if (idx < std::distance(method_iter, method_end))
|
||||||
|
{
|
||||||
|
std::advance(method_iter, idx);
|
||||||
|
auto method_decl = method_iter->getCanonicalDecl();
|
||||||
|
if (method_decl)
|
||||||
|
return ClangASTType(m_ast,method_decl->getType().getAsOpaquePtr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClangASTType();
|
||||||
|
}
|
||||||
|
|
||||||
ClangASTType
|
ClangASTType
|
||||||
ClangASTType::GetLValueReferenceType () const
|
ClangASTType::GetLValueReferenceType () const
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
LEVEL = ../../make
|
||||||
|
|
||||||
|
CXX_SOURCES := main.cpp
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,81 @@
|
||||||
|
"""
|
||||||
|
Test SBType and SBTypeList API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os, time
|
||||||
|
import re
|
||||||
|
import unittest2
|
||||||
|
import lldb, lldbutil
|
||||||
|
from lldbtest import *
|
||||||
|
|
||||||
|
class TypeAndTypeListTestCase(TestBase):
|
||||||
|
|
||||||
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
|
|
||||||
|
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||||
|
@python_api_test
|
||||||
|
@dsym_test
|
||||||
|
def test_with_dsym(self):
|
||||||
|
"""Exercise SBType and SBTypeList API."""
|
||||||
|
d = {'EXE': self.exe_name}
|
||||||
|
self.buildDsym(dictionary=d)
|
||||||
|
self.setTearDownCleanup(dictionary=d)
|
||||||
|
self.type_api(self.exe_name)
|
||||||
|
|
||||||
|
@python_api_test
|
||||||
|
@dwarf_test
|
||||||
|
def test_with_dwarf(self):
|
||||||
|
"""Exercise SBType and SBTypeList API."""
|
||||||
|
d = {'EXE': self.exe_name}
|
||||||
|
self.buildDwarf(dictionary=d)
|
||||||
|
self.setTearDownCleanup(dictionary=d)
|
||||||
|
self.type_api(self.exe_name)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Call super's setUp().
|
||||||
|
TestBase.setUp(self)
|
||||||
|
# We'll use the test method name as the exe_name.
|
||||||
|
self.exe_name = self.testMethodName
|
||||||
|
# Find the line number to break at.
|
||||||
|
self.source = 'main.cpp'
|
||||||
|
self.line = line_number(self.source, '// set breakpoint here')
|
||||||
|
|
||||||
|
def type_api(self, exe_name):
|
||||||
|
"""Exercise SBType and SBTypeList API."""
|
||||||
|
exe = os.path.join(os.getcwd(), exe_name)
|
||||||
|
|
||||||
|
# Create a target by the debugger.
|
||||||
|
target = self.dbg.CreateTarget(exe)
|
||||||
|
self.assertTrue(target, VALID_TARGET)
|
||||||
|
|
||||||
|
# Create the breakpoint inside function 'main'.
|
||||||
|
breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
|
||||||
|
self.assertTrue(breakpoint, VALID_BREAKPOINT)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Get Frame #0.
|
||||||
|
self.assertTrue(process.GetState() == lldb.eStateStopped)
|
||||||
|
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
|
||||||
|
self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition")
|
||||||
|
frame0 = thread.GetFrameAtIndex(0)
|
||||||
|
|
||||||
|
variable = frame0.FindVariable("d")
|
||||||
|
Derived = variable.GetType()
|
||||||
|
Base = Derived.GetDirectBaseClassAtIndex(0).GetType()
|
||||||
|
|
||||||
|
self.assertTrue(Derived.GetNumberOfMemberFunctions() == 2, "Derived declares two methods")
|
||||||
|
self.assertTrue(Derived.GetMemberFunctionAtIndex(0).GetFunctionReturnType().GetName() == "int", "Derived::dImpl returns int")
|
||||||
|
|
||||||
|
self.assertTrue(Base.GetNumberOfMemberFunctions() == 4, "Base declares three methods")
|
||||||
|
self.assertTrue(Base.GetMemberFunctionAtIndex(3).GetFunctionArgumentTypes().GetSize() == 3, "Base::sfunc takes three arguments")
|
||||||
|
self.assertTrue(Base.GetMemberFunctionAtIndex(2).GetFunctionArgumentTypes().GetSize() == 0, "Base::dat takes no arguments")
|
||||||
|
self.assertTrue(Base.GetMemberFunctionAtIndex(1).GetFunctionArgumentTypes().GetTypeAtIndex(1).GetName() == "char", "Base::bar takes a second 'char' argument")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import atexit
|
||||||
|
lldb.SBDebugger.Initialize()
|
||||||
|
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||||
|
unittest2.main()
|
|
@ -0,0 +1,28 @@
|
||||||
|
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
class Base {
|
||||||
|
public:
|
||||||
|
int foo(int x, int y) { return 1; }
|
||||||
|
char bar(int x, char y) { return 2; }
|
||||||
|
void dat() {}
|
||||||
|
static int sfunc(char, int, float) { return 3; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Derived: public Base {
|
||||||
|
protected:
|
||||||
|
int dImpl() { return 1; }
|
||||||
|
public:
|
||||||
|
float baz(float b) { return b + 1.0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Derived d;
|
||||||
|
return 0; // set breakpoint here
|
||||||
|
}
|
Loading…
Reference in New Issue