Teach SBFrame how to guess its language.

<rdar://problem/31411646>

llvm-svn: 300012
This commit is contained in:
Jim Ingham 2017-04-12 00:19:54 +00:00
parent a76349bffe
commit bdbdd22937
12 changed files with 181 additions and 3 deletions

View File

@ -78,6 +78,10 @@ public:
const char *GetDisplayFunctionName();
const char *GetFunctionName() const;
// Return the frame function's language. If there isn't a function, then
// guess the language type from the mangled name.
lldb::LanguageType GuessLanguage() const;
/// Return true if this frame represents an inlined function.
///

View File

@ -0,0 +1,12 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp other.cpp other-2.cpp
C_SOURCES := somefunc.c
include $(LEVEL)/Makefile.rules
other-2.o: other-2.cpp
$(CXX) $(CFLAGS_NO_DEBUG) -c other-2.cpp
somefunc.o: somefunc.c
$(CC) $(CFLAGS) -std=c99 -c somefunc.c

View File

@ -0,0 +1,81 @@
"""
Test the SB API SBFrame::GuessLanguage.
"""
from __future__ import print_function
import os
import time
import re
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.lldbtest import *
class TestFrameGuessLanguage(TestBase):
mydir = TestBase.compute_mydir(__file__)
# If your test case doesn't stress debug info, the
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True
def test_guess_language(self):
"""Test GuessLanguage for C and C++."""
self.build()
self.do_test()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
def check_language(self, thread, frame_no, test_lang):
frame = thread.frames[frame_no]
self.assertTrue(frame.IsValid(), "Frame %d was not valid."%(frame_no))
lang = frame.GuessLanguage()
self.assertEqual(lang, test_lang)
def do_test(self):
"""Test GuessLanguage for C & C++."""
exe = os.path.join(os.getcwd(), "a.out")
# Create a target by the debugger.
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
# Now create a breakpoint in main.c at the source matching
# "Set a breakpoint here"
breakpoint = target.BreakpointCreateBySourceRegex(
"Set breakpoint here", lldb.SBFileSpec("somefunc.c"))
self.assertTrue(breakpoint and
breakpoint.GetNumLocations() >= 1,
VALID_BREAKPOINT)
error = lldb.SBError()
# This is the launch info. If you want to launch with arguments or
# environment variables, add them using SetArguments or
# SetEnvironmentEntries
launch_info = lldb.SBLaunchInfo(None)
process = target.Launch(launch_info, error)
self.assertTrue(process, PROCESS_IS_VALID)
# Did we hit our breakpoint?
from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
threads = get_threads_stopped_at_breakpoint(process, breakpoint)
self.assertTrue(
len(threads) == 1,
"There should be a thread stopped at our breakpoint")
# The hit count for the breakpoint should be 1.
self.assertTrue(breakpoint.GetHitCount() == 1)
thread = threads[0]
self.check_language(thread, 0, lldb.eLanguageTypeC99)
self.check_language(thread, 1, lldb.eLanguageTypeC_plus_plus)
self.check_language(thread, 2, lldb.eLanguageTypeC_plus_plus)

View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include "other.h"
int
main()
{
int test_var = 10;
Other::DoSomethingElse();
return 0;
}

View File

@ -0,0 +1,7 @@
#include "other.h"
void
Other::DoSomethingElse()
{
DoSomething();
}

View File

@ -0,0 +1,10 @@
#include "other.h"
extern "C" void some_func();
void
Other::DoSomething()
{
some_func();
}

View File

@ -0,0 +1,7 @@
class Other
{
public:
static void DoSomething();
static void DoSomethingElse();
};

View File

@ -0,0 +1,7 @@
#include <stdio.h>
void
some_func()
{
printf("Set breakpoint here.");
}

View File

@ -133,6 +133,14 @@ public:
const char *
GetFunctionName() const;
%feature("docstring", "
/// Returns the language of the frame's SBFunction, or if there.
/// is no SBFunction, guess the language from the mangled name.
/// .
") GuessLanguage;
lldb::LanguageType
GuessLanguage() const;
%feature("docstring", "
/// Return true if this frame represents an inlined function.

View File

@ -1370,6 +1370,25 @@ const char *SBFrame::GetFunctionName() {
return static_cast<const SBFrame *>(this)->GetFunctionName();
}
lldb::LanguageType SBFrame::GuessLanguage() const {
std::unique_lock<std::recursive_mutex> lock;
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
StackFrame *frame = nullptr;
Target *target = exe_ctx.GetTargetPtr();
Process *process = exe_ctx.GetProcessPtr();
if (target && process) {
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&process->GetRunLock())) {
frame = exe_ctx.GetFramePtr();
if (frame) {
return frame->GuessLanguage();
}
}
}
return eLanguageTypeUnknown;
}
const char *SBFrame::GetFunctionName() const {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
const char *name = nullptr;

View File

@ -432,6 +432,14 @@ lldb::LanguageType Mangled::GuessLanguage() const {
else if (ObjCLanguage::IsPossibleObjCMethodName(mangled_name))
return lldb::eLanguageTypeObjC;
}
} else {
// ObjC names aren't really mangled, so they won't necessarily be in the
// mangled name slot.
ConstString demangled_name = GetDemangledName(lldb::eLanguageTypeUnknown);
if (demangled_name
&& ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()))
return lldb::eLanguageTypeObjC;
}
return lldb::eLanguageTypeUnknown;
}

View File

@ -1212,9 +1212,14 @@ lldb::LanguageType StackFrame::GuessLanguage() {
LanguageType lang_type = GetLanguage();
if (lang_type == eLanguageTypeUnknown) {
Function *f = GetSymbolContext(eSymbolContextFunction).function;
if (f) {
lang_type = f->GetMangled().GuessLanguage();
SymbolContext sc = GetSymbolContext(eSymbolContextFunction
| eSymbolContextSymbol);
if (sc.function) {
lang_type = sc.function->GetMangled().GuessLanguage();
}
else if (sc.symbol)
{
lang_type = sc.symbol->GetMangled().GuessLanguage();
}
}