"""
Set breakpoints on objective-c class and instance methods in foundation.
Also lookup objective-c data types and evaluate expressions.
"""
import os
import os.path
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
file_index = 0
class FoundationTestCase(TestBase):
def setUp(self):
TestBase.setUp(self)
self.main_source = "main.m"
self.line = line_number(self.main_source, "// Set break point at this line.")
def test_break(self):
"""Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
self.build()
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
break_results = lldbutil.run_break_set_command(
self, "_regexp-break +[NSString stringWithFormat:]"
)
lldbutil.check_breakpoint_result(
self,
break_results,
symbol_name="+[NSString stringWithFormat:]",
num_locations=1,
)
lldbutil.run_break_set_by_symbol(
self,
"-[MyString initWithNSString:]",
num_expected_locations=1,
sym_exact=True,
)
lldbutil.run_break_set_by_selector(
self, "description", num_expected_locations=1, module_name="a.out"
)
break_results = lldbutil.run_break_set_command(
self, "_regexp-break -[NSAutoreleasePool release]"
)
lldbutil.check_breakpoint_result(
self,
break_results,
symbol_name="-[NSAutoreleasePool release]",
num_locations=1,
)
self.runCmd("run", RUN_SUCCEEDED)
self.expect(
"thread backtrace",
"Stop at +[NSString stringWithFormat:]",
substrs=["Foundation`+[NSString stringWithFormat:]"],
)
self.runCmd("process continue")
self.expect(
"thread backtrace",
"Stop at +[NSString stringWithFormat:]",
substrs=["Foundation`+[NSString stringWithFormat:]"],
)
self.runCmd("process continue")
self.expect(
"thread backtrace",
"Stop at a.out`-[MyString initWithNSString:]",
substrs=["a.out`-[MyString initWithNSString:]"],
)
self.runCmd("process continue")
self.expect(
"thread backtrace",
"Stop at -[MyString description]",
substrs=["a.out`-[MyString description]"],
)
self.runCmd("process continue")
self.expect(
"thread backtrace",
"Stop at -[MyString description]",
substrs=["a.out`-[MyString description]"],
)
self.runCmd("process continue")
self.expect(
"thread backtrace",
"Stop at -[NSAutoreleasePool release]",
substrs=["Foundation`-[NSAutoreleasePool release]"],
)
def test_data_type_and_expr(self):
"""Lookup objective-c data types and evaluate expressions."""
self.build()
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_symbol(
self, "-[MyString description]", num_expected_locations=1, sym_exact=True
)
self.runCmd("run", RUN_SUCCEEDED)
self.runCmd("settings set target.prefer-dynamic-value no-dynamic-values")
self.expect(
"thread backtrace",
"Stop at -[MyString description]",
substrs=["a.out`-[MyString description]"],
)
self.expect(
"image lookup -t NSString",
DATA_TYPES_DISPLAYED_CORRECTLY,
substrs=['name = "NSString"', 'compiler_type = "@interface NSString'],
)
self.expect(
"image lookup -t MyString",
DATA_TYPES_DISPLAYED_CORRECTLY,
substrs=[
'name = "MyString"',
'compiler_type = "@interface MyString',
"NSString * str;",
"NSDate * date;",
],
)
self.expect(
"frame variable --show-types --scope",
VARIABLES_DISPLAYED_CORRECTLY,
substrs=["ARG: (MyString *) self"],
patterns=["ARG: \(.*\) _cmd", "(objc_selector *)|(SEL)"],
)
self.runCmd("frame variable *_cmd")
self.expect(
"frame variable --show-types self->str",
VARIABLES_DISPLAYED_CORRECTLY,
startstr="(NSString *) self->str",
)
self.expect(
"frame variable --show-types self->date",
VARIABLES_DISPLAYED_CORRECTLY,
startstr="(NSDate *) self->date",
)
self.expect(
"frame variable --show-types *self",
VARIABLES_DISPLAYED_CORRECTLY,
substrs=["(MyString) *self", "(NSString *) str", "(NSDate *) date"],
)
self.expect(
"expression self->isa", VARIABLES_DISPLAYED_CORRECTLY, substrs=["Class)"]
)
self.expect(
"expression self->non_existent_member",
COMMAND_FAILED_AS_EXPECTED,
error=True,
substrs=[
"error:",
"'MyString' does not have a member named 'non_existent_member'",
],
)
self.runCmd("expression self->str")
self.runCmd("expression self->date")
self.runCmd("breakpoint delete 1")
lldbutil.run_break_set_by_file_and_line(
self, "main.m", self.line, num_expected_locations=1, loc_exact=True
)
self.runCmd("process continue")
self.expect(
"expression --object-description -- my",
"Object description displayed correctly",
patterns=["Hello from.*a.out.*with timestamp: "],
)
@add_test_categories(["pyapi"])
def test_print_ivars_correctly(self):
self.build()
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
break1 = target.BreakpointCreateByLocation(self.main_source, self.line)
self.assertTrue(break1, VALID_BREAKPOINT)
process = target.LaunchSimple(None, None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
thread = process.GetThreadAtIndex(0)
if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
from lldbsuite.test.lldbutil import stop_reason_to_str
self.fail(
STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS
% stop_reason_to_str(thread.GetStopReason())
)
cur_frame = thread.GetFrameAtIndex(0)
line_number = cur_frame.GetLineEntry().GetLine()
self.assertEqual(line_number, self.line, "Hit the first breakpoint.")
my_var = cur_frame.FindVariable("my")
self.assertTrue(my_var, "Made a variable object for my")
str_var = cur_frame.FindVariable("str")
self.assertTrue(str_var, "Made a variable object for str")
my_str_var = my_var.GetChildMemberWithName("str")
self.assertTrue(my_str_var, "Found a str ivar in my")
str_value = int(str_var.GetValue(), 0)
my_str_value = int(my_str_var.GetValue(), 0)
self.assertEqual(str_value, my_str_value, "Got the correct value for my->str")
def test_expression_lookups_objc(self):
"""Test running an expression detect spurious debug info lookups (DWARF)."""
self.build()
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_symbol(
self,
"-[MyString initWithNSString:]",
num_expected_locations=1,
sym_exact=True,
)
self.runCmd("run", RUN_SUCCEEDED)
global file_index
++file_index
logfile = os.path.join(
self.getBuildDir(),
"dwarf-lookups-" + self.getArchitecture() + "-" + str(file_index) + ".txt",
)
self.runCmd("log enable -f %s dwarf lookups" % (logfile))
self.runCmd("expr self")
self.runCmd("log disable dwarf lookups")
def cleanup():
if os.path.exists(logfile):
os.unlink(logfile)
self.addTearDownHook(cleanup)
if os.path.exists(logfile):
f = open(logfile)
lines = f.readlines()
num_errors = 0
for line in lines:
if "$__lldb" in line:
if num_errors == 0:
print(
"error: found spurious name lookups when evaluating an expression:"
)
num_errors += 1
print(line, end="")
self.assertEqual(num_errors, 0, "Spurious lookups detected")
f.close()