"""
Make sure the frame variable -g, -a, and -l flags work.
"""
import lldb
import lldbsuite.test.lldbutil as lldbutil
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
import os
import shutil
import time
class TestFrameVar(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def test_frame_var(self):
self.build()
self.do_test()
def do_test(self):
target = self.createTestTarget()
breakpoint = target.BreakpointCreateBySourceRegex(
"Set a breakpoint here", lldb.SBFileSpec("main.c")
)
self.assertTrue(
breakpoint and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT
)
error = lldb.SBError()
launch_info = target.GetLaunchInfo()
process = target.Launch(launch_info, error)
self.assertTrue(process, PROCESS_IS_VALID)
from lldbsuite.test.lldbutil import get_threads_stopped_at_breakpoint
threads = get_threads_stopped_at_breakpoint(process, breakpoint)
self.assertEqual(
len(threads), 1, "There should be a thread stopped at our breakpoint"
)
self.assertEqual(breakpoint.GetHitCount(), 1)
frame = threads[0].GetFrameAtIndex(0)
command_result = lldb.SBCommandReturnObject()
interp = self.dbg.GetCommandInterpreter()
self.expect("frame var --regex g_", substrs=["g_var"])
self.expect(
"frame var --regex argc --no-args",
error=True,
substrs=["no variables matched the regular expression 'argc'"],
)
result = interp.HandleCommand("frame var -l", command_result)
self.assertEqual(
result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"
)
output = command_result.GetOutput()
self.assertIn("argc", output, "Args didn't find argc")
self.assertIn("argv", output, "Args didn't find argv")
self.assertNotIn("test_var", output, "Args found a local")
self.assertNotIn("g_var", output, "Args found a global")
result = interp.HandleCommand("frame var -a", command_result)
self.assertEqual(
result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"
)
output = command_result.GetOutput()
self.assertNotIn("argc", output, "Locals found argc")
self.assertNotIn("argv", output, "Locals found argv")
self.assertIn("test_var", output, "Locals didn't find test_var")
self.assertNotIn("g_var", output, "Locals found a global")
result = interp.HandleCommand("frame var -l -a -g", command_result)
self.assertEqual(
result, lldb.eReturnStatusSuccessFinishResult, "frame var -a didn't succeed"
)
output = command_result.GetOutput()
self.assertNotIn("argc", output, "Globals found argc")
self.assertNotIn("argv", output, "Globals found argv")
self.assertNotIn("test_var", output, "Globals found test_var")
self.assertIn("g_var", output, "Globals didn't find g_var")
def check_frame_variable_errors(self, thread, error_strings):
command_result = lldb.SBCommandReturnObject()
interp = self.dbg.GetCommandInterpreter()
result = interp.HandleCommand("frame variable", command_result)
self.assertEqual(
result, lldb.eReturnStatusFailed, "frame var succeeded unexpectedly"
)
command_error = command_result.GetError()
frame = thread.GetFrameAtIndex(0)
var_list = frame.GetVariables(True, True, False, True)
self.assertEqual(var_list.GetSize(), 0)
api_error = var_list.GetError().GetCString()
for s in error_strings:
self.assertIn(s, command_error)
for s in error_strings:
self.assertIn(s, api_error)
@skipIfRemote
@skipUnlessDarwin
def test_darwin_dwarf_missing_obj(self):
"""
Test that if we build a binary with DWARF in .o files and we remove
the .o file for main.cpp, that we get an appropriate error when we
do 'frame variable' that explains why we aren't seeing variables.
"""
self.build(debug_info="dwarf")
exe = self.getBuildArtifact("a.out")
main_obj = self.getBuildArtifact("main.o")
os.unlink(main_obj)
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
error_strings = [
'debug map object file "',
'main.o" containing debug info does not exist, debug info will not be loaded',
]
self.check_frame_variable_errors(thread, error_strings)
@skipIfRemote
@skipUnlessDarwin
def test_darwin_dwarf_obj_mod_time_mismatch(self):
"""
Test that if we build a binary with DWARF in .o files and we update
the mod time of the .o file for main.cpp, that we get an appropriate
error when we do 'frame variable' that explains why we aren't seeing
variables.
"""
self.build(debug_info="dwarf")
exe = self.getBuildArtifact("a.out")
main_obj = self.getBuildArtifact("main.o")
time.sleep(2)
os.utime(main_obj, None)
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
error_strings = [
'debug map object file "',
'main.o" changed (actual: 0x',
", debug map: 0x",
") since this executable was linked, debug info will not be loaded",
]
self.check_frame_variable_errors(thread, error_strings)
@skipIfRemote
@skipIfWindows
def test_gline_tables_only(self):
"""
Test that if we build a binary with "-gline-tables-only" that we can
set a file and line breakpoint successfully, and get an error
letting us know that this build option was enabled when trying to
read variables.
"""
self.build(dictionary={"CFLAGS_EXTRAS": "-gline-tables-only"})
exe = self.getBuildArtifact("a.out")
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
error_strings = [
"no variable information is available in debug info for this compile unit"
]
self.check_frame_variable_errors(thread, error_strings)
@skipUnlessPlatform(["linux", "freebsd"])
@add_test_categories(["dwo"])
def test_fission_missing_dwo(self):
"""
Test that if we build a binary with "-gsplit-dwarf" that we can
set a file and line breakpoint successfully, and get an error
letting us know we were unable to load the .dwo file.
"""
self.build(dictionary={"CFLAGS_EXTRAS": "-gsplit-dwarf"})
exe = self.getBuildArtifact("a.out")
main_dwo = self.getBuildArtifact("main.dwo")
self.assertTrue(
os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo)
)
os.unlink(main_dwo)
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
error_strings = [
'unable to locate .dwo debug file "',
'main.dwo" for skeleton DIE 0x',
]
self.check_frame_variable_errors(thread, error_strings)
@skipUnlessPlatform(["linux", "freebsd"])
@add_test_categories(["dwo"])
def test_fission_invalid_dwo_objectfile(self):
"""
Test that if we build a binary with "-gsplit-dwarf" that we can
set a file and line breakpoint successfully, and get an error
letting us know we were unable to load the .dwo file because it
existed, but it wasn't a valid object file.
"""
self.build(dictionary={"CFLAGS_EXTRAS": "-gsplit-dwarf"})
exe = self.getBuildArtifact("a.out")
main_dwo = self.getBuildArtifact("main.dwo")
self.assertTrue(
os.path.exists(main_dwo), 'Make sure "%s" file exists' % (main_dwo)
)
shutil.copyfile(self.getSourcePath("main.c"), main_dwo)
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
error_strings = [
'unable to load object file for .dwo debug file "'
'main.dwo" for unit DIE 0x',
]
self.check_frame_variable_errors(thread, error_strings)