Jason Molenda a0c2d6e369
[lldb] Add utility to create Mach-O corefile from YAML desc (#153911)
I've wanted a utility to create a corefile for test purposes given a bit
of memory and regsters, for a while. I've written a few API tests over
the years that needed exactly this capability -- we have several one-off
Mach-O corefile creator utility in the API testsuite to do this. But
it's a lot of boilerplate when you only want to specify some register
contents and memory contents, to create an API test.

This adds yaml2mach-core, a tool that should build on any system, takes
a yaml description of register values for one or more threads,
optionally memory values for one or more memory regions, and can take a
list of UUIDs that will be added as LC_NOTE "load binary" metadata to
the corefile so binaries can be loaded into virtual address space in a
test scenario.

The format of the yaml file looks like

```
cpu: armv7m

# optionally specify the number of bits used for addressing
# (this line is from a different, 64-bit, yaml file)
addressable-bits: 
    num-bits: 39

# optionally specify one or more binary UUID and slide/virtual address to be added as an LC_NOTE
# (this line is from a different, 64-bit, yaml file)
binaries:
  - name: debug-binary.development
    uuid: 67942352-5857-3D3D-90CB-A3F80BA67B04
    virtual-address: 0xfffffff01840c000

threads:
  - regsets: 
     - flavor: gpr 
        registers: [{name: sp, value: 0x2000fe70}, {name: r7, value: 0x2000fe80}, 
                    {name: pc, value: 0x0020392c}, {name: lr, value: 0x0020392d}]

memory-regions:
  # stack memory
  - addr: 0x2000fe70 
    UInt32: [ 0x0000002a, 0x20010e58, 0x00203923, 
              0x00000001, 0x2000fe88, 0x00203911, 
              0x2000ffdc, 0xfffffff9 ]
  # instructions of a function
  - addr: 0x203910 
     UInt8: [ 0xf8, 0xb5, 0x04, 0xaf, 0x06, 0x4c, 0x07, 0x49, 
              0x74, 0xf0, 0x2e, 0xf8, 0x01, 0xac, 0x74, 0xf0 ]
```

and that's all that is needed to specify a corefile where four register
values are specified (the others will be set to 0), and two memory
regions will be emitted.

The memory can be specified as an array of UInt8, UInt32, or UInt64, I
anticipate that some of these corefiles may have stack values
constructed manually and it may be simpler for a human to write them in
a particular grouping of values.

I needed this utility for an upcoming patch for ARM Cortex-M processors,
to create a test for the change. I took the opportunity to remove two of
the "trivial mach-o corefile" creator utilities I've written in the
past, which also restricted the tests to only run on Darwin systems
because I was using the system headers for Mach-O constant values.

rdar://110663219
2025-09-04 11:42:26 -07:00

188 lines
4.5 KiB
Python

"""
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
See https://llvm.org/LICENSE.txt for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Provides the configuration class, which holds all information related to
how this invocation of the test suite should be run.
"""
# System modules
import os
# Third-party modules
import unittest
# LLDB Modules
import lldbsuite
# The test suite.
suite = unittest.TestSuite()
# The list of categories we said we care about
categories_list = None
# set to true if we are going to use categories for cherry-picking test cases
use_categories = False
# Categories we want to skip
skip_categories = []
# Categories we expect to fail
xfail_categories = []
# use this to track per-category failures
failures_per_category = {}
# The path to LLDB.framework is optional.
lldb_framework_path = None
# Test suite repeat count. Can be overwritten with '-# count'.
count = 1
# The 'arch' and 'compiler' can be specified via command line.
arch = None
compiler = None
dsymutil = None
sdkroot = None
make_path = None
# Allow specifying a triple for cross compilation.
triple = None
# The overriden dwarf verison.
# Don't use this to test the current compiler's
# DWARF version, as this won't be set if the
# version isn't overridden.
# Use lldbplatformutils.getDwarfVersion() instead.
dwarf_version = 0
# Any overridden settings.
settings = []
# Path to the FileCheck testing tool. Not optional.
filecheck = None
# Path to the yaml2obj tool. Not optional.
yaml2obj = None
# Path to the yaml2macho-core tool. Not optional.
yaml2macho_core = None
# The arch might dictate some specific CFLAGS to be passed to the toolchain to build
# the inferior programs. The global variable cflags_extras provides a hook to do
# just that.
cflags_extras = ""
# The filters (testclass.testmethod) used to admit tests into our test suite.
filters = []
# The regular expression pattern to match against eligible filenames as
# our test cases.
regexp = None
# Sets of tests which are excluded at runtime
skip_tests = None
xfail_tests = None
# Set this flag if there is any session info dumped during the test run.
sdir_has_content = False
# svn_info stores the output from 'svn info lldb.base.dir'.
svn_info = ""
# Default verbosity is 0.
verbose = 0
# By default, search from the script directory.
# We can't use sys.path[0] to determine the script directory
# because it doesn't work under a debugger
testdirs = [lldbsuite.lldb_test_root]
# The root of the test case tree (where the actual tests reside, not the test
# infrastructure).
test_src_root = lldbsuite.lldb_test_root
# Separator string.
separator = "-" * 70
failed = False
# LLDB Remote platform setting
lldb_platform_name = None
lldb_platform_url = None
lldb_platform_working_dir = None
lldb_platform_available_ports = None
# Apple SDK
apple_sdk = None
# The base directory in which the tests are being built.
test_build_dir = None
# The clang module cache directory used by lldb.
lldb_module_cache_dir = None
# The clang module cache directory used by clang.
clang_module_cache_dir = None
# Test results handling globals
test_result = None
# The names of all tests. Used to assert we don't have two tests with the
# same base name.
all_tests = set()
# Path to LLVM tools to be used by tests.
llvm_tools_dir = None
# LLDB library directory.
lldb_libs_dir = None
lldb_obj_root = None
libcxx_include_dir = None
libcxx_include_target_dir = None
libcxx_library_dir = None
# A plugin whose tests will be enabled, like intel-pt.
enabled_plugins = []
# the build type of lldb
# Typical values include Debug, Release, RelWithDebInfo and MinSizeRel
cmake_build_type = None
def shouldSkipBecauseOfCategories(test_categories):
if use_categories:
if (
len(test_categories) == 0
or len(categories_list & set(test_categories)) == 0
):
return True
for category in skip_categories:
if category in test_categories:
return True
return False
def get_filecheck_path():
"""
Get the path to the FileCheck testing tool.
"""
if filecheck and os.path.lexists(filecheck):
return filecheck
def get_yaml2obj_path():
"""
Get the path to the yaml2obj tool.
"""
if yaml2obj and os.path.lexists(yaml2obj):
return yaml2obj
def get_yaml2macho_core_path():
"""
Get the path to the yaml2macho-core tool.
"""
if yaml2macho_core and os.path.lexists(yaml2macho_core):
return yaml2macho_core