Files
clang-p2996/lldb/test/API/lang/objc/foundation/TestFoundationDisassembly.py
Pavel Labath 8b845ac5ed Recommit "[lldb] Don't dissasemble large functions by default"
This recommits f665e80c02 which was reverted in 1cbd1b8f69 for breaking
TestFoundationDisassembly.py. The fix is to use --force in the test to avoid
bailing out on large functions.

I have also doubled the large function limit to 8000 bytes (~~ 2000 insns), as
the foundation library contains a lot of large-ish functions. The intent of this
feature is to prevent accidental disassembling of enormous (multi-megabyte)
"functions", not to get in people's way.

The original commit message follows:

If we have a binary without symbol information (and without
LC_FUNCTION_STARTS, if on a mac), then we have to resort to using
heuristics to determine the function boundaries. However, these don't
always work, and so we can easily end up thinking we have functions
which are several megabytes in size. Attempting to (accidentally)
disassemble these can take a very long time spam the terminal with
thousands of lines of disassembly.

This patch works around that problem by adding a sanity check to the
disassemble command. If we are about to disassemble a function which is
larger than a certain threshold, we will refuse to disassemble such a
function unless the user explicitly specifies the number of instructions
to disassemble, uses start/stop addresses for disassembly, or passes the
(new) --force argument.

The threshold is currently fairly aggressive (4000 bytes ~~ 1000
instructions). If needed, we can increase it, or even make it
configurable.

Differential Revision: https://reviews.llvm.org/D79789
2020-05-15 11:57:48 +02:00

152 lines
5.3 KiB
Python

"""
Test the lldb disassemble command on foundation framework.
"""
import unittest2
import os
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
@skipUnlessDarwin
class FoundationDisassembleTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True
@skipIfAsan
def test_foundation_disasm(self):
"""Do 'disassemble -n func' on each and every 'Code' symbol entry from the Foundation.framework."""
self.build()
# Enable synchronous mode
self.dbg.SetAsync(False)
# Create a target by the debugger.
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.assertTrue(target, VALID_TARGET)
# 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)
foundation_framework = None
for module in target.modules:
if module.file.basename == "Foundation":
foundation_framework = module.file.fullpath
break
self.assertTrue(
foundation_framework is not None,
"Foundation.framework path located")
self.runCmd("image dump symtab '%s'" % foundation_framework)
raw_output = self.res.GetOutput()
# Now, grab every 'Code' symbol and feed it into the command:
# 'disassemble -n func'.
#
# The symbol name is on the last column and trails the flag column which
# looks like '0xhhhhhhhh', i.e., 8 hexadecimal digits.
codeRE = re.compile(r"""
\ Code\ {9} # ' Code' followed by 9 SPCs,
.* # the wildcard chars,
0x[0-9a-f]{8} # the flag column, and
\ (.+)$ # finally the function symbol.
""", re.VERBOSE)
for line in raw_output.split(os.linesep):
match = codeRE.search(line)
if match:
func = match.group(1)
self.runCmd('image lookup -s "%s"' % func)
self.runCmd('disassemble --force -n "%s"' % func)
@skipIfAsan
def test_simple_disasm(self):
"""Test the lldb 'disassemble' command"""
self.build()
# Create a target by the debugger.
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self.assertTrue(target, VALID_TARGET)
# Stop at +[NSString stringWithFormat:].
symbol_name = "+[NSString stringWithFormat:]"
break_results = lldbutil.run_break_set_command(
self, "_regexp-break %s" % (symbol_name))
lldbutil.check_breakpoint_result(
self,
break_results,
symbol_name=symbol_name,
num_locations=1)
# Stop at -[MyString initWithNSString:].
lldbutil.run_break_set_by_symbol(
self,
'-[MyString initWithNSString:]',
num_expected_locations=1,
sym_exact=True)
# Stop at the "description" selector.
lldbutil.run_break_set_by_selector(
self,
'description',
num_expected_locations=1,
module_name='a.out')
# Stop at -[NSAutoreleasePool release].
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)
# First stop is +[NSString stringWithFormat:].
self.expect(
"thread backtrace",
"Stop at +[NSString stringWithFormat:]",
substrs=["Foundation`+[NSString stringWithFormat:]"])
# Do the disassemble for the currently stopped function.
self.runCmd("disassemble -f")
self.runCmd("process continue")
# Skip another breakpoint for +[NSString stringWithFormat:].
self.runCmd("process continue")
# Followed by a.out`-[MyString initWithNSString:].
self.expect(
"thread backtrace",
"Stop at a.out`-[MyString initWithNSString:]",
substrs=["a.out`-[MyString initWithNSString:]"])
# Do the disassemble for the currently stopped function.
self.runCmd("disassemble -f")
self.runCmd("process continue")
# Followed by -[MyString description].
self.expect("thread backtrace", "Stop at -[MyString description]",
substrs=["a.out`-[MyString description]"])
# Do the disassemble for the currently stopped function.
self.runCmd("disassemble -f")
self.runCmd("process continue")
# Skip another breakpoint for -[MyString description].
self.runCmd("process continue")
# Followed by -[NSAutoreleasePool release].
self.expect("thread backtrace", "Stop at -[NSAutoreleasePool release]",
substrs=["Foundation`-[NSAutoreleasePool release]"])
# Do the disassemble for the currently stopped function.
self.runCmd("disassemble -f")