+++ /dev/null
-#.rst:
-# FindLibEdit
-# -----------
-#
-# Find libedit library and headers
-#
-# The module defines the following variables:
-#
-# ::
-#
-# LibEdit_FOUND - true if libedit was found
-# LibEdit_INCLUDE_DIRS - include search path
-# LibEdit_LIBRARIES - libraries to link
-# LibEdit_VERSION_STRING - version number
-
-if(LibEdit_INCLUDE_DIRS AND LibEdit_LIBRARIES)
- set(LibEdit_FOUND TRUE)
-else()
- find_package(PkgConfig QUIET)
- pkg_check_modules(PC_LIBEDIT QUIET libedit)
-
- find_path(LibEdit_INCLUDE_DIRS
- NAMES
- histedit.h
- HINTS
- ${PC_LIBEDIT_INCLUDEDIR}
- ${PC_LIBEDIT_INCLUDE_DIRS}
- ${CMAKE_INSTALL_FULL_INCLUDEDIR})
- find_library(LibEdit_LIBRARIES
- NAMES
- edit libedit
- HINTS
- ${PC_LIBEDIT_LIBDIR}
- ${PC_LIBEDIT_LIBRARY_DIRS}
- ${CMAKE_INSTALL_FULL_LIBDIR})
-
- if(LibEdit_INCLUDE_DIRS AND EXISTS "${LibEdit_INCLUDE_DIRS}/histedit.h")
- file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h"
- libedit_major_version_str
- REGEX "^#define[ \t]+LIBEDIT_MAJOR[ \t]+[0-9]+")
- string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MAJOR[ \t]+([0-9]+)" "\\1"
- LIBEDIT_MAJOR_VERSION "${libedit_major_version_str}")
-
- file(STRINGS "${LibEdit_INCLUDE_DIRS}/histedit.h"
- libedit_minor_version_str
- REGEX "^#define[ \t]+LIBEDIT_MINOR[ \t]+[0-9]+")
- string(REGEX REPLACE "^#define[ \t]+LIBEDIT_MINOR[ \t]+([0-9]+)" "\\1"
- LIBEDIT_MINOR_VERSION "${libedit_minor_version_str}")
-
- set(LibEdit_VERSION_STRING "${libedit_major_version}.${libedit_minor_version}")
- endif()
-
- include(FindPackageHandleStandardArgs)
- find_package_handle_standard_args(LibEdit
- FOUND_VAR
- LibEdit_FOUND
- REQUIRED_VARS
- LibEdit_INCLUDE_DIRS
- LibEdit_LIBRARIES
- VERSION_VAR
- LibEdit_VERSION_STRING)
- mark_as_advanced(LibEdit_INCLUDE_DIRS LibEdit_LIBRARIES)
-endif()
-
+++ /dev/null
-Reproducers
-===========
-
-As unbelievable as it may sound, the debugger has bugs. These bugs might
-manifest themselves as errors, missing results or even a crash. Quite often
-these bugs don't reproduce in simple, isolated scenarios. The debugger deals
-with a lot of moving parts and subtle differences can easily add up.
-
-Reproducers in LLDB improve the experience for both the users encountering bugs
-and the developers working on resolving them. The general idea consists of
-*capturing* all the information necessary to later *replay* a debug session
-while debugging the debugger.
-
-.. contents::
- :local:
-
-Usage
------
-
-Reproducers are a generic concept in LLDB and are not inherently coupled with
-the command line driver. The functionality can be used for anything that uses
-the SB API and the driver is just one example. However, because it's probably
-the most common way users interact with lldb, that's the workflow described in
-this section.
-
-Capture
-```````
-
-Until reproducer capture is enabled by default, you need to launch LLDB in
-capture mode. For the command line driver, this means passing ``--capture``.
-You cannot enable reproducer capture from within LLDB, as this would be too
-late to capture initialization of the debugger.
-
-.. code-block:: bash
-
- > lldb --capture
-
-In capture mode, LLDB will keep track of all the information it needs to replay
-the current debug session. Most data is captured lazily to limit the impact on
-performance. To create the reproducer, use the ``reproducer generate``
-sub-command. It's always possible to check the status of the reproducers with
-the ``reproducer status`` sub-command. Note that generating the reproducer
-terminates the debug session.
-
-.. code-block:: none
-
- (lldb) reproducer status
- Reproducer is in capture mode.
- (lldb) reproducer generate
- Reproducer written to '/path/to/reproducer'
- Please have a look at the directory to assess if you're willing to share the contained information.
-
-
-The resulting reproducer is a directory. It was a conscious decision to not
-compress and archive it automatically. The reproducer can contain potentially
-sensitive information like object and symbol files, their paths on disk, debug
-information, memory excerpts of the inferior process, etc.
-
-Replay
-``````
-
-It is strongly recommended to replay the reproducer locally to ensure it
-actually reproduces the expected behavior. If the reproducer doesn't behave
-correctly locally, it means there's a bug in the reproducer implementation that
-should be addressed.
-
-To replay a reproducer, simply pass its path to LLDB through the ``--replay``
-flag. It is unnecessary to pass any other command line flags. The flags that
-were passed to LLDB during capture are already part of the reproducer.
-
-.. code-block:: bash
-
- > lldb --replay /path/to/reproducer
-
-
-During replay LLDB will behave similar to batch mode. The session should be
-identical to the recorded debug session. The only expected differences are that
-the binary being debugged doesn't actually run during replay. That means that
-you won't see any of its side effects, like things being printed to the
-terminal. Another expected difference is the behavior of the ``reproducer
-generate`` command, which becomes a NOOP during replay.
-
-Augmenting a Bug Report with a Reproducer
-`````````````````````````````````````````
-
-A reproducer can significantly improve a bug report, but it in itself is not
-sufficient. Always describe the expected and unexpected behavior. Just like the
-debugger can have bugs, the reproducer can have bugs too.
-
-
-Design
-------
-
-
-Replay
-``````
-
-Reproducers support two replay modes. The main and most common mode is active
-replay. It's called active, because it's LLDB that is driving replay by calling
-the captured SB API functions one after each other. The second mode is passive
-replay. In this mode, LLDB sits idle until an SB API function is called, for
-example from Python, and then replays just this individual call.
-
-Active Replay
-^^^^^^^^^^^^^
-
-No matter how a reproducer was captured, they can always be replayed with the
-command line driver. When a reproducer is passed with the ``--replay`` flag, the
-driver short-circuits and passes off control to the reproducer infrastructure,
-effectively bypassing its normal operation. This works because the driver is
-implemented using the SB API and is therefore nothing more than a sequence of
-SB API calls.
-
-Replay is driven by the ``Registry::Replay``. As long as there's data in the
-buffer holding the API data, the next SB API function call is deserialized.
-Once the function is known, the registry can retrieve its signature, and use
-that to deserialize its arguments. The function can then be invoked, most
-commonly through the synthesized default replayer, or potentially using a
-custom defined replay function. This process continues, until more data is
-available or a replay error is encountered.
-
-During replay only a function's side effects matter. The result returned by the
-replayed function is ignored because it cannot be observed beyond the driver.
-This is sound, because anything that is passed into a subsequent API call will
-have been serialized as an input argument. This also works for SB API objects
-because the reproducers know about every object that has crossed the API
-boundary, which is true by definition for object return values.
-
-
-Passive Replay
-^^^^^^^^^^^^^^
-
-Passive replay exists to support running the API test suite against a
-reproducer. The API test suite is written in Python and tests the debugger by
-calling into its API from Python. To make this work, the API must transparently
-replay itself when called. This is what makes passive replay different from
-driver replay, where it is lldb itself that's driving replay. For passive
-replay, the driving factor is external.
-
-In order to replay API calls, the reproducers need a way to intercept them.
-Every API call is already instrumented with an ``LLDB_RECORD_*`` macro that
-captures its input arguments. Furthermore, it also contains the necessary logic
-to detect which calls cross the API boundary and should be intercepted. We were
-able to reuse all of this to implement passive replay.
-
-During passive replay is enabled, nothing happens until an SB API is called.
-Inside that API function, the macro detects whether this call should be
-replayed (i.e. crossed the API boundary). If the answer is yes, the next
-function is deserialized from the SB API data and compared to the current
-function. If the signature matches, we deserialize its input arguments and
-reinvoke the current function with the deserialized arguments. We don't need to
-do anything special to prevent us from recursively calling the replayed version
-again, as the API boundary crossing logic knows that we're still behind the API
-boundary when we re-invoked the current function.
-
-Another big difference with driver replay is the return value. While this
-didn't matter for driver replay, it's key for passive replay, because that's
-what gets checked by the test suite. Luckily, the ``LLDB_RECORD_*`` macros
-contained sufficient type information to derive the result type.
-
-Testing
--------
-
-Reproducers are tested in the following ways:
-
- - Unit tests to cover the reproducer infrastructure. There are tests for the
- provider, loader and for the reproducer instrumentation.
- - Feature specific end-to-end test cases in the ``test/Shell/Reproducer``
- directory. These tests serve as integration and regression tests for the
- reproducers infrastructure, as well as doing some sanity checking for basic
- debugger functionality.
- - The API and shell tests can be run against a replayed reproducer. The
- ``check-lldb-reproducers`` target will run the API and shell test suite
- twice: first running the test normally while capturing a reproducer and then
- a second time using the replayed session as the test input. For the shell
- tests this use a little shim (``lldb-repro``) that uses the arguments and
- current working directory to transparently generate or replay a reproducer.
- For the API tests an extra argument with the reproducer path is passed to
- ``dotest.py`` which initializes the debugger in the appropriate mode.
- Certain tests do not fit this paradigm (for example test that check the
- output of the binary being debugged) and are skipped by marking them as
- unsupported by adding ``UNSUPPORTED: lldb-repro`` to the top of the shell
- test or adding the ``skipIfReproducer`` decorator for the API tests.
-
-Knows Issues
-------------
-
-The reproducers are still a work in progress. Here's a non-exhaustive list of
-outstanding work, limitations and known issues.
-
- - The VFS cannot deal with more than one current working directory. Changing
- the current working directory during the debug session will break relative
- paths.
- - Not all SB APIs are properly instrumented. We need customer serialization
- for APIs that take buffers and lengths.
- - We leak memory during replay because the reproducer doesn't capture the end
- of an object's life time. We need to add instrumentation to the destructor
- of SB API objects.
- - The reproducer includes every file opened by LLDB. This is overkill. For
- example we do not need to capture source files for code listings. There's
- currently no way to say that some file shouldn't be included in the
- reproducer.
- - We do not yet automatically generate a reproducer on a crash. The reason is
- that generating the reproducer is too expensive to do in a signal handler.
- We should re-invoke lldb after a crash and do the heavy lifting.
.. option:: --source-quietly
- Tells the debugger to execute this one-line lldb command before any file has been loaded.
+ Tells the debugger not to echo commands while sourcing files or one-line commands provided on the command line.
.. option:: --source <file>
Alias for --script-language
+.. option:: --print-script-interpreter-info
+
+ Prints out a json dictionary with information about the scripting language interpreter.
+
.. option:: --python-path
Prints out the path to the lldb.py file for this version of lldb.
+++ /dev/null
-This document attempts to point out some best practices that prove to be helpful
-when building new test cases in the tot/test directory. Everyone is welcomed to
-add/modify contents into this file.
-
-o Do not use hard-coded line numbers in your test case. Instead, try to tag the
- line with some distinguishing pattern, and use the function line_number()
- defined in lldbtest.py which takes filename and string_to_match as arguments
- and returns the line number.
-
-As an example, take a look at test/breakpoint_conditions/main.c which has these
-two lines:
-
- return c(val); // Find the line number of c's parent call here.
-
-and
-
- return val + 3; // Find the line number of function "c" here.
-
-The Python test case TestBreakpointConditions.py uses the comment strings to
-find the line numbers during setUp(self) and use them later on to verify that
-the correct breakpoint is being stopped on and that its parent frame also has
-the correct line number as intended through the breakpoint condition.
-
-o Take advantage of the unittest framework's decorator features to properly
- mark your test class or method for platform-specific tests.
-
-As an example, take a look at test/forward/TestForwardDeclaration.py which has
-these lines:
-
- @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
- def test_with_dsym_and_run_command(self):
- """Display *bar_ptr when stopped on a function with forward declaration of struct bar."""
- self.buildDsym()
- self.forward_declaration()
-
-This tells the test harness that unless we are running "darwin", the test should
-be skipped. This is because we are asking to build the binaries with dsym debug
-info, which is only available on the darwin platforms.
-
-o Cleanup after yourself. A classic example of this can be found in test/types/
- TestFloatTypes.py:
-
- def test_float_types_with_dsym(self):
- """Test that float-type variables are displayed correctly."""
- d = {'CXX_SOURCES': 'float.cpp'}
- self.buildDsym(dictionary=d)
- self.setTearDownCleanup(dictionary=d)
- self.float_type()
-
- ...
-
- def test_double_type_with_dsym(self):
- """Test that double-type variables are displayed correctly."""
- d = {'CXX_SOURCES': 'double.cpp'}
- self.buildDsym(dictionary=d)
- self.setTearDownCleanup(dictionary=d)
- self.double_type()
-
-This tests different data structures composed of float types to verify that what
-the debugger prints out matches what the compiler does for different variables
-of these types. We're using a dictionary to pass the build parameters to the
-build system. After a particular test instance is done, it is a good idea to
-clean up the files built. This eliminates the chance that some leftover files
-can interfere with the build phase for the next test instance and render it
-invalid.
-
-TestBase.setTearDownCleanup(self, dictionary) defined in lldbtest.py is created
-to cope with this use case by taking the same build parameters in order to do
-the cleanup when we are finished with a test instance, during
-TestBase.tearDown(self).
-
-o Class-wise cleanup after yourself.
-
-TestBase.tearDownClass(cls) provides a mechanism to invoke the platform-specific
-cleanup after finishing with a test class. A test class can have more than one
-test methods, so the tearDownClass(cls) method gets run after all the test
-methods have been executed by the test harness.
-
-The default cleanup action performed by the plugins/darwin.py module invokes the
-"make clean" os command.
-
-If this default cleanup is not enough, individual class can provide an extra
-cleanup hook with a class method named classCleanup , for example,
-in test/breakpoint_command/TestBreakpointCommand.py:
-
- @classmethod
- def classCleanup(cls):
- system(["/bin/sh", "-c", "rm -f output.txt"])
-
-The 'output.txt' file gets generated during the test run, so it makes sense to
-explicitly spell out the action in the same TestBreakpointCommand.py file to do
-the cleanup instead of artificially adding it as part of the default cleanup
-action which serves to cleanup those intermediate and a.out files.
+++ /dev/null
-Links
-=====
-
-This page contains links to external resources on how to use LLDB. Being listed
-on this page is not an endorsement.
-
-## Blog Posts
-
-### [Dancing in the Debugger — A Waltz with LLDB (2014) ](https://www.objc.io/issues/19-debugging/lldb-debugging/)
-
-A high level overview of LLDB with a focus on debugging Objective-C code.
-
-## Videos
-
-### [LLDB: Beyond "po" (2019)](https://developer.apple.com/videos/play/wwdc2019/429/)
-
-LLDB is a powerful tool for exploring and debugging your app at runtime.
-Discover the various ways to display values in your app, how to format custom
-data types, and how to extend LLDB using your own Python 3 scripts.
-
-### [Advanced Debugging with Xcode and LLDB (2018)](https://developer.apple.com/videos/play/wwdc2018/412/)
-
-Discover advanced techniques, and tips and tricks for enhancing your Xcode
-debugging workflows. Learn how to take advantage of LLDB and custom breakpoints
-for more powerful debugging. Get the most out of Xcode's view debugging tools
-to solve UI issues in your app more efficiently.
-
-### [Debugging with LLDB (2012)](https://developer.apple.com/videos/play/wwdc2012/415/)
-
-LLDB is the next-generation debugger for macOS and iOS. Get an introduction to
-using LLDB via the console interface and within Xcode's graphical debugger. The
-team that created LLDB will demonstrate the latest features and improvements,
-helping you track down bugs more efficiently than ever before.
-
-### [Migrating from GDB to LLDB (2011)](https://developer.apple.com/videos/play/wwdc2011/321/)
-
-LLDB is the next-generation debugger for macOS and iOS. Discover why you'll
-want to start using LLDB in your own development, get expert tips from the team
-that created LLDB, and see how it will help you track down bugs more
-efficiently than ever before.
-
-## Books
-
-### [Advanced Apple Debugging & Reverse Engineering (2018)](https://www.raywenderlich.com/books/advanced-apple-debugging-reverse-engineering/)
-
-A book about using LLDB on Apple platforms.
-
-## Extensions
-
-### [facebook/chisel](https://github.com/facebook/chisel)
-
-Chisel is a collection of LLDB commands to assist in the debugging of iOS apps.
-
-### [DerekSelander/LLDB](https://github.com/DerekSelander/LLDB)
-
-A collection of LLDB aliases/regexes and Python scripts.
+++ /dev/null
-import os
-
-import lldb
-from lldb.plugins.scripted_process import ScriptedProcess
-
-class MyScriptedProcess(ScriptedProcess):
- def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
- super().__init__(target, args)
-
- def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
- return self.memory_regions[0]
-
- def get_thread_with_id(self, tid: int):
- return {}
-
- def get_registers_for_thread(self, tid: int):
- return {}
-
- def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
- data = lldb.SBData().CreateDataFromCString(
- self.target.GetByteOrder(),
- self.target.GetCodeByteSize(),
- "Hello, world!")
- return data
-
- def get_loaded_images(self):
- return self.loaded_images
-
- def get_process_id(self) -> int:
- return 42
-
- def should_stop(self) -> bool:
- return True
-
- def is_alive(self) -> bool:
- return True
-
-def __lldb_init_module(debugger, dict):
- if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ:
- debugger.HandleCommand(
- "process launch -C %s.%s" % (__name__,
- MyScriptedProcess.__name__))
- else:
- print("Name of the class that will manage the scripted process: '%s.%s'"
- % (__name__, MyScriptedProcess.__name__))
\ No newline at end of file
+++ /dev/null
-//===-- StringConvert.h -----------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_HOST_STRINGCONVERT_H
-#define LLDB_HOST_STRINGCONVERT_H
-
-#include <cstdint>
-
-namespace lldb_private {
-
-namespace StringConvert {
-
-/// \namespace StringConvert StringConvert.h "lldb/Host/StringConvert.h"
-/// Utility classes for converting strings into Integers
-
-int32_t ToSInt32(const char *s, int32_t fail_value = 0, int base = 0,
- bool *success_ptr = nullptr);
-
-uint32_t ToUInt32(const char *s, uint32_t fail_value = 0, int base = 0,
- bool *success_ptr = nullptr);
-
-int64_t ToSInt64(const char *s, int64_t fail_value = 0, int base = 0,
- bool *success_ptr = nullptr);
-
-uint64_t ToUInt64(const char *s, uint64_t fail_value = 0, int base = 0,
- bool *success_ptr = nullptr);
-
-double ToDouble(const char *s, double fail_value = 0.0,
- bool *success_ptr = nullptr);
-} // namespace StringConvert
-} // namespace lldb_private
-
-#endif
#include "lldb/Host/posix/HostInfoPosix.h"
#include "lldb/Utility/FileSpec.h"
#include "llvm/Support/VersionTuple.h"
+#include <optional>
namespace lldb_private {
public:
static llvm::VersionTuple GetOSVersion();
- static bool GetOSBuildString(std::string &s);
- static bool GetOSKernelDescription(std::string &s);
+ static std::optional<std::string> GetOSBuildString();
static FileSpec GetProgramFileSpec();
protected:
+++ /dev/null
-//===-- Fcntl.h -------------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// This file defines fcntl functions & structures
-
-#ifndef liblldb_Host_posix_Fcntl_h_
-#define liblldb_Host_posix_Fcntl_h_
-
-#ifdef __ANDROID__
-#include <android/api-level.h>
-#endif
-
-#include <fcntl.h>
-
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
-#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
-#endif
-
-#endif // liblldb_Host_posix_Fcntl_h_
+++ /dev/null
-//===-- TraceInstructionDumper.h --------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/TraceCursor.h"
-
-#ifndef LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H
-#define LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H
-
-namespace lldb_private {
-
-/// Class used to dump the instructions of a \a TraceCursor using its current
-/// state and granularity.
-class TraceInstructionDumper {
-public:
- /// Create a instruction dumper for the cursor.
- ///
- /// \param[in] cursor
- /// The cursor whose instructions will be dumped.
- ///
- /// \param[in] initial_index
- /// Presentation index to use for referring to the current instruction
- /// of the cursor. If the direction is forwards, the index will increase,
- /// and if the direction is backwards, the index will decrease.
- ///
- /// \param[in] raw
- /// Dump only instruction addresses without disassembly nor symbol
- /// information.
- ///
- /// \param[in] show_tsc
- /// For each instruction, print the corresponding timestamp counter if
- /// available.
- TraceInstructionDumper(lldb::TraceCursorUP &&cursor_up, int initial_index = 0,
- bool raw = false, bool show_tsc = false);
-
- /// Dump \a count instructions of the thread trace starting at the current
- /// cursor position.
- ///
- /// This effectively moves the cursor to the next unvisited position, so that
- /// a subsequent call to this method continues where it left off.
- ///
- /// \param[in] s
- /// The stream object where the instructions are printed.
- ///
- /// \param[in] count
- /// The number of instructions to print.
- void DumpInstructions(Stream &s, size_t count);
-
- /// Indicate the dumper that no more data is available in the trace.
- void SetNoMoreData();
-
- /// \return
- /// \b true if there's still more data to traverse in the trace.
- bool HasMoreData();
-
-private:
- /// Move the cursor one step.
- ///
- /// \return
- /// \b true if the cursor moved.
- bool TryMoveOneStep();
-
- lldb::TraceCursorUP m_cursor_up;
- int m_index;
- bool m_raw;
- bool m_show_tsc;
- /// If \b true, all the instructions have been traversed.
- bool m_no_more_data = false;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H
#include "lldb/lldb-private-enumerations.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Support/YAMLTraits.h"
#include <cstddef>
#include <cstdint>
#include <string>
eARM_abi_hard_float = 0x00000400
};
+ enum RISCVeflags {
+ eRISCV_rvc = 0x00000001, /// RVC, +c
+ eRISCV_float_abi_soft = 0x00000000, /// soft float
+ eRISCV_float_abi_single = 0x00000002, /// single precision floating point, +f
+ eRISCV_float_abi_double = 0x00000004, /// double precision floating point, +d
+ eRISCV_float_abi_quad = 0x00000006, /// quad precision floating point, +q
+ eRISCV_float_abi_mask = 0x00000006,
+ eRISCV_rve = 0x00000008, /// RVE, +e
+ eRISCV_tso = 0x00000010, /// RVTSO (total store ordering)
+ };
+
enum RISCVSubType {
eRISCVSubType_unknown,
eRISCVSubType_riscv32,
eRISCVSubType_riscv64,
};
+ enum LoongArchSubType {
+ eLoongArchSubType_unknown,
+ eLoongArchSubType_loongarch32,
+ eLoongArchSubType_loongarch64,
+ };
+
enum Core {
eCore_arm_generic,
eCore_arm_armv4,
eCore_riscv32,
eCore_riscv64,
+ eCore_loongarch32,
+ eCore_loongarch64,
+
eCore_uknownMach32,
eCore_uknownMach64,
/// architecture and false otherwise.
bool CharIsSignedByDefault() const;
- /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu type
- /// match between them. e.g. armv7s is not an exact match with armv7 - this
- /// would return false
+ enum MatchType : bool { CompatibleMatch, ExactMatch };
+
+ /// Compare this ArchSpec to another ArchSpec. \a match specifies the kind of
+ /// matching that is to be done. CompatibleMatch requires only a compatible
+ /// cpu type (e.g., armv7s is compatible with armv7). ExactMatch requires an
+ /// exact match (armv7s is not an exact match with armv7).
///
/// \return true if the two ArchSpecs match.
- bool IsExactMatch(const ArchSpec &rhs) const;
+ bool IsMatch(const ArchSpec &rhs, MatchType match) const;
- /// Compare an ArchSpec to another ArchSpec, requiring a compatible cpu type
- /// match between them. e.g. armv7s is compatible with armv7 - this method
- /// would return true
- ///
- /// \return true if the two ArchSpecs are compatible
- bool IsCompatibleMatch(const ArchSpec &rhs) const;
+ /// Shorthand for IsMatch(rhs, ExactMatch).
+ bool IsExactMatch(const ArchSpec &rhs) const {
+ return IsMatch(rhs, ExactMatch);
+ }
+
+ /// Shorthand for IsMatch(rhs, CompatibleMatch).
+ bool IsCompatibleMatch(const ArchSpec &rhs) const {
+ return IsMatch(rhs, CompatibleMatch);
+ }
bool IsFullySpecifiedTriple() const;
void SetFlags(const std::string &elf_abi);
protected:
- bool IsEqualTo(const ArchSpec &rhs, bool exact_match) const;
void UpdateCore();
llvm::Triple m_triple;
} // namespace lldb_private
-namespace llvm {
-namespace yaml {
-template <> struct ScalarTraits<lldb_private::ArchSpec> {
- static void output(const lldb_private::ArchSpec &, void *, raw_ostream &);
- static StringRef input(StringRef, void *, lldb_private::ArchSpec &);
- static QuotingType mustQuote(StringRef S) { return QuotingType::Double; }
-};
-} // namespace yaml
-} // namespace llvm
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ArchSpec)
-
#endif // LLDB_UTILITY_ARCHSPEC_H
+++ /dev/null
-//===-- Logging.h -----------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UTILITY_LOGGING_H
-#define LLDB_UTILITY_LOGGING_H
-
-#include <cstdint>
-
-// Log Bits specific to logging in lldb
-#define LIBLLDB_LOG_PROCESS (1u << 1)
-#define LIBLLDB_LOG_THREAD (1u << 2)
-#define LIBLLDB_LOG_DYNAMIC_LOADER (1u << 3)
-#define LIBLLDB_LOG_EVENTS (1u << 4)
-#define LIBLLDB_LOG_BREAKPOINTS (1u << 5)
-#define LIBLLDB_LOG_WATCHPOINTS (1u << 6)
-#define LIBLLDB_LOG_STEP (1u << 7)
-#define LIBLLDB_LOG_EXPRESSIONS (1u << 8)
-#define LIBLLDB_LOG_TEMPORARY (1u << 9)
-#define LIBLLDB_LOG_STATE (1u << 10)
-#define LIBLLDB_LOG_OBJECT (1u << 11)
-#define LIBLLDB_LOG_COMMUNICATION (1u << 12)
-#define LIBLLDB_LOG_CONNECTION (1u << 13)
-#define LIBLLDB_LOG_HOST (1u << 14)
-#define LIBLLDB_LOG_UNWIND (1u << 15)
-#define LIBLLDB_LOG_API (1u << 16)
-#define LIBLLDB_LOG_SCRIPT (1u << 17)
-#define LIBLLDB_LOG_COMMANDS (1U << 18)
-#define LIBLLDB_LOG_TYPES (1u << 19)
-#define LIBLLDB_LOG_SYMBOLS (1u << 20)
-#define LIBLLDB_LOG_MODULES (1u << 21)
-#define LIBLLDB_LOG_TARGET (1u << 22)
-#define LIBLLDB_LOG_MMAP (1u << 23)
-#define LIBLLDB_LOG_OS (1u << 24)
-#define LIBLLDB_LOG_PLATFORM (1u << 25)
-#define LIBLLDB_LOG_SYSTEM_RUNTIME (1u << 26)
-#define LIBLLDB_LOG_JIT_LOADER (1u << 27)
-#define LIBLLDB_LOG_LANGUAGE (1u << 28)
-#define LIBLLDB_LOG_DATAFORMATTERS (1u << 29)
-#define LIBLLDB_LOG_DEMANGLE (1u << 30)
-#define LIBLLDB_LOG_AST (1u << 31)
-#define LIBLLDB_LOG_ALL (UINT32_MAX)
-#define LIBLLDB_LOG_DEFAULT \
- (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD | LIBLLDB_LOG_DYNAMIC_LOADER | \
- LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_WATCHPOINTS | LIBLLDB_LOG_STEP | \
- LIBLLDB_LOG_STATE | LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_TARGET | \
- LIBLLDB_LOG_COMMANDS)
-
-namespace lldb_private {
-
-class Log;
-
-Log *GetLogIfAllCategoriesSet(uint32_t mask);
-
-Log *GetLogIfAnyCategoriesSet(uint32_t mask);
-
-void InitializeLldbChannel();
-
-} // namespace lldb_private
-
-#endif // LLDB_UTILITY_LOGGING_H
+++ /dev/null
-//===-- Reproducer.h --------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UTILITY_REPRODUCER_H
-#define LLDB_UTILITY_REPRODUCER_H
-
-#include "lldb/Utility/FileSpec.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/Support/YAMLTraits.h"
-
-#include <mutex>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace lldb_private {
-class UUID;
-namespace repro {
-
-class Reproducer;
-
-enum class ReproducerMode {
- Capture,
- Replay,
- PassiveReplay,
- Off,
-};
-
-/// The provider defines an interface for generating files needed for
-/// reproducing.
-///
-/// Different components will implement different providers.
-class ProviderBase {
-public:
- virtual ~ProviderBase() = default;
-
- const FileSpec &GetRoot() const { return m_root; }
-
- /// The Keep method is called when it is decided that we need to keep the
- /// data in order to provide a reproducer.
- virtual void Keep(){};
-
- /// The Discard method is called when it is decided that we do not need to
- /// keep any information and will not generate a reproducer.
- virtual void Discard(){};
-
- // Returns the class ID for this type.
- static const void *ClassID() { return &ID; }
-
- // Returns the class ID for the dynamic type of this Provider instance.
- virtual const void *DynamicClassID() const = 0;
-
- virtual llvm::StringRef GetName() const = 0;
- virtual llvm::StringRef GetFile() const = 0;
-
-protected:
- ProviderBase(const FileSpec &root) : m_root(root) {}
-
-private:
- /// Every provider knows where to dump its potential files.
- FileSpec m_root;
-
- virtual void anchor();
- static char ID;
-};
-
-template <typename ThisProviderT> class Provider : public ProviderBase {
-public:
- static const void *ClassID() { return &ThisProviderT::ID; }
-
- const void *DynamicClassID() const override { return &ThisProviderT::ID; }
-
- llvm::StringRef GetName() const override { return ThisProviderT::Info::name; }
- llvm::StringRef GetFile() const override { return ThisProviderT::Info::file; }
-
-protected:
- using ProviderBase::ProviderBase; // Inherit constructor.
-};
-
-/// The generator is responsible for the logic needed to generate a
-/// reproducer. For doing so it relies on providers, who serialize data that
-/// is necessary for reproducing a failure.
-class Generator final {
-
-public:
- Generator(FileSpec root);
- ~Generator();
-
- /// Method to indicate we want to keep the reproducer. If reproducer
- /// generation is disabled, this does nothing.
- void Keep();
-
- /// Method to indicate we do not want to keep the reproducer. This is
- /// unaffected by whether or not generation reproduction is enabled, as we
- /// might need to clean up files already written to disk.
- void Discard();
-
- /// Enable or disable auto generate.
- void SetAutoGenerate(bool b);
-
- /// Return whether auto generate is enabled.
- bool IsAutoGenerate() const;
-
- /// Create and register a new provider.
- template <typename T> T *Create() {
- std::unique_ptr<ProviderBase> provider = std::make_unique<T>(m_root);
- return static_cast<T *>(Register(std::move(provider)));
- }
-
- /// Get an existing provider.
- template <typename T> T *Get() {
- auto it = m_providers.find(T::ClassID());
- if (it == m_providers.end())
- return nullptr;
- return static_cast<T *>(it->second.get());
- }
-
- /// Get a provider if it exists, otherwise create it.
- template <typename T> T &GetOrCreate() {
- auto *provider = Get<T>();
- if (provider)
- return *provider;
- return *Create<T>();
- }
-
- const FileSpec &GetRoot() const;
-
-private:
- friend Reproducer;
-
- ProviderBase *Register(std::unique_ptr<ProviderBase> provider);
-
- /// Builds and index with provider info.
- void AddProvidersToIndex();
-
- /// Map of provider IDs to provider instances.
- llvm::DenseMap<const void *, std::unique_ptr<ProviderBase>> m_providers;
- std::mutex m_providers_mutex;
-
- /// The reproducer root directory.
- FileSpec m_root;
-
- /// Flag to ensure that we never call both keep and discard.
- bool m_done = false;
-
- /// Flag to auto generate a reproducer when it would otherwise be discarded.
- bool m_auto_generate = false;
-};
-
-class Loader final {
-public:
- Loader(FileSpec root, bool passive = false);
-
- template <typename T> FileSpec GetFile() {
- if (!HasFile(T::file))
- return {};
-
- return GetRoot().CopyByAppendingPathComponent(T::file);
- }
-
- template <typename T> llvm::Expected<std::string> LoadBuffer() {
- FileSpec file = GetFile<typename T::Info>();
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
- llvm::vfs::getRealFileSystem()->getBufferForFile(file.GetPath());
- if (!buffer)
- return llvm::errorCodeToError(buffer.getError());
- return (*buffer)->getBuffer().str();
- }
-
- llvm::Error LoadIndex();
-
- const FileSpec &GetRoot() const { return m_root; }
-
- bool IsPassiveReplay() const { return m_passive_replay; }
-
-private:
- bool HasFile(llvm::StringRef file);
-
- FileSpec m_root;
- std::vector<std::string> m_files;
- bool m_loaded;
- bool m_passive_replay;
-};
-
-/// The reproducer enables clients to obtain access to the Generator and
-/// Loader.
-class Reproducer {
-public:
- static Reproducer &Instance();
- static llvm::Error Initialize(ReproducerMode mode,
- llvm::Optional<FileSpec> root);
- static void Initialize();
- static bool Initialized();
- static void Terminate();
-
- Reproducer() = default;
-
- Generator *GetGenerator();
- Loader *GetLoader();
-
- const Generator *GetGenerator() const;
- const Loader *GetLoader() const;
-
- FileSpec GetReproducerPath() const;
-
- bool IsCapturing() { return static_cast<bool>(m_generator); };
- bool IsReplaying() { return static_cast<bool>(m_loader); };
-
-protected:
- llvm::Error SetCapture(llvm::Optional<FileSpec> root);
- llvm::Error SetReplay(llvm::Optional<FileSpec> root, bool passive = false);
-
-private:
- static llvm::Optional<Reproducer> &InstanceImpl();
-
- llvm::Optional<Generator> m_generator;
- llvm::Optional<Loader> m_loader;
-
- mutable std::mutex m_mutex;
-};
-
-class Verifier {
-public:
- Verifier(Loader *loader) : m_loader(loader) {}
- void Verify(llvm::function_ref<void(llvm::StringRef)> error_callback,
- llvm::function_ref<void(llvm::StringRef)> warning_callback,
- llvm::function_ref<void(llvm::StringRef)> note_callback) const;
-
-private:
- Loader *m_loader;
-};
-
-struct ReplayOptions {
- bool verify = true;
- bool check_version = true;
-};
-
-llvm::Error Finalize(Loader *loader);
-llvm::Error Finalize(const FileSpec &root);
-
-} // namespace repro
-} // namespace lldb_private
-
-#endif // LLDB_UTILITY_REPRODUCER_H
+++ /dev/null
-//===-- ReproducerInstrumentation.h -----------------------------*- C++ -*-===//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H
-#define LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H
-
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/Logging.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/ErrorHandling.h"
-
-#include <map>
-#include <thread>
-#include <type_traits>
-
-template <typename T,
- typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
-inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
- ss << t;
-}
-
-template <typename T, typename std::enable_if<!std::is_fundamental<T>::value,
- int>::type = 0>
-inline void stringify_append(llvm::raw_string_ostream &ss, const T &t) {
- ss << &t;
-}
-
-template <typename T>
-inline void stringify_append(llvm::raw_string_ostream &ss, T *t) {
- ss << reinterpret_cast<void *>(t);
-}
-
-template <typename T>
-inline void stringify_append(llvm::raw_string_ostream &ss, const T *t) {
- ss << reinterpret_cast<const void *>(t);
-}
-
-template <>
-inline void stringify_append<char>(llvm::raw_string_ostream &ss,
- const char *t) {
- ss << '\"' << t << '\"';
-}
-
-template <>
-inline void stringify_append<std::nullptr_t>(llvm::raw_string_ostream &ss,
- const std::nullptr_t &t) {
- ss << "\"nullptr\"";
-}
-
-template <typename Head>
-inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head) {
- stringify_append(ss, head);
-}
-
-template <typename Head, typename... Tail>
-inline void stringify_helper(llvm::raw_string_ostream &ss, const Head &head,
- const Tail &... tail) {
- stringify_append(ss, head);
- ss << ", ";
- stringify_helper(ss, tail...);
-}
-
-template <typename... Ts> inline std::string stringify_args(const Ts &... ts) {
- std::string buffer;
- llvm::raw_string_ostream ss(buffer);
- stringify_helper(ss, ts...);
- return ss.str();
-}
-
-// Define LLDB_REPRO_INSTR_TRACE to trace to stderr instead of LLDB's log
-// infrastructure. This is useful when you need to see traces before the logger
-// is initialized or enabled.
-// #define LLDB_REPRO_INSTR_TRACE
-
-#ifdef LLDB_REPRO_INSTR_TRACE
-inline llvm::raw_ostream &this_thread_id() {
- size_t tid = std::hash<std::thread::id>{}(std::this_thread::get_id());
- return llvm::errs().write_hex(tid) << " :: ";
-}
-#endif
-
-#define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \
- R.Register<Class * Signature>(&construct<Class Signature>::record, "", \
- #Class, #Class, #Signature)
-
-#define LLDB_REGISTER_METHOD(Result, Class, Method, Signature) \
- R.Register( \
- &invoke<Result(Class::*) Signature>::method<(&Class::Method)>::record, \
- #Result, #Class, #Method, #Signature)
-
-#define LLDB_REGISTER_METHOD_CONST(Result, Class, Method, Signature) \
- R.Register(&invoke<Result(Class::*) \
- Signature const>::method<(&Class::Method)>::record, \
- #Result, #Class, #Method, #Signature)
-
-#define LLDB_REGISTER_STATIC_METHOD(Result, Class, Method, Signature) \
- R.Register(&invoke<Result(*) Signature>::method<(&Class::Method)>::record, \
- #Result, #Class, #Method, #Signature)
-
-#define LLDB_REGISTER_CHAR_PTR_METHOD_STATIC(Result, Class, Method) \
- R.Register( \
- &invoke<Result (*)(char *, size_t)>::method<(&Class::Method)>::record, \
- &invoke_char_ptr<Result (*)(char *, \
- size_t)>::method<(&Class::Method)>::record, \
- #Result, #Class, #Method, "(char*, size_t");
-
-#define LLDB_REGISTER_CHAR_PTR_METHOD(Result, Class, Method) \
- R.Register(&invoke<Result (Class::*)(char *, size_t)>::method<( \
- &Class::Method)>::record, \
- &invoke_char_ptr<Result (Class::*)(char *, size_t)>::method<( \
- &Class::Method)>::record, \
- #Result, #Class, #Method, "(char*, size_t");
-
-#define LLDB_REGISTER_CHAR_PTR_METHOD_CONST(Result, Class, Method) \
- R.Register(&invoke<Result (Class::*)(char *, size_t) \
- const>::method<(&Class::Method)>::record, \
- &invoke_char_ptr<Result (Class::*)(char *, size_t) \
- const>::method<(&Class::Method)>::record, \
- #Result, #Class, #Method, "(char*, size_t");
-
-#define LLDB_CONSTRUCT_(T, Class, ...) \
- lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION); \
- lldb_private::repro::construct<T>::handle(LLDB_GET_INSTRUMENTATION_DATA(), \
- _recorder, Class, __VA_ARGS__);
-
-#define LLDB_RECORD_CONSTRUCTOR(Class, Signature, ...) \
- LLDB_CONSTRUCT_(Class Signature, this, __VA_ARGS__)
-
-#define LLDB_RECORD_CONSTRUCTOR_NO_ARGS(Class) \
- LLDB_CONSTRUCT_(Class(), this, lldb_private::repro::EmptyArg())
-
-#define LLDB_RECORD_(T1, T2, ...) \
- lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \
- stringify_args(__VA_ARGS__)); \
- if (lldb_private::repro::InstrumentationData _data = \
- LLDB_GET_INSTRUMENTATION_DATA()) { \
- if (lldb_private::repro::Serializer *_serializer = \
- _data.GetSerializer()) { \
- _recorder.Record(*_serializer, _data.GetRegistry(), \
- &lldb_private::repro::invoke<T1>::method<T2>::record, \
- __VA_ARGS__); \
- } else if (lldb_private::repro::Deserializer *_deserializer = \
- _data.GetDeserializer()) { \
- if (_recorder.ShouldCapture()) { \
- return lldb_private::repro::invoke<T1>::method<T2>::replay( \
- _recorder, *_deserializer, _data.GetRegistry()); \
- } \
- } \
- }
-
-#define LLDB_RECORD_METHOD(Result, Class, Method, Signature, ...) \
- LLDB_RECORD_(Result(Class::*) Signature, (&Class::Method), this, __VA_ARGS__)
-
-#define LLDB_RECORD_METHOD_CONST(Result, Class, Method, Signature, ...) \
- LLDB_RECORD_(Result(Class::*) Signature const, (&Class::Method), this, \
- __VA_ARGS__)
-
-#define LLDB_RECORD_METHOD_NO_ARGS(Result, Class, Method) \
- LLDB_RECORD_(Result (Class::*)(), (&Class::Method), this)
-
-#define LLDB_RECORD_METHOD_CONST_NO_ARGS(Result, Class, Method) \
- LLDB_RECORD_(Result (Class::*)() const, (&Class::Method), this)
-
-#define LLDB_RECORD_STATIC_METHOD(Result, Class, Method, Signature, ...) \
- LLDB_RECORD_(Result(*) Signature, (&Class::Method), __VA_ARGS__)
-
-#define LLDB_RECORD_STATIC_METHOD_NO_ARGS(Result, Class, Method) \
- LLDB_RECORD_(Result (*)(), (&Class::Method), lldb_private::repro::EmptyArg())
-
-#define LLDB_RECORD_CHAR_PTR_(T1, T2, StrOut, ...) \
- lldb_private::repro::Recorder _recorder(LLVM_PRETTY_FUNCTION, \
- stringify_args(__VA_ARGS__)); \
- if (lldb_private::repro::InstrumentationData _data = \
- LLDB_GET_INSTRUMENTATION_DATA()) { \
- if (lldb_private::repro::Serializer *_serializer = \
- _data.GetSerializer()) { \
- _recorder.Record(*_serializer, _data.GetRegistry(), \
- &lldb_private::repro::invoke<T1>::method<(T2)>::record, \
- __VA_ARGS__); \
- } else if (lldb_private::repro::Deserializer *_deserializer = \
- _data.GetDeserializer()) { \
- if (_recorder.ShouldCapture()) { \
- return lldb_private::repro::invoke_char_ptr<T1>::method<T2>::replay( \
- _recorder, *_deserializer, _data.GetRegistry(), StrOut); \
- } \
- } \
- }
-
-#define LLDB_RECORD_CHAR_PTR_METHOD(Result, Class, Method, Signature, StrOut, \
- ...) \
- LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature, (&Class::Method), StrOut, \
- this, __VA_ARGS__)
-
-#define LLDB_RECORD_CHAR_PTR_METHOD_CONST(Result, Class, Method, Signature, \
- StrOut, ...) \
- LLDB_RECORD_CHAR_PTR_(Result(Class::*) Signature const, (&Class::Method), \
- StrOut, this, __VA_ARGS__)
-
-#define LLDB_RECORD_CHAR_PTR_STATIC_METHOD(Result, Class, Method, Signature, \
- StrOut, ...) \
- LLDB_RECORD_CHAR_PTR_(Result(*) Signature, (&Class::Method), StrOut, \
- __VA_ARGS__)
-
-#define LLDB_RECORD_RESULT(Result) _recorder.RecordResult(Result, true);
-
-/// The LLDB_RECORD_DUMMY macro is special because it doesn't actually record
-/// anything. It's used to track API boundaries when we cannot record for
-/// technical reasons.
-#define LLDB_RECORD_DUMMY(Result, Class, Method, Signature, ...) \
- lldb_private::repro::Recorder _recorder;
-
-#define LLDB_RECORD_DUMMY_NO_ARGS(Result, Class, Method) \
- lldb_private::repro::Recorder _recorder;
-
-namespace lldb_private {
-namespace repro {
-
-template <class T>
-struct is_trivially_serializable
- : std::integral_constant<bool, std::is_fundamental<T>::value ||
- std::is_enum<T>::value> {};
-
-/// Mapping between serialized indices and their corresponding objects.
-///
-/// This class is used during replay to map indices back to in-memory objects.
-///
-/// When objects are constructed, they are added to this mapping using
-/// AddObjectForIndex.
-///
-/// When an object is passed to a function, its index is deserialized and
-/// AddObjectForIndex returns the corresponding object. If there is no object
-/// for the given index, a nullptr is returend. The latter is valid when custom
-/// replay code is in place and the actual object is ignored.
-class IndexToObject {
-public:
- /// Returns an object as a pointer for the given index or nullptr if not
- /// present in the map.
- template <typename T> T *GetObjectForIndex(unsigned idx) {
- assert(idx != 0 && "Cannot get object for sentinel");
- void *object = GetObjectForIndexImpl(idx);
- return static_cast<T *>(object);
- }
-
- /// Adds a pointer to an object to the mapping for the given index.
- template <typename T> T *AddObjectForIndex(unsigned idx, T *object) {
- AddObjectForIndexImpl(
- idx, static_cast<void *>(
- const_cast<typename std::remove_const<T>::type *>(object)));
- return object;
- }
-
- /// Adds a reference to an object to the mapping for the given index.
- template <typename T> T &AddObjectForIndex(unsigned idx, T &object) {
- AddObjectForIndexImpl(
- idx, static_cast<void *>(
- const_cast<typename std::remove_const<T>::type *>(&object)));
- return object;
- }
-
- /// Get all objects sorted by their index.
- std::vector<void *> GetAllObjects() const;
-
-private:
- /// Helper method that does the actual lookup. The void* result is later cast
- /// by the caller.
- void *GetObjectForIndexImpl(unsigned idx);
-
- /// Helper method that does the actual insertion.
- void AddObjectForIndexImpl(unsigned idx, void *object);
-
- /// Keeps a mapping between indices and their corresponding object.
- llvm::DenseMap<unsigned, void *> m_mapping;
-};
-
-/// We need to differentiate between pointers to fundamental and
-/// non-fundamental types. See the corresponding Deserializer::Read method
-/// for the reason why.
-struct PointerTag {};
-struct ReferenceTag {};
-struct ValueTag {};
-struct FundamentalPointerTag {};
-struct FundamentalReferenceTag {};
-
-/// Return the deserialization tag for the given type T.
-template <class T> struct serializer_tag {
- typedef typename std::conditional<std::is_trivially_copyable<T>::value,
- ValueTag, ReferenceTag>::type type;
-};
-template <class T> struct serializer_tag<T *> {
- typedef
- typename std::conditional<std::is_fundamental<T>::value,
- FundamentalPointerTag, PointerTag>::type type;
-};
-template <class T> struct serializer_tag<T &> {
- typedef typename std::conditional<std::is_fundamental<T>::value,
- FundamentalReferenceTag, ReferenceTag>::type
- type;
-};
-
-/// Deserializes data from a buffer. It is used to deserialize function indices
-/// to replay, their arguments and return values.
-///
-/// Fundamental types and strings are read by value. Objects are read by their
-/// index, which get translated by the IndexToObject mapping maintained in
-/// this class.
-///
-/// Additional bookkeeping with regards to the IndexToObject is required to
-/// deserialize objects. When a constructor is run or an object is returned by
-/// value, we need to capture the object and add it to the index together with
-/// its index. This is the job of HandleReplayResult(Void).
-class Deserializer {
-public:
- Deserializer(llvm::StringRef buffer) : m_buffer(buffer) {}
-
- /// Returns true when the buffer has unread data.
- bool HasData(unsigned size) { return size <= m_buffer.size(); }
-
- /// Deserialize and interpret value as T.
- template <typename T> T Deserialize() {
- T t = Read<T>(typename serializer_tag<T>::type());
-#ifdef LLDB_REPRO_INSTR_TRACE
- llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> "
- << stringify_args(t) << "\n";
-#endif
- return t;
- }
-
- template <typename T> const T &HandleReplayResult(const T &t) {
- CheckSequence(Deserialize<unsigned>());
- unsigned result = Deserialize<unsigned>();
- if (is_trivially_serializable<T>::value)
- return t;
- // We need to make a copy as the original object might go out of scope.
- return *m_index_to_object.AddObjectForIndex(result, new T(t));
- }
-
- /// Store the returned value in the index-to-object mapping.
- template <typename T> T &HandleReplayResult(T &t) {
- CheckSequence(Deserialize<unsigned>());
- unsigned result = Deserialize<unsigned>();
- if (is_trivially_serializable<T>::value)
- return t;
- // We need to make a copy as the original object might go out of scope.
- return *m_index_to_object.AddObjectForIndex(result, new T(t));
- }
-
- /// Store the returned value in the index-to-object mapping.
- template <typename T> T *HandleReplayResult(T *t) {
- CheckSequence(Deserialize<unsigned>());
- unsigned result = Deserialize<unsigned>();
- if (is_trivially_serializable<T>::value)
- return t;
- return m_index_to_object.AddObjectForIndex(result, t);
- }
-
- /// All returned types are recorded, even when the function returns a void.
- /// The latter requires special handling.
- void HandleReplayResultVoid() {
- CheckSequence(Deserialize<unsigned>());
- unsigned result = Deserialize<unsigned>();
- assert(result == 0);
- (void)result;
- }
-
- std::vector<void *> GetAllObjects() const {
- return m_index_to_object.GetAllObjects();
- }
-
- void SetExpectedSequence(unsigned sequence) {
- m_expected_sequence = sequence;
- }
-
-private:
- template <typename T> T Read(ValueTag) {
- assert(HasData(sizeof(T)));
- T t;
- std::memcpy(reinterpret_cast<char *>(&t), m_buffer.data(), sizeof(T));
- m_buffer = m_buffer.drop_front(sizeof(T));
- return t;
- }
-
- template <typename T> T Read(PointerTag) {
- typedef typename std::remove_pointer<T>::type UnderlyingT;
- return m_index_to_object.template GetObjectForIndex<UnderlyingT>(
- Deserialize<unsigned>());
- }
-
- template <typename T> T Read(ReferenceTag) {
- typedef typename std::remove_reference<T>::type UnderlyingT;
- // If this is a reference to a fundamental type we just read its value.
- return *m_index_to_object.template GetObjectForIndex<UnderlyingT>(
- Deserialize<unsigned>());
- }
-
- /// This method is used to parse references to fundamental types. Because
- /// they're not recorded in the object table we have serialized their value.
- /// We read its value, allocate a copy on the heap, and return a pointer to
- /// the copy.
- template <typename T> T Read(FundamentalPointerTag) {
- typedef typename std::remove_pointer<T>::type UnderlyingT;
- return new UnderlyingT(Deserialize<UnderlyingT>());
- }
-
- /// This method is used to parse references to fundamental types. Because
- /// they're not recorded in the object table we have serialized their value.
- /// We read its value, allocate a copy on the heap, and return a reference to
- /// the copy.
- template <typename T> T Read(FundamentalReferenceTag) {
- // If this is a reference to a fundamental type we just read its value.
- typedef typename std::remove_reference<T>::type UnderlyingT;
- return *(new UnderlyingT(Deserialize<UnderlyingT>()));
- }
-
- /// Verify that the given sequence number matches what we expect.
- void CheckSequence(unsigned sequence);
-
- /// Mapping of indices to objects.
- IndexToObject m_index_to_object;
-
- /// Buffer containing the serialized data.
- llvm::StringRef m_buffer;
-
- /// The result's expected sequence number.
- llvm::Optional<unsigned> m_expected_sequence;
-};
-
-/// Partial specialization for C-style strings. We read the string value
-/// instead of treating it as pointer.
-template <> const char *Deserializer::Deserialize<const char *>();
-template <> const char **Deserializer::Deserialize<const char **>();
-template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>();
-template <> const void *Deserializer::Deserialize<const void *>();
-template <> char *Deserializer::Deserialize<char *>();
-template <> void *Deserializer::Deserialize<void *>();
-
-/// Helpers to auto-synthesize function replay code. It deserializes the replay
-/// function's arguments one by one and finally calls the corresponding
-/// function.
-template <typename... Remaining> struct DeserializationHelper;
-
-template <typename Head, typename... Tail>
-struct DeserializationHelper<Head, Tail...> {
- template <typename Result, typename... Deserialized> struct deserialized {
- static Result doit(Deserializer &deserializer,
- Result (*f)(Deserialized..., Head, Tail...),
- Deserialized... d) {
- return DeserializationHelper<Tail...>::
- template deserialized<Result, Deserialized..., Head>::doit(
- deserializer, f, d..., deserializer.Deserialize<Head>());
- }
- };
-};
-
-template <> struct DeserializationHelper<> {
- template <typename Result, typename... Deserialized> struct deserialized {
- static Result doit(Deserializer &deserializer, Result (*f)(Deserialized...),
- Deserialized... d) {
- return f(d...);
- }
- };
-};
-
-/// The replayer interface.
-struct Replayer {
- virtual ~Replayer() = default;
- virtual void operator()(Deserializer &deserializer) const = 0;
-};
-
-/// The default replayer deserializes the arguments and calls the function.
-template <typename Signature> struct DefaultReplayer;
-template <typename Result, typename... Args>
-struct DefaultReplayer<Result(Args...)> : public Replayer {
- DefaultReplayer(Result (*f)(Args...)) : Replayer(), f(f) {}
-
- void operator()(Deserializer &deserializer) const override {
- Replay(deserializer);
- }
-
- Result Replay(Deserializer &deserializer) const {
- return deserializer.HandleReplayResult(
- DeserializationHelper<Args...>::template deserialized<Result>::doit(
- deserializer, f));
- }
-
- Result (*f)(Args...);
-};
-
-/// Partial specialization for function returning a void type. It ignores the
-/// (absent) return value.
-template <typename... Args>
-struct DefaultReplayer<void(Args...)> : public Replayer {
- DefaultReplayer(void (*f)(Args...)) : Replayer(), f(f) {}
-
- void operator()(Deserializer &deserializer) const override {
- Replay(deserializer);
- }
-
- void Replay(Deserializer &deserializer) const {
- DeserializationHelper<Args...>::template deserialized<void>::doit(
- deserializer, f);
- deserializer.HandleReplayResultVoid();
- }
-
- void (*f)(Args...);
-};
-
-/// The registry contains a unique mapping between functions and their ID. The
-/// IDs can be serialized and deserialized to replay a function. Functions need
-/// to be registered with the registry for this to work.
-class Registry {
-private:
- struct SignatureStr {
- SignatureStr(llvm::StringRef result = {}, llvm::StringRef scope = {},
- llvm::StringRef name = {}, llvm::StringRef args = {})
- : result(result), scope(scope), name(name), args(args) {}
-
- std::string ToString() const;
-
- llvm::StringRef result;
- llvm::StringRef scope;
- llvm::StringRef name;
- llvm::StringRef args;
- };
-
-public:
- Registry() = default;
- virtual ~Registry() = default;
-
- /// Register a default replayer for a function.
- template <typename Signature>
- void Register(Signature *f, llvm::StringRef result = {},
- llvm::StringRef scope = {}, llvm::StringRef name = {},
- llvm::StringRef args = {}) {
- DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(f),
- SignatureStr(result, scope, name, args));
- }
-
- /// Register a replayer that invokes a custom function with the same
- /// signature as the replayed function.
- template <typename Signature>
- void Register(Signature *f, Signature *g, llvm::StringRef result = {},
- llvm::StringRef scope = {}, llvm::StringRef name = {},
- llvm::StringRef args = {}) {
- DoRegister(uintptr_t(f), std::make_unique<DefaultReplayer<Signature>>(g),
- SignatureStr(result, scope, name, args));
- }
-
- /// Replay functions from a file.
- bool Replay(const FileSpec &file);
-
- /// Replay functions from a buffer.
- bool Replay(llvm::StringRef buffer);
-
- /// Replay functions from a deserializer.
- bool Replay(Deserializer &deserializer);
-
- /// Returns the ID for a given function address.
- unsigned GetID(uintptr_t addr);
-
- /// Get the replayer matching the given ID.
- Replayer *GetReplayer(unsigned id);
-
- std::string GetSignature(unsigned id);
-
- void CheckID(unsigned expected, unsigned actual);
-
-protected:
- /// Register the given replayer for a function (and the ID mapping).
- void DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
- SignatureStr signature);
-
-private:
- /// Mapping of function addresses to replayers and their ID.
- std::map<uintptr_t, std::pair<std::unique_ptr<Replayer>, unsigned>>
- m_replayers;
-
- /// Mapping of IDs to replayer instances.
- std::map<unsigned, std::pair<Replayer *, SignatureStr>> m_ids;
-};
-
-/// Maps an object to an index for serialization. Indices are unique and
-/// incremented for every new object.
-///
-/// Indices start at 1 in order to differentiate with an invalid index (0) in
-/// the serialized buffer.
-class ObjectToIndex {
-public:
- template <typename T> unsigned GetIndexForObject(T *t) {
- return GetIndexForObjectImpl(static_cast<const void *>(t));
- }
-
-private:
- unsigned GetIndexForObjectImpl(const void *object);
-
- llvm::DenseMap<const void *, unsigned> m_mapping;
-};
-
-/// Serializes functions, their arguments and their return type to a stream.
-class Serializer {
-public:
- Serializer(llvm::raw_ostream &stream = llvm::outs()) : m_stream(stream) {}
-
- /// Recursively serialize all the given arguments.
- template <typename Head, typename... Tail>
- void SerializeAll(const Head &head, const Tail &... tail) {
- Serialize(head);
- SerializeAll(tail...);
- }
-
- void SerializeAll() { m_stream.flush(); }
-
-private:
- /// Serialize pointers. We need to differentiate between pointers to
- /// fundamental types (in which case we serialize its value) and pointer to
- /// objects (in which case we serialize their index).
- template <typename T> void Serialize(T *t) {
-#ifdef LLDB_REPRO_INSTR_TRACE
- this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
- << stringify_args(t) << "\n";
-#endif
- if (std::is_fundamental<T>::value) {
- Serialize(*t);
- } else {
- unsigned idx = m_tracker.GetIndexForObject(t);
- Serialize(idx);
- }
- }
-
- /// Serialize references. We need to differentiate between references to
- /// fundamental types (in which case we serialize its value) and references
- /// to objects (in which case we serialize their index).
- template <typename T> void Serialize(T &t) {
-#ifdef LLDB_REPRO_INSTR_TRACE
- this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
- << stringify_args(t) << "\n";
-#endif
- if (is_trivially_serializable<T>::value) {
- m_stream.write(reinterpret_cast<const char *>(&t), sizeof(T));
- } else {
- unsigned idx = m_tracker.GetIndexForObject(&t);
- Serialize(idx);
- }
- }
-
- void Serialize(const void *v) {
- // FIXME: Support void*
- }
-
- void Serialize(void *v) {
- // FIXME: Support void*
- }
-
- void Serialize(const char *t) {
-#ifdef LLDB_REPRO_INSTR_TRACE
- this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> "
- << stringify_args(t) << "\n";
-#endif
- const size_t size = t ? strlen(t) : std::numeric_limits<size_t>::max();
- Serialize(size);
- if (t) {
- m_stream << t;
- m_stream.write(0x0);
- }
- }
-
- void Serialize(const char **t) {
- size_t size = 0;
- if (!t) {
- Serialize(size);
- return;
- }
-
- // Compute the size of the array.
- const char *const *temp = t;
- while (*temp++)
- size++;
- Serialize(size);
-
- // Serialize the content of the array.
- while (*t)
- Serialize(*t++);
- }
-
- /// Serialization stream.
- llvm::raw_ostream &m_stream;
-
- /// Mapping of objects to indices.
- ObjectToIndex m_tracker;
-}; // namespace repro
-
-class InstrumentationData {
-public:
- Serializer *GetSerializer() { return m_serializer; }
- Deserializer *GetDeserializer() { return m_deserializer; }
- Registry &GetRegistry() { return *m_registry; }
-
- operator bool() {
- return (m_serializer != nullptr || m_deserializer != nullptr) &&
- m_registry != nullptr;
- }
-
- static void Initialize(Serializer &serializer, Registry ®istry);
- static void Initialize(Deserializer &serializer, Registry ®istry);
- static InstrumentationData &Instance();
-
-protected:
- friend llvm::optional_detail::OptionalStorage<InstrumentationData, true>;
- friend llvm::Optional<InstrumentationData>;
-
- InstrumentationData() = default;
- InstrumentationData(Serializer &serializer, Registry ®istry)
- : m_serializer(&serializer), m_deserializer(nullptr),
- m_registry(®istry) {}
- InstrumentationData(Deserializer &deserializer, Registry ®istry)
- : m_serializer(nullptr), m_deserializer(&deserializer),
- m_registry(®istry) {}
-
-private:
- static llvm::Optional<InstrumentationData> &InstanceImpl();
-
- Serializer *m_serializer = nullptr;
- Deserializer *m_deserializer = nullptr;
- Registry *m_registry = nullptr;
-};
-
-struct EmptyArg {};
-
-/// RAII object that records function invocations and their return value.
-///
-/// API calls are only captured when the API boundary is crossed. Once we're in
-/// the API layer, and another API function is called, it doesn't need to be
-/// recorded.
-///
-/// When a call is recored, its result is always recorded as well, even if the
-/// function returns a void. For functions that return by value, RecordResult
-/// should be used. Otherwise a sentinel value (0) will be serialized.
-///
-/// Because of the functional overlap between logging and recording API calls,
-/// this class is also used for logging.
-class Recorder {
-public:
- Recorder();
- Recorder(llvm::StringRef pretty_func, std::string &&pretty_args = {});
- ~Recorder();
-
- /// Records a single function call.
- template <typename Result, typename... FArgs, typename... RArgs>
- void Record(Serializer &serializer, Registry ®istry, Result (*f)(FArgs...),
- const RArgs &... args) {
- m_serializer = &serializer;
- if (!ShouldCapture())
- return;
-
- std::lock_guard<std::mutex> lock(g_mutex);
- unsigned sequence = GetSequenceNumber();
- unsigned id = registry.GetID(uintptr_t(f));
-
-#ifdef LLDB_REPRO_INSTR_TRACE
- Log(id);
-#endif
-
- serializer.SerializeAll(sequence);
- serializer.SerializeAll(id);
- serializer.SerializeAll(args...);
-
- if (std::is_class<typename std::remove_pointer<
- typename std::remove_reference<Result>::type>::type>::value) {
- m_result_recorded = false;
- } else {
- serializer.SerializeAll(sequence);
- serializer.SerializeAll(0);
- m_result_recorded = true;
- }
- }
-
- /// Records a single function call.
- template <typename... Args>
- void Record(Serializer &serializer, Registry ®istry, void (*f)(Args...),
- const Args &... args) {
- m_serializer = &serializer;
- if (!ShouldCapture())
- return;
-
- std::lock_guard<std::mutex> lock(g_mutex);
- unsigned sequence = GetSequenceNumber();
- unsigned id = registry.GetID(uintptr_t(f));
-
-#ifdef LLDB_REPRO_INSTR_TRACE
- Log(id);
-#endif
-
- serializer.SerializeAll(sequence);
- serializer.SerializeAll(id);
- serializer.SerializeAll(args...);
-
- // Record result.
- serializer.SerializeAll(sequence);
- serializer.SerializeAll(0);
- m_result_recorded = true;
- }
-
- /// Specializations for the no-argument methods. These are passed an empty
- /// dummy argument so the same variadic macro can be used. These methods
- /// strip the arguments before forwarding them.
- template <typename Result>
- void Record(Serializer &serializer, Registry ®istry, Result (*f)(),
- const EmptyArg &arg) {
- Record(serializer, registry, f);
- }
-
- /// Record the result of a function call.
- template <typename Result>
- Result RecordResult(Result &&r, bool update_boundary) {
- // When recording the result from the LLDB_RECORD_RESULT macro, we need to
- // update the boundary so we capture the copy constructor. However, when
- // called to record the this pointer of the (copy) constructor, the
- // boundary should not be toggled, because it is called from the
- // LLDB_RECORD_CONSTRUCTOR macro, which might be followed by other API
- // calls.
- if (update_boundary)
- UpdateBoundary();
- if (m_serializer && ShouldCapture()) {
- std::lock_guard<std::mutex> lock(g_mutex);
- assert(!m_result_recorded);
- m_serializer->SerializeAll(GetSequenceNumber());
- m_serializer->SerializeAll(r);
- m_result_recorded = true;
- }
- return std::forward<Result>(r);
- }
-
- template <typename Result, typename T>
- Result Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr,
- bool update_boundary) {
- deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
- unsigned actual_id = registry.GetID(addr);
- unsigned id = deserializer.Deserialize<unsigned>();
- registry.CheckID(id, actual_id);
- return ReplayResult<Result>(
- static_cast<DefaultReplayer<T> *>(registry.GetReplayer(id))
- ->Replay(deserializer),
- update_boundary);
- }
-
- void Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr) {
- deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
- unsigned actual_id = registry.GetID(addr);
- unsigned id = deserializer.Deserialize<unsigned>();
- registry.CheckID(id, actual_id);
- registry.GetReplayer(id)->operator()(deserializer);
- }
-
- template <typename Result>
- Result ReplayResult(Result &&r, bool update_boundary) {
- if (update_boundary)
- UpdateBoundary();
- return std::forward<Result>(r);
- }
-
- bool ShouldCapture() { return m_local_boundary; }
-
- /// Mark the current thread as a private thread and pretend that everything
- /// on this thread is behind happening behind the API boundary.
- static void PrivateThread() { g_global_boundary = true; }
-
-private:
- static unsigned GetNextSequenceNumber() { return g_sequence++; }
- unsigned GetSequenceNumber() const;
-
- template <typename T> friend struct replay;
- void UpdateBoundary() {
- if (m_local_boundary)
- g_global_boundary = false;
- }
-
-#ifdef LLDB_REPRO_INSTR_TRACE
- void Log(unsigned id) {
- this_thread_id() << "Recording " << id << ": " << m_pretty_func << " ("
- << m_pretty_args << ")\n";
- }
-#endif
-
- Serializer *m_serializer = nullptr;
-
- /// Pretty function for logging.
- llvm::StringRef m_pretty_func;
- std::string m_pretty_args;
-
- /// Whether this function call was the one crossing the API boundary.
- bool m_local_boundary = false;
-
- /// Whether the return value was recorded explicitly.
- bool m_result_recorded = true;
-
- /// The sequence number for this pair of function and result.
- unsigned m_sequence;
-
- /// Whether we're currently across the API boundary.
- static thread_local bool g_global_boundary;
-
- /// Global mutex to protect concurrent access.
- static std::mutex g_mutex;
-
- /// Unique, monotonically increasing sequence number.
- static std::atomic<unsigned> g_sequence;
-};
-
-/// To be used as the "Runtime ID" of a constructor. It also invokes the
-/// constructor when called.
-template <typename Signature> struct construct;
-template <typename Class, typename... Args> struct construct<Class(Args...)> {
- static Class *handle(lldb_private::repro::InstrumentationData data,
- lldb_private::repro::Recorder &recorder, Class *c,
- const EmptyArg &) {
- return handle(data, recorder, c);
- }
-
- static Class *handle(lldb_private::repro::InstrumentationData data,
- lldb_private::repro::Recorder &recorder, Class *c,
- Args... args) {
- if (!data)
- return nullptr;
-
- if (Serializer *serializer = data.GetSerializer()) {
- recorder.Record(*serializer, data.GetRegistry(), &record, args...);
- recorder.RecordResult(c, false);
- } else if (Deserializer *deserializer = data.GetDeserializer()) {
- if (recorder.ShouldCapture()) {
- replay(recorder, *deserializer, data.GetRegistry());
- }
- }
-
- return nullptr;
- }
-
- static Class *record(Args... args) { return new Class(args...); }
-
- static Class *replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- return recorder.Replay<Class *, Class *(Args...)>(
- deserializer, registry, uintptr_t(&record), false);
- }
-};
-
-/// To be used as the "Runtime ID" of a member function. It also invokes the
-/// member function when called.
-template <typename Signature> struct invoke;
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...)> {
- template <Result (Class::*m)(Args...)> struct method {
- static Result record(Class *c, Args... args) { return (c->*m)(args...); }
-
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- return recorder.Replay<Result, Result(Class *, Args...)>(
- deserializer, registry, uintptr_t(&record), true);
- }
- };
-};
-
-template <typename Class, typename... Args>
-struct invoke<void (Class::*)(Args...)> {
- template <void (Class::*m)(Args...)> struct method {
- static void record(Class *c, Args... args) { (c->*m)(args...); }
- static void replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- recorder.Replay(deserializer, registry, uintptr_t(&record));
- }
- };
-};
-
-template <typename Result, typename Class, typename... Args>
-struct invoke<Result (Class::*)(Args...) const> {
- template <Result (Class::*m)(Args...) const> struct method {
- static Result record(Class *c, Args... args) { return (c->*m)(args...); }
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- return recorder.Replay<Result, Result(Class *, Args...)>(
- deserializer, registry, uintptr_t(&record), true);
- }
- };
-};
-
-template <typename Class, typename... Args>
-struct invoke<void (Class::*)(Args...) const> {
- template <void (Class::*m)(Args...) const> struct method {
- static void record(Class *c, Args... args) { return (c->*m)(args...); }
- static void replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- recorder.Replay(deserializer, registry, uintptr_t(&record));
- }
- };
-};
-
-template <typename Signature> struct replay;
-
-template <typename Result, typename Class, typename... Args>
-struct replay<Result (Class::*)(Args...)> {
- template <Result (Class::*m)(Args...)> struct method {};
-};
-
-template <typename Result, typename... Args>
-struct invoke<Result (*)(Args...)> {
- template <Result (*m)(Args...)> struct method {
- static Result record(Args... args) { return (*m)(args...); }
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- return recorder.Replay<Result, Result(Args...)>(deserializer, registry,
- uintptr_t(&record), true);
- }
- };
-};
-
-template <typename... Args> struct invoke<void (*)(Args...)> {
- template <void (*m)(Args...)> struct method {
- static void record(Args... args) { return (*m)(args...); }
- static void replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry) {
- recorder.Replay(deserializer, registry, uintptr_t(&record));
- }
- };
-};
-
-/// Special handling for functions returning strings as (char*, size_t).
-/// {
-
-/// For inline replay, we ignore the arguments and use the ones from the
-/// serializer instead. This doesn't work for methods that use a char* and a
-/// size to return a string. For one these functions have a custom replayer to
-/// prevent override the input buffer. Furthermore, the template-generated
-/// deserialization is not easy to hook into.
-///
-/// The specializations below hand-implement the serialization logic for the
-/// inline replay. Instead of using the function from the registry, it uses the
-/// one passed into the macro.
-template <typename Signature> struct invoke_char_ptr;
-template <typename Result, typename Class, typename... Args>
-struct invoke_char_ptr<Result (Class::*)(Args...) const> {
- template <Result (Class::*m)(Args...) const> struct method {
- static Result record(Class *c, char *s, size_t l) {
- char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
- return (c->*m)(buffer, l);
- }
-
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry, char *str) {
- deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
- deserializer.Deserialize<unsigned>();
- Class *c = deserializer.Deserialize<Class *>();
- deserializer.Deserialize<const char *>();
- size_t l = deserializer.Deserialize<size_t>();
- return recorder.ReplayResult(
- std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
- }
- };
-};
-
-template <typename Signature> struct invoke_char_ptr;
-template <typename Result, typename Class, typename... Args>
-struct invoke_char_ptr<Result (Class::*)(Args...)> {
- template <Result (Class::*m)(Args...)> struct method {
- static Result record(Class *c, char *s, size_t l) {
- char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
- return (c->*m)(buffer, l);
- }
-
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry, char *str) {
- deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
- deserializer.Deserialize<unsigned>();
- Class *c = deserializer.Deserialize<Class *>();
- deserializer.Deserialize<const char *>();
- size_t l = deserializer.Deserialize<size_t>();
- return recorder.ReplayResult(
- std::move(deserializer.HandleReplayResult((c->*m)(str, l))), true);
- }
- };
-};
-
-template <typename Result, typename... Args>
-struct invoke_char_ptr<Result (*)(Args...)> {
- template <Result (*m)(Args...)> struct method {
- static Result record(char *s, size_t l) {
- char *buffer = reinterpret_cast<char *>(calloc(l, sizeof(char)));
- return (*m)(buffer, l);
- }
-
- static Result replay(Recorder &recorder, Deserializer &deserializer,
- Registry ®istry, char *str) {
- deserializer.SetExpectedSequence(deserializer.Deserialize<unsigned>());
- deserializer.Deserialize<unsigned>();
- deserializer.Deserialize<const char *>();
- size_t l = deserializer.Deserialize<size_t>();
- return recorder.ReplayResult(
- std::move(deserializer.HandleReplayResult((*m)(str, l))), true);
- }
- };
-};
-/// }
-
-} // namespace repro
-} // namespace lldb_private
-
-#endif // LLDB_UTILITY_REPRODUCERINSTRUMENTATION_H
+++ /dev/null
-//===-- Reproducer.h --------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UTILITY_REPRODUCER_PROVIDER_H
-#define LLDB_UTILITY_REPRODUCER_PROVIDER_H
-
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/ProcessInfo.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/Utility/UUID.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileCollector.h"
-#include "llvm/Support/YAMLTraits.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace lldb_private {
-namespace repro {
-
-/// The recorder is a small object handed out by a provider to record data. It
-/// is commonly used in combination with a MultiProvider which is meant to
-/// record information for multiple instances of the same source of data.
-class AbstractRecorder {
-protected:
- AbstractRecorder(const FileSpec &filename, std::error_code &ec)
- : m_filename(filename.GetFilename().GetStringRef()),
- m_os(filename.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF),
- m_record(true) {}
-
-public:
- const FileSpec &GetFilename() { return m_filename; }
-
- void Stop() {
- assert(m_record);
- m_record = false;
- }
-
-private:
- FileSpec m_filename;
-
-protected:
- llvm::raw_fd_ostream m_os;
- bool m_record;
-};
-
-/// Recorder that records its data as text to a file.
-class DataRecorder : public AbstractRecorder {
-public:
- DataRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
-
- static llvm::Expected<std::unique_ptr<DataRecorder>>
- Create(const FileSpec &filename);
-
- template <typename T> void Record(const T &t, bool newline = false) {
- if (!m_record)
- return;
- m_os << t;
- if (newline)
- m_os << '\n';
- m_os.flush();
- }
-};
-
-/// Recorder that records its data as YAML to a file.
-class YamlRecorder : public AbstractRecorder {
-public:
- YamlRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
-
- static llvm::Expected<std::unique_ptr<YamlRecorder>>
- Create(const FileSpec &filename);
-
- template <typename T> void Record(const T &t) {
- if (!m_record)
- return;
- llvm::yaml::Output yout(m_os);
- // The YAML traits are defined as non-const because they are used for
- // serialization and deserialization. The cast is safe because
- // serialization doesn't modify the object.
- yout << const_cast<T &>(t);
- m_os.flush();
- }
-};
-
-class FlushingFileCollector : public llvm::FileCollectorBase {
-public:
- FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path,
- std::error_code &ec);
-
-protected:
- void addFileImpl(llvm::StringRef file) override;
-
- llvm::vfs::directory_iterator
- addDirectoryImpl(const llvm::Twine &dir,
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
- std::error_code &dir_ec) override;
-
- llvm::Optional<llvm::raw_fd_ostream> m_files_os;
- llvm::Optional<llvm::raw_fd_ostream> m_dirs_os;
-};
-
-class FileProvider : public Provider<FileProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- FileProvider(const FileSpec &directory) : Provider(directory) {
- std::error_code ec;
- m_collector = std::make_shared<FlushingFileCollector>(
- directory.CopyByAppendingPathComponent("files.txt").GetPath(),
- directory.CopyByAppendingPathComponent("dirs.txt").GetPath(), ec);
- if (ec)
- m_collector.reset();
- }
-
- std::shared_ptr<llvm::FileCollectorBase> GetFileCollector() {
- return m_collector;
- }
-
- void RecordInterestingDirectory(const llvm::Twine &dir);
- void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
-
- static char ID;
-
-private:
- std::shared_ptr<FlushingFileCollector> m_collector;
-};
-
-/// Provider for the LLDB version number.
-///
-/// When the reproducer is kept, it writes the lldb version to a file named
-/// version.txt in the reproducer root.
-class VersionProvider : public Provider<VersionProvider> {
-public:
- VersionProvider(const FileSpec &directory) : Provider(directory) {}
- struct Info {
- static const char *name;
- static const char *file;
- };
- void SetVersion(std::string version) {
- assert(m_version.empty());
- m_version = std::move(version);
- }
- void Keep() override;
- std::string m_version;
- static char ID;
-};
-
-/// Abstract provider to storing directory paths.
-template <typename T> class DirectoryProvider : public repro::Provider<T> {
-public:
- DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
- void SetDirectory(std::string directory) {
- m_directory = std::move(directory);
- }
- llvm::StringRef GetDirectory() { return m_directory; }
-
- void Keep() override {
- FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- os << m_directory << "\n";
- }
-
-protected:
- std::string m_directory;
-};
-
-/// Provider for the current working directory.
-///
-/// When the reproducer is kept, it writes lldb's current working directory to
-/// a file named cwd.txt in the reproducer root.
-class WorkingDirectoryProvider
- : public DirectoryProvider<WorkingDirectoryProvider> {
-public:
- WorkingDirectoryProvider(const FileSpec &directory)
- : DirectoryProvider(directory) {
- llvm::SmallString<128> cwd;
- if (std::error_code EC = llvm::sys::fs::current_path(cwd))
- return;
- SetDirectory(std::string(cwd));
- }
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
-};
-
-/// Provider for the home directory.
-///
-/// When the reproducer is kept, it writes the user's home directory to a file
-/// a file named home.txt in the reproducer root.
-class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
-public:
- HomeDirectoryProvider(const FileSpec &directory)
- : DirectoryProvider(directory) {
- llvm::SmallString<128> home_dir;
- llvm::sys::path::home_directory(home_dir);
- SetDirectory(std::string(home_dir));
- }
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
-};
-
-/// Provider for mapping UUIDs to symbol and executable files.
-class SymbolFileProvider : public Provider<SymbolFileProvider> {
-public:
- SymbolFileProvider(const FileSpec &directory)
- : Provider(directory), m_symbol_files() {}
-
- void AddSymbolFile(const UUID *uuid, const FileSpec &module_path,
- const FileSpec &symbol_path);
- void Keep() override;
-
- struct Entry {
- Entry() = default;
- Entry(std::string uuid) : uuid(std::move(uuid)) {}
- Entry(std::string uuid, std::string module_path, std::string symbol_path)
- : uuid(std::move(uuid)), module_path(std::move(module_path)),
- symbol_path(std::move(symbol_path)) {}
-
- bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; }
- bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; }
-
- std::string uuid;
- std::string module_path;
- std::string symbol_path;
- };
-
- struct Info {
- static const char *name;
- static const char *file;
- };
- static char ID;
-
-private:
- std::vector<Entry> m_symbol_files;
-};
-
-/// The MultiProvider is a provider that hands out recorder which can be used
-/// to capture data for different instances of the same object. The recorders
-/// can be passed around or stored as an instance member.
-///
-/// The Info::file for the MultiProvider contains an index of files for every
-/// recorder. Use the MultiLoader to read the index and get the individual
-/// files.
-template <typename T, typename V>
-class MultiProvider : public repro::Provider<V> {
-public:
- MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
-
- T *GetNewRecorder() {
- std::size_t i = m_recorders.size() + 1;
- std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
- llvm::Twine(i) + llvm::Twine(".yaml"))
- .str();
- auto recorder_or_error =
- T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
- if (!recorder_or_error) {
- llvm::consumeError(recorder_or_error.takeError());
- return nullptr;
- }
-
- m_recorders.push_back(std::move(*recorder_or_error));
- return m_recorders.back().get();
- }
-
- void Keep() override {
- std::vector<std::string> files;
- for (auto &recorder : m_recorders) {
- recorder->Stop();
- files.push_back(recorder->GetFilename().GetPath());
- }
-
- FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- llvm::yaml::Output yout(os);
- yout << files;
- }
-
- void Discard() override { m_recorders.clear(); }
-
-private:
- std::vector<std::unique_ptr<T>> m_recorders;
-};
-
-class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- CommandProvider(const FileSpec &directory)
- : MultiProvider<DataRecorder, CommandProvider>(directory) {}
-
- static char ID;
-};
-
-class ProcessInfoRecorder : public AbstractRecorder {
-public:
- ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
- : AbstractRecorder(filename, ec) {}
-
- static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
- Create(const FileSpec &filename);
-
- void Record(const ProcessInstanceInfoList &process_infos);
-};
-
-class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
-
- ProcessInfoRecorder *GetNewProcessInfoRecorder();
-
- void Keep() override;
- void Discard() override;
-
- static char ID;
-
-private:
- std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
- std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
-};
-
-/// Loader for data captured with the MultiProvider. It will read the index and
-/// return the path to the files in the index.
-template <typename T> class MultiLoader {
-public:
- MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
-
- static std::unique_ptr<MultiLoader> Create(Loader *loader) {
- if (!loader)
- return {};
-
- FileSpec file = loader->GetFile<typename T::Info>();
- if (!file)
- return {};
-
- auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
- if (auto err = error_or_file.getError())
- return {};
-
- std::vector<std::string> files;
- llvm::yaml::Input yin((*error_or_file)->getBuffer());
- yin >> files;
-
- if (auto err = yin.error())
- return {};
-
- for (auto &file : files) {
- FileSpec absolute_path =
- loader->GetRoot().CopyByAppendingPathComponent(file);
- file = absolute_path.GetPath();
- }
-
- return std::make_unique<MultiLoader<T>>(std::move(files));
- }
-
- llvm::Optional<std::string> GetNextFile() {
- if (m_index >= m_files.size())
- return {};
- return m_files[m_index++];
- }
-
-private:
- std::vector<std::string> m_files;
- unsigned m_index = 0;
-};
-
-class SymbolFileLoader {
-public:
- SymbolFileLoader(Loader *loader);
- std::pair<FileSpec, FileSpec> GetPaths(const UUID *uuid) const;
-
-private:
- // Sorted list of UUID to path mappings.
- std::vector<SymbolFileProvider::Entry> m_symbol_files;
-};
-
-/// Helper to read directories written by the DirectoryProvider.
-template <typename T>
-llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
- llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
- if (!dir)
- return dir.takeError();
- return std::string(llvm::StringRef(*dir).rtrim());
-}
-
-} // namespace repro
-} // namespace lldb_private
-
-LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry)
-
-namespace llvm {
-namespace yaml {
-template <>
-struct MappingTraits<lldb_private::repro::SymbolFileProvider::Entry> {
- static void mapping(IO &io,
- lldb_private::repro::SymbolFileProvider::Entry &entry) {
- io.mapRequired("uuid", entry.uuid);
- io.mapRequired("module-path", entry.module_path);
- io.mapRequired("symbol-path", entry.symbol_path);
- }
-};
-} // namespace yaml
-} // namespace llvm
-
-#endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H
+++ /dev/null
-//===-- StreamCallback.h -----------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UTILITY_STREAMCALLBACK_H
-#define LLDB_UTILITY_STREAMCALLBACK_H
-
-#include "lldb/lldb-types.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <cstddef>
-#include <cstdint>
-
-namespace lldb_private {
-
-class StreamCallback : public llvm::raw_ostream {
-public:
- StreamCallback(lldb::LogOutputCallback callback, void *baton);
- ~StreamCallback() override = default;
-
-private:
- lldb::LogOutputCallback m_callback;
- void *m_baton;
-
- void write_impl(const char *Ptr, size_t Size) override;
- uint64_t current_pos() const override;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_UTILITY_STREAMCALLBACK_H
+++ /dev/null
-//===-- lldb-private-defines.h ----------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_LLDB_PRIVATE_DEFINES_H
-#define LLDB_LLDB_PRIVATE_DEFINES_H
-
-#if defined(__cplusplus)
-
-// Include Compiler.h here so we don't define LLVM_FALLTHROUGH and then
-// Compiler.h later tries to redefine it.
-#include "llvm/Support/Compiler.h"
-
-#ifndef LLVM_FALLTHROUGH
-
-#ifndef __has_cpp_attribute
-#define __has_cpp_attribute(x) 0
-#endif
-
-/// \macro LLVM_FALLTHROUGH
-/// Marks an empty statement preceding a deliberate switch fallthrough.
-#if __has_cpp_attribute(clang::fallthrough)
-#define LLVM_FALLTHROUGH [[clang::fallthrough]]
-#else
-#define LLVM_FALLTHROUGH
-#endif
-
-#endif // ifndef LLVM_FALLTHROUGH
-
-#endif // #if defined(__cplusplus)
-
-#endif // LLDB_LLDB_PRIVATE_DEFINES_H
+++ /dev/null
-INITIALIZE = True
+++ /dev/null
-//===-- SBReproducerPrivate.h -----------------------------------*- C++ -*-===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_API_SBREPRODUCERPRIVATE_H
-#define LLDB_SOURCE_API_SBREPRODUCERPRIVATE_H
-
-#include "lldb/API/SBReproducer.h"
-
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/Utility/ReproducerInstrumentation.h"
-#include "lldb/Utility/ReproducerProvider.h"
-
-#include "llvm/ADT/DenseMap.h"
-
-#define LLDB_GET_INSTRUMENTATION_DATA() \
- lldb_private::repro::InstrumentationData::Instance()
-
-namespace lldb_private {
-namespace repro {
-
-class SBRegistry : public Registry {
-public:
- SBRegistry();
-};
-
-class SBProvider : public Provider<SBProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- SBProvider(const FileSpec &directory)
- : Provider(directory),
- m_stream(directory.CopyByAppendingPathComponent("sbapi.bin").GetPath(),
- m_ec, llvm::sys::fs::OpenFlags::OF_None),
- m_serializer(m_stream) {}
-
- Serializer &GetSerializer() { return m_serializer; }
- Registry &GetRegistry() { return m_registry; }
-
- static char ID;
-
-private:
- std::error_code m_ec;
- llvm::raw_fd_ostream m_stream;
- Serializer m_serializer;
- SBRegistry m_registry;
-};
-
-class ReplayData {
-public:
- ReplayData(std::unique_ptr<llvm::MemoryBuffer> memory_buffer)
- : m_memory_buffer(std::move(memory_buffer)), m_registry(),
- m_deserializer(m_memory_buffer->getBuffer()) {}
- Deserializer &GetDeserializer() { return m_deserializer; }
- Registry &GetRegistry() { return m_registry; }
-
-private:
- std::unique_ptr<llvm::MemoryBuffer> m_memory_buffer;
- SBRegistry m_registry;
- Deserializer m_deserializer;
-};
-
-template <typename T> void RegisterMethods(Registry &R);
-
-} // namespace repro
-} // namespace lldb_private
-
-#endif
+++ /dev/null
-__ZN4lldb*
-__ZNK4lldb*
-_init_lld*
+++ /dev/null
-//===-- CommandObjectReproducer.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "CommandObjectReproducer.h"
-
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/OptionParser.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Interpreter/OptionArgParser.h"
-#include "lldb/Utility/GDBRemote.h"
-#include "lldb/Utility/ProcessInfo.h"
-#include "lldb/Utility/Reproducer.h"
-
-#include <csignal>
-
-using namespace lldb;
-using namespace llvm;
-using namespace lldb_private;
-using namespace lldb_private::repro;
-
-enum ReproducerProvider {
- eReproducerProviderCommands,
- eReproducerProviderFiles,
- eReproducerProviderSymbolFiles,
- eReproducerProviderGDB,
- eReproducerProviderProcessInfo,
- eReproducerProviderVersion,
- eReproducerProviderWorkingDirectory,
- eReproducerProviderHomeDirectory,
- eReproducerProviderNone
-};
-
-static constexpr OptionEnumValueElement g_reproducer_provider_type[] = {
- {
- eReproducerProviderCommands,
- "commands",
- "Command Interpreter Commands",
- },
- {
- eReproducerProviderFiles,
- "files",
- "Files",
- },
- {
- eReproducerProviderSymbolFiles,
- "symbol-files",
- "Symbol Files",
- },
- {
- eReproducerProviderGDB,
- "gdb",
- "GDB Remote Packets",
- },
- {
- eReproducerProviderProcessInfo,
- "processes",
- "Process Info",
- },
- {
- eReproducerProviderVersion,
- "version",
- "Version",
- },
- {
- eReproducerProviderWorkingDirectory,
- "cwd",
- "Working Directory",
- },
- {
- eReproducerProviderHomeDirectory,
- "home",
- "Home Directory",
- },
- {
- eReproducerProviderNone,
- "none",
- "None",
- },
-};
-
-static constexpr OptionEnumValues ReproducerProviderType() {
- return OptionEnumValues(g_reproducer_provider_type);
-}
-
-#define LLDB_OPTIONS_reproducer_dump
-#include "CommandOptions.inc"
-
-enum ReproducerCrashSignal {
- eReproducerCrashSigill,
- eReproducerCrashSigsegv,
-};
-
-static constexpr OptionEnumValueElement g_reproducer_signaltype[] = {
- {
- eReproducerCrashSigill,
- "SIGILL",
- "Illegal instruction",
- },
- {
- eReproducerCrashSigsegv,
- "SIGSEGV",
- "Segmentation fault",
- },
-};
-
-static constexpr OptionEnumValues ReproducerSignalType() {
- return OptionEnumValues(g_reproducer_signaltype);
-}
-
-#define LLDB_OPTIONS_reproducer_xcrash
-#include "CommandOptions.inc"
-
-#define LLDB_OPTIONS_reproducer_verify
-#include "CommandOptions.inc"
-
-template <typename T>
-llvm::Expected<T> static ReadFromYAML(StringRef filename) {
- auto error_or_file = MemoryBuffer::getFile(filename);
- if (auto err = error_or_file.getError()) {
- return errorCodeToError(err);
- }
-
- T t;
- yaml::Input yin((*error_or_file)->getBuffer());
- yin >> t;
-
- if (auto err = yin.error()) {
- return errorCodeToError(err);
- }
-
- return t;
-}
-
-static void SetError(CommandReturnObject &result, Error err) {
- result.AppendError(toString(std::move(err)));
-}
-
-/// Create a loader from the given path if specified. Otherwise use the current
-/// loader used for replay.
-static Loader *
-GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage,
- CommandReturnObject &result,
- FileSpec reproducer_path) {
- if (reproducer_path) {
- loader_storage.emplace(reproducer_path);
- Loader *loader = &(*loader_storage);
- if (Error err = loader->LoadIndex()) {
- // This is a hard error and will set the result to eReturnStatusFailed.
- SetError(result, std::move(err));
- return nullptr;
- }
- return loader;
- }
-
- if (Loader *loader = Reproducer::Instance().GetLoader())
- return loader;
-
- // This is a soft error because this is expected to fail during capture.
- result.AppendError(
- "Not specifying a reproducer is only support during replay.");
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- return nullptr;
-}
-
-class CommandObjectReproducerGenerate : public CommandObjectParsed {
-public:
- CommandObjectReproducerGenerate(CommandInterpreter &interpreter)
- : CommandObjectParsed(
- interpreter, "reproducer generate",
- "Generate reproducer on disk. When the debugger is in capture "
- "mode, this command will output the reproducer to a directory on "
- "disk and quit. In replay mode this command in a no-op.",
- nullptr) {}
-
- ~CommandObjectReproducerGenerate() override = default;
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- if (!command.empty()) {
- result.AppendErrorWithFormat("'%s' takes no arguments",
- m_cmd_name.c_str());
- return false;
- }
-
- auto &r = Reproducer::Instance();
- if (auto generator = r.GetGenerator()) {
- generator->Keep();
- if (llvm::Error e = repro::Finalize(r.GetReproducerPath())) {
- SetError(result, std::move(e));
- return result.Succeeded();
- }
- } else if (r.IsReplaying()) {
- // Make this operation a NO-OP in replay mode.
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- return result.Succeeded();
- } else {
- result.AppendErrorWithFormat("Unable to get the reproducer generator");
- return false;
- }
-
- result.GetOutputStream()
- << "Reproducer written to '" << r.GetReproducerPath() << "'\n";
- result.GetOutputStream()
- << "Please have a look at the directory to assess if you're willing to "
- "share the contained information.\n";
-
- m_interpreter.BroadcastEvent(
- CommandInterpreter::eBroadcastBitQuitCommandReceived);
- result.SetStatus(eReturnStatusQuit);
- return result.Succeeded();
- }
-};
-
-class CommandObjectReproducerXCrash : public CommandObjectParsed {
-public:
- CommandObjectReproducerXCrash(CommandInterpreter &interpreter)
- : CommandObjectParsed(interpreter, "reproducer xcrash",
- "Intentionally force the debugger to crash in "
- "order to trigger and test reproducer generation.",
- nullptr) {}
-
- ~CommandObjectReproducerXCrash() override = default;
-
- Options *GetOptions() override { return &m_options; }
-
- class CommandOptions : public Options {
- public:
- CommandOptions() : Options() {}
-
- ~CommandOptions() override = default;
-
- Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
- ExecutionContext *execution_context) override {
- Status error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option) {
- case 's':
- signal = (ReproducerCrashSignal)OptionArgParser::ToOptionEnum(
- option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
- if (!error.Success())
- error.SetErrorStringWithFormat("unrecognized value for signal '%s'",
- option_arg.str().c_str());
- break;
- default:
- llvm_unreachable("Unimplemented option");
- }
-
- return error;
- }
-
- void OptionParsingStarting(ExecutionContext *execution_context) override {
- signal = eReproducerCrashSigsegv;
- }
-
- ArrayRef<OptionDefinition> GetDefinitions() override {
- return makeArrayRef(g_reproducer_xcrash_options);
- }
-
- ReproducerCrashSignal signal = eReproducerCrashSigsegv;
- };
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- if (!command.empty()) {
- result.AppendErrorWithFormat("'%s' takes no arguments",
- m_cmd_name.c_str());
- return false;
- }
-
- auto &r = Reproducer::Instance();
-
- if (!r.IsCapturing() && !r.IsReplaying()) {
- result.AppendError(
- "forcing a crash is only supported when capturing a reproducer.");
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- return false;
- }
-
- switch (m_options.signal) {
- case eReproducerCrashSigill:
- std::raise(SIGILL);
- break;
- case eReproducerCrashSigsegv:
- std::raise(SIGSEGV);
- break;
- }
-
- result.SetStatus(eReturnStatusQuit);
- return result.Succeeded();
- }
-
-private:
- CommandOptions m_options;
-};
-
-class CommandObjectReproducerStatus : public CommandObjectParsed {
-public:
- CommandObjectReproducerStatus(CommandInterpreter &interpreter)
- : CommandObjectParsed(
- interpreter, "reproducer status",
- "Show the current reproducer status. In capture mode the "
- "debugger "
- "is collecting all the information it needs to create a "
- "reproducer. In replay mode the reproducer is replaying a "
- "reproducer. When the reproducers are off, no data is collected "
- "and no reproducer can be generated.",
- nullptr) {}
-
- ~CommandObjectReproducerStatus() override = default;
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- if (!command.empty()) {
- result.AppendErrorWithFormat("'%s' takes no arguments",
- m_cmd_name.c_str());
- return false;
- }
-
- auto &r = Reproducer::Instance();
- if (r.IsCapturing()) {
- result.GetOutputStream() << "Reproducer is in capture mode.\n";
- } else if (r.IsReplaying()) {
- result.GetOutputStream() << "Reproducer is in replay mode.\n";
- } else {
- result.GetOutputStream() << "Reproducer is off.\n";
- }
-
- if (r.IsCapturing() || r.IsReplaying()) {
- result.GetOutputStream()
- << "Path: " << r.GetReproducerPath().GetPath() << '\n';
- }
-
- // Auto generate is hidden unless enabled because this is mostly for
- // development and testing.
- if (Generator *g = r.GetGenerator()) {
- if (g->IsAutoGenerate())
- result.GetOutputStream() << "Auto generate: on\n";
- }
-
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return result.Succeeded();
- }
-};
-
-class CommandObjectReproducerDump : public CommandObjectParsed {
-public:
- CommandObjectReproducerDump(CommandInterpreter &interpreter)
- : CommandObjectParsed(interpreter, "reproducer dump",
- "Dump the information contained in a reproducer. "
- "If no reproducer is specified during replay, it "
- "dumps the content of the current reproducer.",
- nullptr) {}
-
- ~CommandObjectReproducerDump() override = default;
-
- Options *GetOptions() override { return &m_options; }
-
- class CommandOptions : public Options {
- public:
- CommandOptions() : Options(), file() {}
-
- ~CommandOptions() override = default;
-
- Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
- ExecutionContext *execution_context) override {
- Status error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option) {
- case 'f':
- file.SetFile(option_arg, FileSpec::Style::native);
- FileSystem::Instance().Resolve(file);
- break;
- case 'p':
- provider = (ReproducerProvider)OptionArgParser::ToOptionEnum(
- option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
- if (!error.Success())
- error.SetErrorStringWithFormat("unrecognized value for provider '%s'",
- option_arg.str().c_str());
- break;
- default:
- llvm_unreachable("Unimplemented option");
- }
-
- return error;
- }
-
- void OptionParsingStarting(ExecutionContext *execution_context) override {
- file.Clear();
- provider = eReproducerProviderNone;
- }
-
- ArrayRef<OptionDefinition> GetDefinitions() override {
- return makeArrayRef(g_reproducer_dump_options);
- }
-
- FileSpec file;
- ReproducerProvider provider = eReproducerProviderNone;
- };
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- if (!command.empty()) {
- result.AppendErrorWithFormat("'%s' takes no arguments",
- m_cmd_name.c_str());
- return false;
- }
-
- llvm::Optional<Loader> loader_storage;
- Loader *loader =
- GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
- if (!loader)
- return false;
-
- switch (m_options.provider) {
- case eReproducerProviderFiles: {
- FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
-
- // Read the VFS mapping.
- ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
- vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
- if (!buffer) {
- SetError(result, errorCodeToError(buffer.getError()));
- return false;
- }
-
- // Initialize a VFS from the given mapping.
- IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
- std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
-
- // Dump the VFS to a buffer.
- std::string str;
- raw_string_ostream os(str);
- static_cast<vfs::RedirectingFileSystem &>(*vfs).dump(os);
- os.flush();
-
- // Return the string.
- result.AppendMessage(str);
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderSymbolFiles: {
- Expected<std::string> symbol_files =
- loader->LoadBuffer<SymbolFileProvider>();
- if (!symbol_files) {
- SetError(result, symbol_files.takeError());
- return false;
- }
-
- std::vector<SymbolFileProvider::Entry> entries;
- llvm::yaml::Input yin(*symbol_files);
- yin >> entries;
-
- for (const auto &entry : entries) {
- result.AppendMessageWithFormat("- uuid: %s\n",
- entry.uuid.c_str());
- result.AppendMessageWithFormat(" module path: %s\n",
- entry.module_path.c_str());
- result.AppendMessageWithFormat(" symbol path: %s\n",
- entry.symbol_path.c_str());
- }
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderVersion: {
- Expected<std::string> version = loader->LoadBuffer<VersionProvider>();
- if (!version) {
- SetError(result, version.takeError());
- return false;
- }
- result.AppendMessage(*version);
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderWorkingDirectory: {
- Expected<std::string> cwd =
- repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
- if (!cwd) {
- SetError(result, cwd.takeError());
- return false;
- }
- result.AppendMessage(*cwd);
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderHomeDirectory: {
- Expected<std::string> home =
- repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
- if (!home) {
- SetError(result, home.takeError());
- return false;
- }
- result.AppendMessage(*home);
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderCommands: {
- std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader =
- repro::MultiLoader<repro::CommandProvider>::Create(loader);
- if (!multi_loader) {
- SetError(result,
- make_error<StringError>("Unable to create command loader.",
- llvm::inconvertibleErrorCode()));
- return false;
- }
-
- // Iterate over the command files and dump them.
- llvm::Optional<std::string> command_file;
- while ((command_file = multi_loader->GetNextFile())) {
- if (!command_file)
- break;
-
- auto command_buffer = llvm::MemoryBuffer::getFile(*command_file);
- if (auto err = command_buffer.getError()) {
- SetError(result, errorCodeToError(err));
- return false;
- }
- result.AppendMessage((*command_buffer)->getBuffer());
- }
-
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderGDB: {
- std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
- multi_loader =
- repro::MultiLoader<repro::GDBRemoteProvider>::Create(loader);
-
- if (!multi_loader) {
- SetError(result,
- make_error<StringError>("Unable to create GDB loader.",
- llvm::inconvertibleErrorCode()));
- return false;
- }
-
- llvm::Optional<std::string> gdb_file;
- while ((gdb_file = multi_loader->GetNextFile())) {
- if (llvm::Expected<std::vector<GDBRemotePacket>> packets =
- ReadFromYAML<std::vector<GDBRemotePacket>>(*gdb_file)) {
- for (GDBRemotePacket &packet : *packets) {
- packet.Dump(result.GetOutputStream());
- }
- } else {
- SetError(result, packets.takeError());
- return false;
- }
- }
-
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderProcessInfo: {
- std::unique_ptr<repro::MultiLoader<repro::ProcessInfoProvider>>
- multi_loader =
- repro::MultiLoader<repro::ProcessInfoProvider>::Create(loader);
-
- if (!multi_loader) {
- SetError(result, make_error<StringError>(
- llvm::inconvertibleErrorCode(),
- "Unable to create process info loader."));
- return false;
- }
-
- llvm::Optional<std::string> process_file;
- while ((process_file = multi_loader->GetNextFile())) {
- if (llvm::Expected<ProcessInstanceInfoList> infos =
- ReadFromYAML<ProcessInstanceInfoList>(*process_file)) {
- for (ProcessInstanceInfo info : *infos)
- info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver());
- } else {
- SetError(result, infos.takeError());
- return false;
- }
- }
-
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return true;
- }
- case eReproducerProviderNone:
- result.AppendError("No valid provider specified.");
- return false;
- }
-
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
- return result.Succeeded();
- }
-
-private:
- CommandOptions m_options;
-};
-
-class CommandObjectReproducerVerify : public CommandObjectParsed {
-public:
- CommandObjectReproducerVerify(CommandInterpreter &interpreter)
- : CommandObjectParsed(interpreter, "reproducer verify",
- "Verify the contents of a reproducer. "
- "If no reproducer is specified during replay, it "
- "verifies the content of the current reproducer.",
- nullptr) {}
-
- ~CommandObjectReproducerVerify() override = default;
-
- Options *GetOptions() override { return &m_options; }
-
- class CommandOptions : public Options {
- public:
- CommandOptions() : Options(), file() {}
-
- ~CommandOptions() override = default;
-
- Status SetOptionValue(uint32_t option_idx, StringRef option_arg,
- ExecutionContext *execution_context) override {
- Status error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option) {
- case 'f':
- file.SetFile(option_arg, FileSpec::Style::native);
- FileSystem::Instance().Resolve(file);
- break;
- default:
- llvm_unreachable("Unimplemented option");
- }
-
- return error;
- }
-
- void OptionParsingStarting(ExecutionContext *execution_context) override {
- file.Clear();
- }
-
- ArrayRef<OptionDefinition> GetDefinitions() override {
- return makeArrayRef(g_reproducer_verify_options);
- }
-
- FileSpec file;
- };
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- if (!command.empty()) {
- result.AppendErrorWithFormat("'%s' takes no arguments",
- m_cmd_name.c_str());
- return false;
- }
-
- llvm::Optional<Loader> loader_storage;
- Loader *loader =
- GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file);
- if (!loader)
- return false;
-
- bool errors = false;
- auto error_callback = [&](llvm::StringRef error) {
- errors = true;
- result.AppendError(error);
- };
-
- bool warnings = false;
- auto warning_callback = [&](llvm::StringRef warning) {
- warnings = true;
- result.AppendWarning(warning);
- };
-
- auto note_callback = [&](llvm::StringRef warning) {
- result.AppendMessage(warning);
- };
-
- Verifier verifier(loader);
- verifier.Verify(error_callback, warning_callback, note_callback);
-
- if (warnings || errors) {
- result.AppendMessage("reproducer verification failed");
- result.SetStatus(eReturnStatusFailed);
- } else {
- result.AppendMessage("reproducer verification succeeded");
- result.SetStatus(eReturnStatusSuccessFinishResult);
- }
-
- return result.Succeeded();
- }
-
-private:
- CommandOptions m_options;
-};
-
-CommandObjectReproducer::CommandObjectReproducer(
- CommandInterpreter &interpreter)
- : CommandObjectMultiword(
- interpreter, "reproducer",
- "Commands for manipulating reproducers. Reproducers make it "
- "possible "
- "to capture full debug sessions with all its dependencies. The "
- "resulting reproducer is used to replay the debug session while "
- "debugging the debugger.\n"
- "Because reproducers need the whole the debug session from "
- "beginning to end, you need to launch the debugger in capture or "
- "replay mode, commonly though the command line driver.\n"
- "Reproducers are unrelated record-replay debugging, as you cannot "
- "interact with the debugger during replay.\n",
- "reproducer <subcommand> [<subcommand-options>]") {
- LoadSubCommand(
- "generate",
- CommandObjectSP(new CommandObjectReproducerGenerate(interpreter)));
- LoadSubCommand("status", CommandObjectSP(
- new CommandObjectReproducerStatus(interpreter)));
- LoadSubCommand("dump",
- CommandObjectSP(new CommandObjectReproducerDump(interpreter)));
- LoadSubCommand("verify", CommandObjectSP(
- new CommandObjectReproducerVerify(interpreter)));
- LoadSubCommand("xcrash", CommandObjectSP(
- new CommandObjectReproducerXCrash(interpreter)));
-}
-
-CommandObjectReproducer::~CommandObjectReproducer() = default;
+++ /dev/null
-//===-- CommandObjectReproducer.h -------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H
-#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H
-
-#include "lldb/Interpreter/CommandObjectMultiword.h"
-
-namespace lldb_private {
-
-// CommandObjectReproducer
-
-class CommandObjectReproducer : public CommandObjectMultiword {
-public:
- CommandObjectReproducer(CommandInterpreter &interpreter);
-
- ~CommandObjectReproducer() override;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTREPRODUCER_H
#include "lldb/Utility/CompletionRequest.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
-#include "lldb/Utility/Logging.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
FormatEntity::Entry::Entry(llvm::StringRef s)
: string(s.data(), s.size()), printf_format(), children(),
- type(Type::String), fmt(lldb::eFormatDefault), number(0), deref(false) {}
+ type(Type::String) {}
FormatEntity::Entry::Entry(char ch)
- : string(1, ch), printf_format(), children(), type(Type::String),
- fmt(lldb::eFormatDefault), number(0), deref(false) {}
+ : string(1, ch), printf_format(), children(), type(Type::String) {}
void FormatEntity::Entry::AppendChar(char ch) {
if (children.empty() || children.back().type != Entry::Type::String)
size_t &close_bracket_index,
const char *&var_name_final_if_array_range,
int64_t &index_lower, int64_t &index_higher) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
+ Log *log = GetLog(LLDBLog::DataFormatters);
close_bracket_index = llvm::StringRef::npos;
const size_t open_bracket_index = subpath.find('[');
if (open_bracket_index == llvm::StringRef::npos) {
static ValueObjectSP ExpandIndexedExpression(ValueObject *valobj, size_t index,
bool deref_pointer) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
- const char *ptr_deref_format = "[%d]";
- std::string ptr_deref_buffer(10, 0);
- ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index);
- LLDB_LOGF(log, "[ExpandIndexedExpression] name to deref: %s",
- ptr_deref_buffer.c_str());
+ Log *log = GetLog(LLDBLog::DataFormatters);
+ std::string name_to_deref = llvm::formatv("[{0}]", index);
+ LLDB_LOG(log, "[ExpandIndexedExpression] name to deref: {0}", name_to_deref);
ValueObject::GetValueForExpressionPathOptions options;
ValueObject::ExpressionPathEndResultType final_value_type;
ValueObject::ExpressionPathScanEndReason reason_to_stop;
(deref_pointer ? ValueObject::eExpressionPathAftermathDereference
: ValueObject::eExpressionPathAftermathNothing);
ValueObjectSP item = valobj->GetValueForExpressionPath(
- ptr_deref_buffer.c_str(), &reason_to_stop, &final_value_type, options,
- &what_next);
+ name_to_deref, &reason_to_stop, &final_value_type, options, &what_next);
if (!item) {
LLDB_LOGF(log,
"[ExpandIndexedExpression] ERROR: why stopping = %d,"
if (valobj == nullptr)
return false;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS));
+ Log *log = GetLog(LLDBLog::DataFormatters);
Format custom_format = eFormatInvalid;
ValueObject::ValueObjectRepresentationStyle val_obj_display =
entry.string.empty()
case FormatEntity::Entry::Type::ScriptVariableSynthetic:
is_script = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FormatEntity::Entry::Type::VariableSynthetic:
custom_format = entry.fmt;
val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number;
return false;
}
- if (valobj == nullptr)
- return false;
-
ValueObject::ExpressionPathAftermath what_next =
(do_deref_pointer ? ValueObject::eExpressionPathAftermathDereference
: ValueObject::eExpressionPathAftermathNothing);
bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(),
target->GetBitfieldBitSize());
auto type_sp = std::make_shared<TypeNameSpecifierImpl>(
- bitfield_name.GetString(), false);
+ bitfield_name.GetString(), lldb::eFormatterMatchExact);
if (val_obj_display ==
ValueObject::eValueObjectRepresentationStyleSummary &&
!DataVisualization::GetSummaryForType(type_sp))
return (::strncmp(var_name_begin, var, strlen(var)) == 0);
}
+/// Parses the basename out of a demangled function name
+/// that may include function arguments. Supports
+/// template functions.
+///
+/// Returns pointers to the opening and closing parenthesis of
+/// `full_name`. Can return nullptr for either parenthesis if
+/// none is exists.
+static std::pair<char const *, char const *>
+ParseBaseName(char const *full_name) {
+ const char *open_paren = strchr(full_name, '(');
+ const char *close_paren = nullptr;
+ const char *generic = strchr(full_name, '<');
+ // if before the arguments list begins there is a template sign
+ // then scan to the end of the generic args before you try to find
+ // the arguments list
+ if (generic && open_paren && generic < open_paren) {
+ int generic_depth = 1;
+ ++generic;
+ for (; *generic && generic_depth > 0; generic++) {
+ if (*generic == '<')
+ generic_depth++;
+ if (*generic == '>')
+ generic_depth--;
+ }
+ if (*generic)
+ open_paren = strchr(generic, '(');
+ else
+ open_paren = nullptr;
+ }
+
+ if (open_paren) {
+ if (IsToken(open_paren, "(anonymous namespace)")) {
+ open_paren = strchr(open_paren + strlen("(anonymous namespace)"), '(');
+ if (open_paren)
+ close_paren = strchr(open_paren, ')');
+ } else
+ close_paren = strchr(open_paren, ')');
+ }
+
+ return {open_paren, close_paren};
+}
+
+/// Writes out the function name in 'full_name' to 'out_stream'
+/// but replaces each argument type with the variable name
+/// and the corresponding pretty-printed value
+static void PrettyPrintFunctionNameWithArgs(Stream &out_stream,
+ char const *full_name,
+ ExecutionContextScope *exe_scope,
+ VariableList const &args) {
+ auto [open_paren, close_paren] = ParseBaseName(full_name);
+ if (open_paren)
+ out_stream.Write(full_name, open_paren - full_name + 1);
+ else {
+ out_stream.PutCString(full_name);
+ out_stream.PutChar('(');
+ }
+
+ FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
+
+ if (close_paren)
+ out_stream.PutCString(close_paren);
+ else
+ out_stream.PutChar(')');
+}
+
bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s,
const SymbolContext *sc,
const ExecutionContext *exe_ctx,
variable_list_sp->AppendVariablesWithScope(
eValueTypeVariableArgument, args);
if (args.GetSize() > 0) {
- const char *open_paren = strchr(cstr, '(');
- const char *close_paren = nullptr;
- const char *generic = strchr(cstr, '<');
- // if before the arguments list begins there is a template sign
- // then scan to the end of the generic args before you try to find
- // the arguments list
- if (generic && open_paren && generic < open_paren) {
- int generic_depth = 1;
- ++generic;
- for (; *generic && generic_depth > 0; generic++) {
- if (*generic == '<')
- generic_depth++;
- if (*generic == '>')
- generic_depth--;
- }
- if (*generic)
- open_paren = strchr(generic, '(');
- else
- open_paren = nullptr;
- }
- if (open_paren) {
- if (IsToken(open_paren, "(anonymous namespace)")) {
- open_paren =
- strchr(open_paren + strlen("(anonymous namespace)"), '(');
- if (open_paren)
- close_paren = strchr(open_paren, ')');
- } else
- close_paren = strchr(open_paren, ')');
- }
-
- if (open_paren)
- s.Write(cstr, open_paren - cstr + 1);
- else {
- s.PutCString(cstr);
- s.PutChar('(');
- }
- const size_t num_args = args.GetSize();
- for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) {
- std::string buffer;
-
- VariableSP var_sp(args.GetVariableAtIndex(arg_idx));
- ValueObjectSP var_value_sp(
- ValueObjectVariable::Create(exe_scope, var_sp));
- StreamString ss;
- llvm::StringRef var_representation;
- const char *var_name = var_value_sp->GetName().GetCString();
- if (var_value_sp->GetCompilerType().IsValid()) {
- if (var_value_sp && exe_scope->CalculateTarget())
- var_value_sp =
- var_value_sp->GetQualifiedRepresentationIfAvailable(
- exe_scope->CalculateTarget()
- ->TargetProperties::GetPreferDynamicValue(),
- exe_scope->CalculateTarget()
- ->TargetProperties::GetEnableSyntheticValue());
- if (var_value_sp->GetCompilerType().IsAggregateType() &&
- DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) {
- static StringSummaryFormat format(
- TypeSummaryImpl::Flags()
- .SetHideItemNames(false)
- .SetShowMembersOneLiner(true),
- "");
- format.FormatObject(var_value_sp.get(), buffer,
- TypeSummaryOptions());
- var_representation = buffer;
- } else
- var_value_sp->DumpPrintableRepresentation(
- ss,
- ValueObject::ValueObjectRepresentationStyle::
- eValueObjectRepresentationStyleSummary,
- eFormatDefault,
- ValueObject::PrintableRepresentationSpecialCases::eAllow,
- false);
- }
-
- if (!ss.GetString().empty())
- var_representation = ss.GetString();
- if (arg_idx > 0)
- s.PutCString(", ");
- if (var_value_sp->GetError().Success()) {
- if (!var_representation.empty())
- s.Printf("%s=%s", var_name, var_representation.str().c_str());
- else
- s.Printf("%s=%s at %s", var_name,
- var_value_sp->GetTypeName().GetCString(),
- var_value_sp->GetLocationAsCString());
- } else
- s.Printf("%s=<unavailable>", var_name);
- }
-
- if (close_paren)
- s.PutCString(close_paren);
- else
- s.PutChar(')');
-
+ PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args);
} else {
s.PutCString(cstr);
}
request.AddCompletions(new_matches);
}
}
+
+void FormatEntity::PrettyPrintFunctionArguments(
+ Stream &out_stream, VariableList const &args,
+ ExecutionContextScope *exe_scope) {
+ const size_t num_args = args.GetSize();
+ for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) {
+ std::string buffer;
+
+ VariableSP var_sp(args.GetVariableAtIndex(arg_idx));
+ ValueObjectSP var_value_sp(ValueObjectVariable::Create(exe_scope, var_sp));
+ StreamString ss;
+ llvm::StringRef var_representation;
+ const char *var_name = var_value_sp->GetName().GetCString();
+ if (var_value_sp->GetCompilerType().IsValid()) {
+ if (exe_scope && exe_scope->CalculateTarget())
+ var_value_sp = var_value_sp->GetQualifiedRepresentationIfAvailable(
+ exe_scope->CalculateTarget()
+ ->TargetProperties::GetPreferDynamicValue(),
+ exe_scope->CalculateTarget()
+ ->TargetProperties::GetEnableSyntheticValue());
+ if (var_value_sp->GetCompilerType().IsAggregateType() &&
+ DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) {
+ static StringSummaryFormat format(TypeSummaryImpl::Flags()
+ .SetHideItemNames(false)
+ .SetShowMembersOneLiner(true),
+ "");
+ format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions());
+ var_representation = buffer;
+ } else
+ var_value_sp->DumpPrintableRepresentation(
+ ss,
+ ValueObject::ValueObjectRepresentationStyle::
+ eValueObjectRepresentationStyleSummary,
+ eFormatDefault,
+ ValueObject::PrintableRepresentationSpecialCases::eAllow, false);
+ }
+
+ if (!ss.GetString().empty())
+ var_representation = ss.GetString();
+ if (arg_idx > 0)
+ out_stream.PutCString(", ");
+ if (var_value_sp->GetError().Success()) {
+ if (!var_representation.empty())
+ out_stream.Printf("%s=%s", var_name, var_representation.str().c_str());
+ else
+ out_stream.Printf("%s=%s at %s", var_name,
+ var_value_sp->GetTypeName().GetCString(),
+ var_value_sp->GetLocationAsCString());
+ } else
+ out_stream.Printf("%s=<unavailable>", var_name);
+ }
+}
+++ /dev/null
-//===-- MainLoop.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Config/llvm-config.h"
-#include "lldb/Host/Config.h"
-
-#include "lldb/Host/MainLoop.h"
-#include "lldb/Host/PosixApi.h"
-#include "lldb/Utility/Status.h"
-#include <algorithm>
-#include <cassert>
-#include <cerrno>
-#include <csignal>
-#include <ctime>
-#include <vector>
-
-// Multiplexing is implemented using kqueue on systems that support it (BSD
-// variants including OSX). On linux we use ppoll, while android uses pselect
-// (ppoll is present but not implemented properly). On windows we use WSApoll
-// (which does not support signals).
-
-#if HAVE_SYS_EVENT_H
-#include <sys/event.h>
-#elif defined(_WIN32)
-#include <winsock2.h>
-#elif defined(__ANDROID__)
-#include <sys/syscall.h>
-#else
-#include <poll.h>
-#endif
-
-#ifdef _WIN32
-#define POLL WSAPoll
-#else
-#define POLL poll
-#endif
-
-#if SIGNAL_POLLING_UNSUPPORTED
-#ifdef _WIN32
-typedef int sigset_t;
-typedef int siginfo_t;
-#endif
-
-int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
- const sigset_t *) {
- int timeout =
- (timeout_ts == nullptr)
- ? -1
- : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
- return POLL(fds, nfds, timeout);
-}
-
-#endif
-
-using namespace lldb;
-using namespace lldb_private;
-
-static sig_atomic_t g_signal_flags[NSIG];
-
-#ifndef SIGNAL_POLLING_UNSUPPORTED
-static void SignalHandler(int signo, siginfo_t *info, void *) {
- assert(signo < NSIG);
- g_signal_flags[signo] = 1;
-}
-#endif
-
-class MainLoop::RunImpl {
-public:
- RunImpl(MainLoop &loop);
- ~RunImpl() = default;
-
- Status Poll();
- void ProcessEvents();
-
-private:
- MainLoop &loop;
-
-#if HAVE_SYS_EVENT_H
- std::vector<struct kevent> in_events;
- struct kevent out_events[4];
- int num_events = -1;
-
-#else
-#ifdef __ANDROID__
- fd_set read_fd_set;
-#else
- std::vector<struct pollfd> read_fds;
-#endif
-
- sigset_t get_sigmask();
-#endif
-};
-
-#if HAVE_SYS_EVENT_H
-MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
- in_events.reserve(loop.m_read_fds.size());
-}
-
-Status MainLoop::RunImpl::Poll() {
- in_events.resize(loop.m_read_fds.size());
- unsigned i = 0;
- for (auto &fd : loop.m_read_fds)
- EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
-
- num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
- out_events, llvm::array_lengthof(out_events), nullptr);
-
- if (num_events < 0) {
- if (errno == EINTR) {
- // in case of EINTR, let the main loop run one iteration
- // we need to zero num_events to avoid assertions failing
- num_events = 0;
- } else
- return Status(errno, eErrorTypePOSIX);
- }
- return Status();
-}
-
-void MainLoop::RunImpl::ProcessEvents() {
- assert(num_events >= 0);
- for (int i = 0; i < num_events; ++i) {
- if (loop.m_terminate_request)
- return;
- switch (out_events[i].filter) {
- case EVFILT_READ:
- loop.ProcessReadObject(out_events[i].ident);
- break;
- case EVFILT_SIGNAL:
- loop.ProcessSignal(out_events[i].ident);
- break;
- default:
- llvm_unreachable("Unknown event");
- }
- }
-}
-#else
-MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
-#ifndef __ANDROID__
- read_fds.reserve(loop.m_read_fds.size());
-#endif
-}
-
-sigset_t MainLoop::RunImpl::get_sigmask() {
- sigset_t sigmask;
-#if defined(_WIN32)
- sigmask = 0;
-#elif SIGNAL_POLLING_UNSUPPORTED
- sigemptyset(&sigmask);
-#else
- int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
- assert(ret == 0);
- (void) ret;
-
- for (const auto &sig : loop.m_signals)
- sigdelset(&sigmask, sig.first);
-#endif
- return sigmask;
-}
-
-#ifdef __ANDROID__
-Status MainLoop::RunImpl::Poll() {
- // ppoll(2) is not supported on older all android versions. Also, older
- // versions android (API <= 19) implemented pselect in a non-atomic way, as a
- // combination of pthread_sigmask and select. This is not sufficient for us,
- // as we rely on the atomicity to correctly implement signal polling, so we
- // call the underlying syscall ourselves.
-
- FD_ZERO(&read_fd_set);
- int nfds = 0;
- for (const auto &fd : loop.m_read_fds) {
- FD_SET(fd.first, &read_fd_set);
- nfds = std::max(nfds, fd.first + 1);
- }
-
- union {
- sigset_t set;
- uint64_t pad;
- } kernel_sigset;
- memset(&kernel_sigset, 0, sizeof(kernel_sigset));
- kernel_sigset.set = get_sigmask();
-
- struct {
- void *sigset_ptr;
- size_t sigset_len;
- } extra_data = {&kernel_sigset, sizeof(kernel_sigset)};
- if (syscall(__NR_pselect6, nfds, &read_fd_set, nullptr, nullptr, nullptr,
- &extra_data) == -1 &&
- errno != EINTR)
- return Status(errno, eErrorTypePOSIX);
-
- return Status();
-}
-#else
-Status MainLoop::RunImpl::Poll() {
- read_fds.clear();
-
- sigset_t sigmask = get_sigmask();
-
- for (const auto &fd : loop.m_read_fds) {
- struct pollfd pfd;
- pfd.fd = fd.first;
- pfd.events = POLLIN;
- pfd.revents = 0;
- read_fds.push_back(pfd);
- }
-
- if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
- errno != EINTR)
- return Status(errno, eErrorTypePOSIX);
-
- return Status();
-}
-#endif
-
-void MainLoop::RunImpl::ProcessEvents() {
-#ifdef __ANDROID__
- // Collect first all readable file descriptors into a separate vector and
- // then iterate over it to invoke callbacks. Iterating directly over
- // loop.m_read_fds is not possible because the callbacks can modify the
- // container which could invalidate the iterator.
- std::vector<IOObject::WaitableHandle> fds;
- for (const auto &fd : loop.m_read_fds)
- if (FD_ISSET(fd.first, &read_fd_set))
- fds.push_back(fd.first);
-
- for (const auto &handle : fds) {
-#else
- for (const auto &fd : read_fds) {
- if ((fd.revents & (POLLIN | POLLHUP)) == 0)
- continue;
- IOObject::WaitableHandle handle = fd.fd;
-#endif
- if (loop.m_terminate_request)
- return;
-
- loop.ProcessReadObject(handle);
- }
-
- std::vector<int> signals;
- for (const auto &entry : loop.m_signals)
- if (g_signal_flags[entry.first] != 0)
- signals.push_back(entry.first);
-
- for (const auto &signal : signals) {
- if (loop.m_terminate_request)
- return;
- g_signal_flags[signal] = 0;
- loop.ProcessSignal(signal);
- }
-}
-#endif
-
-MainLoop::MainLoop() {
-#if HAVE_SYS_EVENT_H
- m_kqueue = kqueue();
- assert(m_kqueue >= 0);
-#endif
-}
-MainLoop::~MainLoop() {
-#if HAVE_SYS_EVENT_H
- close(m_kqueue);
-#endif
- assert(m_read_fds.size() == 0);
- assert(m_signals.size() == 0);
-}
-
-MainLoop::ReadHandleUP MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
- const Callback &callback,
- Status &error) {
-#ifdef _WIN32
- if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
- error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
- return nullptr;
- }
-#endif
- if (!object_sp || !object_sp->IsValid()) {
- error.SetErrorString("IO object is not valid.");
- return nullptr;
- }
-
- const bool inserted =
- m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
- if (!inserted) {
- error.SetErrorStringWithFormat("File descriptor %d already monitored.",
- object_sp->GetWaitableHandle());
- return nullptr;
- }
-
- return CreateReadHandle(object_sp);
-}
-
-// We shall block the signal, then install the signal handler. The signal will
-// be unblocked in the Run() function to check for signal delivery.
-MainLoop::SignalHandleUP
-MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
-#ifdef SIGNAL_POLLING_UNSUPPORTED
- error.SetErrorString("Signal polling is not supported on this platform.");
- return nullptr;
-#else
- auto signal_it = m_signals.find(signo);
- if (signal_it != m_signals.end()) {
- auto callback_it = signal_it->second.callbacks.insert(
- signal_it->second.callbacks.end(), callback);
- return SignalHandleUP(new SignalHandle(*this, signo, callback_it));
- }
-
- SignalInfo info;
- info.callbacks.push_back(callback);
- struct sigaction new_action;
- new_action.sa_sigaction = &SignalHandler;
- new_action.sa_flags = SA_SIGINFO;
- sigemptyset(&new_action.sa_mask);
- sigaddset(&new_action.sa_mask, signo);
- sigset_t old_set;
-
- g_signal_flags[signo] = 0;
-
- // Even if using kqueue, the signal handler will still be invoked, so it's
- // important to replace it with our "benign" handler.
- int ret = sigaction(signo, &new_action, &info.old_action);
- (void)ret;
- assert(ret == 0 && "sigaction failed");
-
-#if HAVE_SYS_EVENT_H
- struct kevent ev;
- EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
- ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
- assert(ret == 0);
-#endif
-
- // If we're using kqueue, the signal needs to be unblocked in order to
- // receive it. If using pselect/ppoll, we need to block it, and later unblock
- // it as a part of the system call.
- ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
- &new_action.sa_mask, &old_set);
- assert(ret == 0 && "pthread_sigmask failed");
- info.was_blocked = sigismember(&old_set, signo);
- auto insert_ret = m_signals.insert({signo, info});
-
- return SignalHandleUP(new SignalHandle(
- *this, signo, insert_ret.first->second.callbacks.begin()));
-#endif
-}
-
-void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
- bool erased = m_read_fds.erase(handle);
- UNUSED_IF_ASSERT_DISABLED(erased);
- assert(erased);
-}
-
-void MainLoop::UnregisterSignal(int signo,
- std::list<Callback>::iterator callback_it) {
-#if SIGNAL_POLLING_UNSUPPORTED
- Status("Signal polling is not supported on this platform.");
-#else
- auto it = m_signals.find(signo);
- assert(it != m_signals.end());
-
- it->second.callbacks.erase(callback_it);
- // Do not remove the signal handler unless all callbacks have been erased.
- if (!it->second.callbacks.empty())
- return;
-
- sigaction(signo, &it->second.old_action, nullptr);
-
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, signo);
- int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
- &set, nullptr);
- assert(ret == 0);
- (void)ret;
-
-#if HAVE_SYS_EVENT_H
- struct kevent ev;
- EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0);
- ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
- assert(ret == 0);
-#endif
-
- m_signals.erase(it);
-#endif
-}
-
-Status MainLoop::Run() {
- m_terminate_request = false;
-
- Status error;
- RunImpl impl(*this);
-
- // run until termination or until we run out of things to listen to
- while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
-
- error = impl.Poll();
- if (error.Fail())
- return error;
-
- impl.ProcessEvents();
- }
- return Status();
-}
-
-void MainLoop::ProcessSignal(int signo) {
- auto it = m_signals.find(signo);
- if (it != m_signals.end()) {
- // The callback may actually register/unregister signal handlers,
- // so we need to create a copy first.
- llvm::SmallVector<Callback, 4> callbacks_to_run{
- it->second.callbacks.begin(), it->second.callbacks.end()};
- for (auto &x : callbacks_to_run)
- x(*this); // Do the work
- }
-}
-
-void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {
- auto it = m_read_fds.find(handle);
- if (it != m_read_fds.end())
- it->second(*this); // Do the work
-}
+++ /dev/null
-//===-- StringConvert.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include <cstdlib>
-
-#include "lldb/Host/StringConvert.h"
-
-namespace lldb_private {
-namespace StringConvert {
-
-int32_t ToSInt32(const char *s, int32_t fail_value, int base,
- bool *success_ptr) {
- if (s && s[0]) {
- char *end = nullptr;
- const long sval = ::strtol(s, &end, base);
- if (*end == '\0') {
- if (success_ptr)
- *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
- return (int32_t)sval; // All characters were used, return the result
- }
- }
- if (success_ptr)
- *success_ptr = false;
- return fail_value;
-}
-
-uint32_t ToUInt32(const char *s, uint32_t fail_value, int base,
- bool *success_ptr) {
- if (s && s[0]) {
- char *end = nullptr;
- const unsigned long uval = ::strtoul(s, &end, base);
- if (*end == '\0') {
- if (success_ptr)
- *success_ptr = (uval <= UINT32_MAX);
- return (uint32_t)uval; // All characters were used, return the result
- }
- }
- if (success_ptr)
- *success_ptr = false;
- return fail_value;
-}
-
-int64_t ToSInt64(const char *s, int64_t fail_value, int base,
- bool *success_ptr) {
- if (s && s[0]) {
- char *end = nullptr;
- int64_t uval = ::strtoll(s, &end, base);
- if (*end == '\0') {
- if (success_ptr)
- *success_ptr = true;
- return uval; // All characters were used, return the result
- }
- }
- if (success_ptr)
- *success_ptr = false;
- return fail_value;
-}
-
-uint64_t ToUInt64(const char *s, uint64_t fail_value, int base,
- bool *success_ptr) {
- if (s && s[0]) {
- char *end = nullptr;
- uint64_t uval = ::strtoull(s, &end, base);
- if (*end == '\0') {
- if (success_ptr)
- *success_ptr = true;
- return uval; // All characters were used, return the result
- }
- }
- if (success_ptr)
- *success_ptr = false;
- return fail_value;
-}
-
-double ToDouble(const char *s, double fail_value, bool *success_ptr) {
- if (s && s[0]) {
- char *end = nullptr;
- double val = strtod(s, &end);
- if (*end == '\0') {
- if (success_ptr)
- *success_ptr = true;
- return val; // All characters were used, return the result
- }
- }
- if (success_ptr)
- *success_ptr = false;
- return fail_value;
-}
-}
-}
#include <cstdio>
#include <cstring>
#include <unistd.h>
+#include <optional>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/utsname.h>
return llvm::VersionTuple();
}
-bool HostInfoOpenBSD::GetOSBuildString(std::string &s) {
+std::optional<std::string> HostInfoOpenBSD::GetOSBuildString() {
int mib[2] = {CTL_KERN, KERN_OSREV};
- char osrev_str[12];
uint32_t osrev = 0;
size_t osrev_len = sizeof(osrev);
- if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0) {
- ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
- s.assign(osrev_str);
- return true;
- }
-
- s.clear();
- return false;
-}
-
-bool HostInfoOpenBSD::GetOSKernelDescription(std::string &s) {
- struct utsname un;
-
- ::memset(&un, 0, sizeof(utsname));
- s.clear();
-
- if (uname(&un) < 0)
- return false;
+ if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
+ return llvm::formatv("{0,8:8}", osrev).str();
- s.assign(un.version);
-
- return true;
+ return std::nullopt;
}
FileSpec HostInfoOpenBSD::GetProgramFileSpec() {
file_spec.IsAbsolute() && FileSystem::Instance().Exists(file_spec))
return true;
- file_spec.GetDirectory().SetCString("/usr/bin");
+ file_spec.SetDirectory("/usr/bin");
return true;
}
#endif
#endif // #ifdef __ANDROID__
-namespace {
+static const int kDomain = AF_UNIX;
+static const int kType = SOCK_STREAM;
-const int kDomain = AF_UNIX;
-const int kType = SOCK_STREAM;
-
-bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
- sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
+static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
+ sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
if (name.size() + name_offset > sizeof(saddr_un->sun_path))
return false;
return true;
}
-} // namespace
DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
: Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
}
std::string DomainSocket::GetSocketName() const {
- if (m_socket != kInvalidSocketValue) {
- struct sockaddr_un saddr_un;
- saddr_un.sun_family = AF_UNIX;
- socklen_t sock_addr_len = sizeof(struct sockaddr_un);
- if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) ==
- 0) {
- std::string name(saddr_un.sun_path + GetNameOffset(),
- sock_addr_len -
- offsetof(struct sockaddr_un, sun_path) -
+ if (m_socket == kInvalidSocketValue)
+ return "";
+
+ struct sockaddr_un saddr_un;
+ saddr_un.sun_family = AF_UNIX;
+ socklen_t sock_addr_len = sizeof(struct sockaddr_un);
+ if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
+ 0)
+ return "";
+
+ if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
+ return ""; // Unnamed domain socket
+
+ llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
+ sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
GetNameOffset());
- if (name.back() == '\0') name.pop_back();
- return name;
- }
- }
- return "";
+ name = name.rtrim('\0');
+
+ return name.str();
}
std::string DomainSocket::GetRemoteConnectionURI() const {
- if (m_socket != kInvalidSocketValue) {
- return std::string(llvm::formatv(
- "{0}://{1}",
- GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect",
- GetSocketName()));
- }
- return "";
+ std::string name = GetSocketName();
+ if (name.empty())
+ return name;
+
+ return llvm::formatv(
+ "{0}://{1}",
+ GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
}
#define PIPE2_SUPPORTED 0
#endif
-namespace {
-
-constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
+static constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
-bool SetCloexecFlag(int fd) {
+static bool SetCloexecFlag(int fd) {
int flags = ::fcntl(fd, F_GETFD);
if (flags == -1)
return false;
}
#endif
-std::chrono::time_point<std::chrono::steady_clock> Now() {
+static std::chrono::time_point<std::chrono::steady_clock> Now() {
return std::chrono::steady_clock::now();
}
-} // namespace
PipePosix::PipePosix()
: m_fds{PipePosix::kInvalidDescriptor, PipePosix::kInvalidDescriptor} {}
+++ /dev/null
-//===-- Windows.cpp -------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// This file provides Windows support functions
-
-#include "lldb/Host/PosixApi.h"
-#include "lldb/Host/windows/windows.h"
-
-#include "llvm/Support/ConvertUTF.h"
-
-#include <cassert>
-#include <cctype>
-#include <cerrno>
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <io.h>
-
-int vasprintf(char **ret, const char *fmt, va_list ap) {
- char *buf;
- int len;
- size_t buflen;
- va_list ap2;
-
- va_copy(ap2, ap);
- len = vsnprintf(NULL, 0, fmt, ap2);
-
- if (len >= 0 &&
- (buf = (char *)malloc((buflen = (size_t)(len + 1)))) != NULL) {
- len = vsnprintf(buf, buflen, fmt, ap);
- *ret = buf;
- } else {
- *ret = NULL;
- len = -1;
- }
-
- va_end(ap2);
- return len;
-}
-
-char *strcasestr(const char *s, const char *find) {
- char c, sc;
- size_t len;
-
- if ((c = *find++) != 0) {
- c = tolower((unsigned char)c);
- len = strlen(find);
- do {
- do {
- if ((sc = *s++) == 0)
- return 0;
- } while ((char)tolower((unsigned char)sc) != c);
- } while (strncasecmp(s, find, len) != 0);
- s--;
- }
- return const_cast<char *>(s);
-}
-
-#ifdef _MSC_VER
-
-char *basename(char *path) {
- char *l1 = strrchr(path, '\\');
- char *l2 = strrchr(path, '/');
- if (l2 > l1)
- l1 = l2;
- if (!l1)
- return path; // no base name
- return &l1[1];
-}
-
-char *dirname(char *path) {
- char *l1 = strrchr(path, '\\');
- char *l2 = strrchr(path, '/');
- if (l2 > l1)
- l1 = l2;
- if (!l1)
- return NULL; // no dir name
- *l1 = 0;
- return path;
-}
-
-int strcasecmp(const char *s1, const char *s2) { return stricmp(s1, s2); }
-
-int strncasecmp(const char *s1, const char *s2, size_t n) {
- return strnicmp(s1, s2, n);
-}
-
-#if _MSC_VER < 1900
-namespace lldb_private {
-int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) {
- int old_errno = errno;
- int r = ::vsnprintf(buffer, count, format, argptr);
- int new_errno = errno;
- buffer[count - 1] = '\0';
- if (r == -1 || r == count) {
- FILE *nul = fopen("nul", "w");
- int bytes_written = ::vfprintf(nul, format, argptr);
- fclose(nul);
- if (bytes_written < count)
- errno = new_errno;
- else {
- errno = old_errno;
- r = bytes_written;
- }
- }
- return r;
-}
-} // namespace lldb_private
-#endif
-
-#endif // _MSC_VER
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Socket.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/ReproducerProvider.h"
+#include "lldb/Target/Statistics.h"
+#include "lldb/Utility/Diagnostics.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Timer.h"
-#include "lldb/lldb-private.h"
+#include "lldb/Version/Version.h"
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include <string>
using namespace lldb_private;
-using namespace lldb_private::repro;
SystemInitializerCommon::SystemInitializerCommon(
HostInfo::SharedLibraryDirectoryHelper *helper)
SystemInitializerCommon::~SystemInitializerCommon() = default;
-/// Initialize the FileSystem based on the current reproducer mode.
-static llvm::Error InitializeFileSystem() {
- auto &r = repro::Reproducer::Instance();
- if (repro::Loader *loader = r.GetLoader()) {
- FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
- if (vfs_mapping) {
- if (llvm::Error e = FileSystem::Initialize(vfs_mapping))
- return e;
- } else {
- FileSystem::Initialize();
- }
-
- // Set the current working directory form the reproducer.
- llvm::Expected<std::string> working_dir =
- repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader);
- if (!working_dir)
- return working_dir.takeError();
- if (std::error_code ec = FileSystem::Instance()
- .GetVirtualFileSystem()
- ->setCurrentWorkingDirectory(*working_dir)) {
- return llvm::errorCodeToError(ec);
- }
-
- // Set the home directory from the reproducer.
- llvm::Expected<std::string> home_dir =
- repro::GetDirectoryFrom<HomeDirectoryProvider>(loader);
- if (!home_dir)
- return home_dir.takeError();
- FileSystem::Instance().SetHomeDirectory(*home_dir);
-
- return llvm::Error::success();
- }
-
- if (repro::Generator *g = r.GetGenerator()) {
- repro::VersionProvider &vp = g->GetOrCreate<repro::VersionProvider>();
- vp.SetVersion(lldb_private::GetVersion());
-
- repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
- FileSystem::Initialize(fp.GetFileCollector());
-
- fp.RecordInterestingDirectory(
- g->GetOrCreate<repro::WorkingDirectoryProvider>().GetDirectory());
- fp.RecordInterestingDirectory(
- g->GetOrCreate<repro::HomeDirectoryProvider>().GetDirectory());
-
- return llvm::Error::success();
- }
-
- FileSystem::Initialize();
- return llvm::Error::success();
-}
-
llvm::Error SystemInitializerCommon::Initialize() {
#if defined(_WIN32)
const char *disable_crash_dialog_var = getenv("LLDB_DISABLE_CRASH_DIALOG");
}
#endif
- // If the reproducer wasn't initialized before, we can safely assume it's
- // off.
- if (!Reproducer::Initialized()) {
- if (auto e = Reproducer::Initialize(ReproducerMode::Off, llvm::None))
- return e;
- }
-
- if (auto e = InitializeFileSystem())
- return e;
+ InitializeLldbChannel();
- Log::Initialize();
+ Diagnostics::Initialize();
+ FileSystem::Initialize();
HostInfo::Initialize(m_shlib_dir_helper);
llvm::Error error = Socket::Initialize();
HostInfo::Terminate();
Log::DisableAllLogChannels();
FileSystem::Terminate();
- Reproducer::Terminate();
+ Diagnostics::Terminate();
}
#include "ABISysV_arm64.h"
+#include <optional>
#include <vector>
#include "llvm/ADT/STLExtras.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Scalar.h"
if (!reg_ctx)
return false;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+ Log *log = GetLog(LLDBLog::Expressions);
if (log) {
StreamString s;
if (value_type) {
bool is_signed = false;
size_t bit_width = 0;
- llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread);
+ std::optional<uint64_t> bit_size = value_type.GetBitSize(&thread);
if (!bit_size)
return false;
if (value_type.IsIntegerOrEnumerationType(is_signed)) {
if (byte_size <= 16) {
if (byte_size <= RegisterValue::GetMaxByteSize()) {
RegisterValue reg_value;
- error = reg_value.SetValueFromData(v0_info, data, 0, true);
+ error = reg_value.SetValueFromData(*v0_info, data, 0, true);
if (error.Success()) {
if (!reg_ctx->WriteRegister(v0_info, reg_value))
error.SetErrorString("failed to write register v0");
if (v0_info) {
if (byte_size <= v0_info->byte_size) {
RegisterValue reg_value;
- error = reg_value.SetValueFromData(v0_info, data, 0, true);
+ error = reg_value.SetValueFromData(*v0_info, data, 0, true);
if (error.Success()) {
if (!reg_ctx->WriteRegister(v0_info, reg_value))
error.SetErrorString("failed to write register v0");
uint32_t &NGRN, // NGRN (see ABI documentation)
uint32_t &NSRN, // NSRN (see ABI documentation)
DataExtractor &data) {
- llvm::Optional<uint64_t> byte_size =
+ std::optional<uint64_t> byte_size =
value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (byte_size || *byte_size == 0)
if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) {
if (!base_type)
return false;
- llvm::Optional<uint64_t> base_byte_size =
+ std::optional<uint64_t> base_byte_size =
base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (!base_byte_size)
return false;
// Make sure we have enough room in "heap_data_up"
if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) {
const size_t bytes_copied = reg_value.GetAsMemoryData(
- reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size,
- byte_order, error);
+ *reg_info, heap_data_up->GetBytes() + data_offset,
+ *base_byte_size, byte_order, error);
if (bytes_copied != *base_byte_size)
return false;
data_offset += bytes_copied;
const size_t curr_byte_size = std::min<size_t>(8, bytes_left);
const size_t bytes_copied = reg_value.GetAsMemoryData(
- reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size,
+ *reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size,
byte_order, error);
if (bytes_copied == 0)
return false;
} else {
const RegisterInfo *reg_info = nullptr;
if (is_return_value) {
- // We are assuming we are decoding this immediately after returning from
- // a function call and that the address of the structure is in x8
- reg_info = reg_ctx->GetRegisterInfoByName("x8", 0);
+ // The SysV arm64 ABI doesn't require you to write the return location
+ // back to x8 before returning from the function the way the x86_64 ABI
+ // does. It looks like all the users of this ABI currently choose not to
+ // do that, and so we can't reconstruct stack based returns on exit
+ // from the function.
+ return false;
} else {
// We are assuming we are stopped at the first instruction in a function
// and that the ABI is being respected so all parameters appear where
++NGRN;
}
- if (reg_info == nullptr)
- return false;
-
const lldb::addr_t value_addr =
reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS);
if (!reg_ctx)
return return_valobj_sp;
- llvm::Optional<uint64_t> byte_size =
- return_compiler_type.GetByteSize(&thread);
+ std::optional<uint64_t> byte_size = return_compiler_type.GetByteSize(&thread);
if (!byte_size)
return return_valobj_sp;
reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) {
Status error;
if (x0_reg_value.GetAsMemoryData(
- x0_reg_info, heap_data_up->GetBytes() + 0, 8,
+ *x0_reg_info, heap_data_up->GetBytes() + 0, 8,
byte_order, error) &&
x1_reg_value.GetAsMemoryData(
- x1_reg_info, heap_data_up->GetBytes() + 8, 8,
+ *x1_reg_info, heap_data_up->GetBytes() + 8, 8,
byte_order, error)) {
DataExtractor data(
DataBufferSP(heap_data_up.release()), byte_order,
RegisterValue reg_value;
if (reg_ctx->ReadRegister(v0_info, reg_value)) {
Status error;
- if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(),
+ if (reg_value.GetAsMemoryData(*v0_info, heap_data_up->GetBytes(),
heap_data_up->GetByteSize(), byte_order,
error)) {
DataExtractor data(DataBufferSP(heap_data_up.release()), byte_order,
// Reads code or data address mask for the current Linux process.
static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp,
llvm::StringRef reg_name) {
- // Linux configures user-space virtual addresses with top byte ignored.
- // We set default value of mask such that top byte is masked out.
- uint64_t address_mask = ~((1ULL << 56) - 1);
- // If Pointer Authentication feature is enabled then Linux exposes
- // PAC data and code mask register. Try reading relevant register
- // below and merge it with default address mask calculated above.
+ // 0 means there isn't a mask or it has not been read yet.
+ // We do not return the top byte mask unless thread_sp is valid.
+ // This prevents calls to this function before the thread is setup locking
+ // in the value to just the top byte mask, in cases where pointer
+ // authentication might also be active.
+ uint64_t address_mask = 0;
lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
if (thread_sp) {
+ // Linux configures user-space virtual addresses with top byte ignored.
+ // We set default value of mask such that top byte is masked out.
+ address_mask = ~((1ULL << 56) - 1);
+ // If Pointer Authentication feature is enabled then Linux exposes
+ // PAC data and code mask register. Try reading relevant register
+ // below and merge it with default address mask calculated above.
lldb::RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
if (reg_ctx_sp) {
const RegisterInfo *reg_info =
void ABISysV_arm64::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
-
-lldb_private::ConstString ABISysV_arm64::GetPluginNameStatic() {
- static ConstString g_name("SysV-arm64");
- return g_name;
-}
-
-// PluginInterface protocol
-
-ConstString ABISysV_arm64::GetPluginName() { return GetPluginNameStatic(); }
-
-uint32_t ABISysV_arm64::GetPluginVersion() { return 1; }
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
-/// Locates the address of the rendezvous structure. Returns the address on
-/// success and LLDB_INVALID_ADDRESS on failure.
-static addr_t ResolveRendezvousAddress(Process *process) {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+DYLDRendezvous::DYLDRendezvous(Process *process)
+ : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_executable_interpreter(false), m_current(), m_previous(),
+ m_loaded_modules(), m_soentries(), m_added_soentries(),
+ m_removed_soentries() {
+ m_thread_info.valid = false;
+ UpdateExecutablePath();
+}
+
+addr_t DYLDRendezvous::ResolveRendezvousAddress() {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
addr_t info_location;
addr_t info_addr;
Status error;
- if (!process) {
+ if (!m_process) {
LLDB_LOGF(log, "%s null process provided", __FUNCTION__);
return LLDB_INVALID_ADDRESS;
}
// Try to get it from our process. This might be a remote process and might
// grab it via some remote-specific mechanism.
- info_location = process->GetImageInfoAddress();
+ info_location = m_process->GetImageInfoAddress();
LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
// If the process fails to return an address, fall back to seeing if the
// local object file can help us find it.
if (info_location == LLDB_INVALID_ADDRESS) {
- Target *target = &process->GetTarget();
+ Target *target = &m_process->GetTarget();
if (target) {
ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
Address addr = obj_file->GetImageInfoAddress(target);
"%s resolved via direct object file approach to 0x%" PRIx64,
__FUNCTION__, info_location);
} else {
+ const Symbol *_r_debug =
+ target->GetExecutableModule()->FindFirstSymbolWithNameAndType(
+ ConstString("_r_debug"));
+ if (_r_debug) {
+ info_addr = _r_debug->GetAddress().GetLoadAddress(target);
+ if (info_addr != LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(log,
+ "%s resolved by finding symbol '_r_debug' whose value is "
+ "0x%" PRIx64,
+ __FUNCTION__, info_addr);
+ m_executable_interpreter = true;
+ return info_addr;
+ }
+ }
LLDB_LOGF(log,
"%s FAILED - direct object file approach did not yield a "
"valid address",
}
LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
- __FUNCTION__, process->GetAddressByteSize(), info_location);
+ __FUNCTION__, m_process->GetAddressByteSize(), info_location);
- info_addr = process->ReadPointerFromMemory(info_location, error);
+ info_addr = m_process->ReadPointerFromMemory(info_location, error);
if (error.Fail()) {
LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",
__FUNCTION__, error.AsCString());
return info_addr;
}
-DYLDRendezvous::DYLDRendezvous(Process *process)
- : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
- m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(),
- m_removed_soentries() {
- m_thread_info.valid = false;
- UpdateExecutablePath();
-}
-
void DYLDRendezvous::UpdateExecutablePath() {
if (m_process) {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
if (exe_mod) {
m_exe_file_spec = exe_mod->GetPlatformFileSpec();
LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",
- __FUNCTION__, m_exe_file_spec.GetCString());
+ __FUNCTION__, m_exe_file_spec.GetPath().c_str());
} else {
LLDB_LOGF(log,
"DYLDRendezvous::%s cannot cache exe module path: null "
}
bool DYLDRendezvous::Resolve() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
const size_t word_size = 4;
Rendezvous info;
__FUNCTION__, uint64_t(address_size), uint64_t(padding));
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
- cursor = info_addr = ResolveRendezvousAddress(m_process);
+ cursor = info_addr =
+ ResolveRendezvousAddress();
else
cursor = info_addr = m_rendezvous_addr;
LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
}
DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
+ // If we have a core file, we will read the current rendezvous state
+ // from the core file's memory into m_current which can be in an inconsistent
+ // state, so we can't rely on its state to determine what we should do. We
+ // always need it to load all of the shared libraries one time when we attach
+ // to a core file.
+ if (IsCoreFile())
+ return eTakeSnapshot;
+
switch (m_current.state) {
case eConsistent:
case eAdd:
case eDelete:
- // Some versions of the android dynamic linker might send two
- // notifications with state == eAdd back to back. Ignore them until we
- // get an eConsistent notification.
- if (!(m_previous.state == eConsistent ||
- (m_previous.state == eAdd && m_current.state == eDelete)))
- return eNoAction;
-
- return eTakeSnapshot;
+ return eNoAction;
}
return eNoAction;
if (action == eNoAction)
return false;
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
if (action == eTakeSnapshot) {
- m_added_soentries.clear();
- m_removed_soentries.clear();
// We already have the loaded list from the previous update so no need to
// find all the modules again.
if (!m_loaded_modules.m_list.empty())
}
bool DYLDRendezvous::UpdateSOEntries() {
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
switch (GetAction()) {
case eTakeSnapshot:
m_soentries.clear();
- m_added_soentries.clear();
- m_removed_soentries.clear();
return TakeSnapshot(m_soentries);
case eAddModules:
return AddSOEntries();
return false;
// Only add shared libraries and not the executable.
- if (!SOEntryIsMainExecutable(entry))
+ if (!SOEntryIsMainExecutable(entry)) {
+ UpdateFileSpecIfNecessary(entry);
m_soentries.push_back(entry);
+ }
}
m_loaded_modules = module_list;
// Only add shared libraries and not the executable.
if (!SOEntryIsMainExecutable(entry)) {
+ UpdateFileSpecIfNecessary(entry);
m_soentries.push_back(entry);
m_added_soentries.push_back(entry);
}
if (SOEntryIsMainExecutable(entry))
continue;
- pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
- if (pos == m_soentries.end()) {
+ UpdateFileSpecIfNecessary(entry);
+
+ if (!llvm::is_contained(m_soentries, entry)) {
m_soentries.push_back(entry);
m_added_soentries.push_back(entry);
}
return false;
for (iterator I = begin(); I != end(); ++I) {
- pos = std::find(entry_list.begin(), entry_list.end(), *I);
- if (pos == entry_list.end())
+ if (!llvm::is_contained(entry_list, *I))
m_removed_soentries.push_back(*I);
}
case llvm::Triple::Linux:
if (triple.isAndroid())
return entry.file_spec == m_exe_file_spec;
+ // If we are debugging ld.so, then all SOEntries should be treated as
+ // libraries, including the "main" one (denoted by an empty string).
+ if (!entry.file_spec && m_executable_interpreter)
+ return false;
return !entry.file_spec;
default:
return false;
if (SOEntryIsMainExecutable(entry))
continue;
+ UpdateFileSpecIfNecessary(entry);
+
entry_list.push_back(entry);
}
}
}
+void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
+ // Updates filename if empty. It is useful while debugging ld.so,
+ // when the link map returns empty string for the main executable.
+ if (!entry.file_spec) {
+ MemoryRegionInfo region;
+ Status region_status =
+ m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
+ if (!region.GetName().IsEmpty())
+ entry.file_spec.SetFile(region.GetName().AsCString(),
+ FileSpec::Style::native);
+ }
+}
+
bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
entry.clear();
log->PutCString("DYLDRendezvous SOEntries:");
for (int i = 1; I != E; ++I, ++i) {
- LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetCString());
+ LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetPath().c_str());
LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
}
}
+
+bool DYLDRendezvous::IsCoreFile() const {
+ return !m_process->IsLiveDebugSession();
+}
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/ProcessInfo.h"
#include <memory>
+#include <optional>
using namespace lldb;
using namespace lldb_private;
void DynamicLoaderPOSIXDYLD::Terminate() {}
-lldb_private::ConstString DynamicLoaderPOSIXDYLD::GetPluginName() {
- return GetPluginNameStatic();
-}
-
-lldb_private::ConstString DynamicLoaderPOSIXDYLD::GetPluginNameStatic() {
- static ConstString g_name("linux-dyld");
- return g_name;
-}
-
-const char *DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() {
+llvm::StringRef DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() {
return "Dynamic loader plug-in that watches for shared library "
"loads/unloads in POSIX processes.";
}
-uint32_t DynamicLoaderPOSIXDYLD::GetPluginVersion() { return 1; }
-
DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process,
bool force) {
bool create = force;
}
void DynamicLoaderPOSIXDYLD::DidAttach() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__,
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
m_auxv = std::make_unique<AuxVector>(m_process->GetAuxvData());
log, "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data",
__FUNCTION__, m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID);
- // ask the process if it can load any of its own modules
- auto error = m_process->LoadModules();
- LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}");
-
ModuleSP executable_sp = GetTargetExecutable();
ResolveExecutableModule(executable_sp);
m_rendezvous.UpdateExecutablePath();
}
void DynamicLoaderPOSIXDYLD::DidLaunch() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__);
ModuleSP executable;
}
void DynamicLoaderPOSIXDYLD::ProbeEntry() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ // If we have a core file, we don't need any breakpoints.
+ if (IsCoreFile())
+ return;
const addr_t entry = GetEntryPoint();
if (entry == LLDB_INVALID_ADDRESS) {
if (!baton)
return false;
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
DynamicLoaderPOSIXDYLD *const dyld_instance =
static_cast<DynamicLoaderPOSIXDYLD *>(baton);
LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64,
}
bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ // If we have a core file, we don't need any breakpoints.
+ if (IsCoreFile())
+ return false;
+
if (m_dyld_bid != LLDB_INVALID_BREAK_ID) {
LLDB_LOG(log,
"Rendezvous breakpoint breakpoint id {0} for pid {1}"
addr_t break_addr;
Target &target = m_process->GetTarget();
BreakpointSP dyld_break;
- if (m_rendezvous.IsValid()) {
+ if (m_rendezvous.IsValid() && m_rendezvous.GetBreakAddress() != 0) {
break_addr = m_rendezvous.GetBreakAddress();
LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}",
m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
LLDB_LOG(log, "Rendezvous structure is not set up yet. "
"Trying to locate rendezvous breakpoint in the interpreter "
"by symbol name.");
- ModuleSP interpreter = LoadInterpreterModule();
- if (!interpreter) {
- LLDB_LOG(log, "Can't find interpreter, rendezvous breakpoint isn't set.");
- return false;
- }
-
- // Function names from different dynamic loaders that are known to be used
- // as rendezvous between the loader and debuggers.
+ // Function names from different dynamic loaders that are known to be
+ // used as rendezvous between the loader and debuggers.
static std::vector<std::string> DebugStateCandidates{
"_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity",
"r_debug_state", "_r_debug_state", "_rtld_debug_state",
};
- FileSpecList containingModules;
- containingModules.Append(interpreter->GetFileSpec());
- dyld_break = target.CreateBreakpoint(
- &containingModules, nullptr /* containingSourceFiles */,
- DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC,
- 0, /* offset */
- eLazyBoolNo, /* skip_prologue */
- true, /* internal */
- false /* request_hardware */);
+ ModuleSP interpreter = LoadInterpreterModule();
+ if (!interpreter) {
+ FileSpecList containingModules;
+ containingModules.Append(
+ m_process->GetTarget().GetExecutableModulePointer()->GetFileSpec());
+
+ dyld_break = target.CreateBreakpoint(
+ &containingModules, /*containingSourceFiles=*/nullptr,
+ DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC,
+ /*m_offset=*/0,
+ /*skip_prologue=*/eLazyBoolNo,
+ /*internal=*/true,
+ /*request_hardware=*/false);
+ } else {
+ FileSpecList containingModules;
+ containingModules.Append(interpreter->GetFileSpec());
+ dyld_break = target.CreateBreakpoint(
+ &containingModules, /*containingSourceFiles=*/nullptr,
+ DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC,
+ /*m_offset=*/0,
+ /*skip_prologue=*/eLazyBoolNo,
+ /*internal=*/true,
+ /*request_hardware=*/false);
+ }
}
if (dyld_break->GetNumResolvedLocations() != 1) {
if (!baton)
return false;
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
DynamicLoaderPOSIXDYLD *const dyld_instance =
static_cast<DynamicLoaderPOSIXDYLD *>(baton);
LLDB_LOGF(log, "DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64,
for (; I != E; ++I) {
ModuleSP module_sp =
LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true);
- if (module_sp.get()) {
- if (module_sp->GetObjectFile()->GetBaseAddress().GetLoadAddress(
- &m_process->GetTarget()) == m_interpreter_base &&
- module_sp != m_interpreter_module.lock()) {
- // If this is a duplicate instance of ld.so, unload it. We may end up
- // with it if we load it via a different path than before (symlink
- // vs real path).
+ if (!module_sp.get())
+ continue;
+
+ if (module_sp->GetObjectFile()->GetBaseAddress().GetLoadAddress(
+ &m_process->GetTarget()) == m_interpreter_base) {
+ ModuleSP interpreter_sp = m_interpreter_module.lock();
+ if (m_interpreter_module.lock() == nullptr) {
+ m_interpreter_module = module_sp;
+ } else if (module_sp == interpreter_sp) {
+ // Module already loaded.
+ continue;
+ } else {
+ // If this is a duplicate instance of ld.so, unload it. We may end
+ // up with it if we load it via a different path than before
+ // (symlink vs real path).
// TODO: remove this once we either fix library matching or avoid
// loading the interpreter when setting the rendezvous breakpoint.
UnloadSections(module_sp);
loaded_modules.Remove(module_sp);
continue;
}
-
- loaded_modules.AppendIfNeeded(module_sp);
- new_modules.Append(module_sp);
}
+
+ loaded_modules.AppendIfNeeded(module_sp);
+ new_modules.Append(module_sp);
}
m_process->GetTarget().ModulesDidLoad(new_modules);
}
if (sym == nullptr || !sym->IsTrampoline())
return thread_plan_sp;
- ConstString sym_name = sym->GetName();
+ ConstString sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
if (!sym_name)
return thread_plan_sp;
MemoryRegionInfo info;
Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info);
if (status.Fail()) {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOG(log, "Failed to get vdso region info: {0}", status);
return;
}
Status status = m_process->GetMemoryRegionInfo(m_interpreter_base, info);
if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes ||
info.GetName().IsEmpty()) {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOG(log, "Failed to get interpreter region info: {0}", status);
return nullptr;
}
FileSpec file(info.GetName().GetCString());
ModuleSpec module_spec(file, target.GetArchitecture());
- if (ModuleSP module_sp = target.GetOrCreateModule(module_spec,
+ if (ModuleSP module_sp = target.GetOrCreateModule(module_spec,
true /* notify */)) {
UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base,
false);
return nullptr;
}
+ModuleSP DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file,
+ addr_t link_map_addr,
+ addr_t base_addr,
+ bool base_addr_is_offset) {
+ if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
+ file, link_map_addr, base_addr, base_addr_is_offset))
+ return module_sp;
+
+ // This works around an dynamic linker "bug" on android <= 23, where the
+ // dynamic linker would report the application name
+ // (e.g. com.example.myapplication) instead of the main process binary
+ // (/system/bin/app_process(32)). The logic is not sound in general (it
+ // assumes base_addr is the real address, even though it actually is a load
+ // bias), but it happens to work on android because app_process has a file
+ // address of zero.
+ // This should be removed after we drop support for android-23.
+ if (m_process->GetTarget().GetArchitecture().GetTriple().isAndroid()) {
+ MemoryRegionInfo memory_info;
+ Status error = m_process->GetMemoryRegionInfo(base_addr, memory_info);
+ if (error.Success() && memory_info.GetMapped() &&
+ memory_info.GetRange().GetRangeBase() == base_addr &&
+ !(memory_info.GetName().IsEmpty())) {
+ if (ModuleSP module_sp = DynamicLoader::LoadModuleAtAddress(
+ FileSpec(memory_info.GetName().GetStringRef()), link_map_addr,
+ base_addr, base_addr_is_offset))
+ return module_sp;
+ }
+ }
+
+ return nullptr;
+}
+
void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
DYLDRendezvous::iterator I;
DYLDRendezvous::iterator E;
ModuleList module_list;
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LoadVDSO();
I->file_spec.GetFilename());
module_list.Append(module_sp);
} else {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOGF(
log,
"DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64,
- __FUNCTION__, I->file_spec.GetCString(), I->base_addr);
+ __FUNCTION__, I->file_spec.GetPath().c_str(), I->base_addr);
}
}
m_process->GetTarget().ModulesDidLoad(module_list);
+ m_initial_modules_added = true;
}
addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() {
}
void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() {
- if (llvm::Optional<uint64_t> vdso_base =
+ if (std::optional<uint64_t> vdso_base =
m_auxv->GetAuxValue(AuxVector::AUXV_AT_SYSINFO_EHDR))
m_vdso_base = *vdso_base;
- if (llvm::Optional<uint64_t> interpreter_base =
+ if (std::optional<uint64_t> interpreter_base =
m_auxv->GetAuxValue(AuxVector::AUXV_AT_BASE))
m_interpreter_base = *interpreter_base;
}
if (m_auxv == nullptr)
return LLDB_INVALID_ADDRESS;
- llvm::Optional<uint64_t> entry_point =
+ std::optional<uint64_t> entry_point =
m_auxv->GetAuxValue(AuxVector::AUXV_AT_ENTRY);
if (!entry_point)
return LLDB_INVALID_ADDRESS;
addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid;
addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset);
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
LLDB_LOGF(log,
"DynamicLoaderPOSIXDYLD::Performed TLS lookup: "
"module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64
void DynamicLoaderPOSIXDYLD::ResolveExecutableModule(
lldb::ModuleSP &module_sp) {
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Log *log = GetLog(LLDBLog::DynamicLoader);
if (m_process == nullptr)
return;
return module_sp->GetFileSpec().GetPath() == "[vdso]";
}
+
+bool DynamicLoaderPOSIXDYLD::IsCoreFile() const {
+ return !m_process->IsLiveDebugSession();
+}
+++ /dev/null
-//===-- LibCxxBitset.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "LibCxx.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Target/Target.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace {
-
-class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
-public:
- BitsetFrontEnd(ValueObject &valobj);
-
- size_t GetIndexOfChildWithName(ConstString name) override {
- return formatters::ExtractIndexFromString(name.GetCString());
- }
-
- bool MightHaveChildren() override { return true; }
- bool Update() override;
- size_t CalculateNumChildren() override { return m_elements.size(); }
- ValueObjectSP GetChildAtIndex(size_t idx) override;
-
-private:
- // The lifetime of a ValueObject and all its derivative ValueObjects
- // (children, clones, etc.) is managed by a ClusterManager. These
- // objects are only destroyed when every shared pointer to any of them
- // is destroyed, so we must not store a shared pointer to any ValueObject
- // derived from our backend ValueObject (since we're in the same cluster).
- // Value objects created from raw data (i.e. in a different cluster) must
- // be referenced via shared pointer to keep them alive, however.
- std::vector<ValueObjectSP> m_elements;
- ValueObject* m_first = nullptr;
- CompilerType m_bool_type;
- ByteOrder m_byte_order = eByteOrderInvalid;
- uint8_t m_byte_size = 0;
-};
-} // namespace
-
-BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj)
- : SyntheticChildrenFrontEnd(valobj) {
- m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
- if (auto target_sp = m_backend.GetTargetSP()) {
- m_byte_order = target_sp->GetArchitecture().GetByteOrder();
- m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
- Update();
- }
-}
-
-bool BitsetFrontEnd::Update() {
- m_elements.clear();
- m_first = nullptr;
-
- TargetSP target_sp = m_backend.GetTargetSP();
- if (!target_sp)
- return false;
- size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay();
-
- size_t size = 0;
- if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
- size = arg->value.getLimitedValue(capping_size);
-
- m_elements.assign(size, ValueObjectSP());
-
- m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true).get();
- return false;
-}
-
-ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
- if (idx >= m_elements.size() || !m_first)
- return ValueObjectSP();
-
- if (m_elements[idx])
- return m_elements[idx];
-
- ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
- CompilerType type;
- ValueObjectSP chunk;
- // For small bitsets __first_ is not an array, but a plain size_t.
- if (m_first->GetCompilerType().IsArrayType(&type)) {
- llvm::Optional<uint64_t> bit_size =
- type.GetBitSize(ctx.GetBestExecutionContextScope());
- if (!bit_size || *bit_size == 0)
- return {};
- chunk = m_first->GetChildAtIndex(idx / *bit_size, true);
- } else {
- type = m_first->GetCompilerType();
- chunk = m_first->GetSP();
- }
- if (!type || !chunk)
- return {};
-
- llvm::Optional<uint64_t> bit_size =
- type.GetBitSize(ctx.GetBestExecutionContextScope());
- if (!bit_size || *bit_size == 0)
- return {};
- size_t chunk_idx = idx % *bit_size;
- uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
- DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
-
- m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
- data, ctx, m_bool_type);
-
- return m_elements[idx];
-}
-
-SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
- CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- if (valobj_sp)
- return new BitsetFrontEnd(*valobj_sp);
- return nullptr;
-}
+++ /dev/null
-//===-- LibCxxOptional.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "LibCxx.h"
-#include "lldb/DataFormatters/FormattersHelpers.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace {
-
-class OptionalFrontEnd : public SyntheticChildrenFrontEnd {
-public:
- OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
- Update();
- }
-
- size_t GetIndexOfChildWithName(ConstString name) override {
- return formatters::ExtractIndexFromString(name.GetCString());
- }
-
- bool MightHaveChildren() override { return true; }
- bool Update() override;
- size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; }
- ValueObjectSP GetChildAtIndex(size_t idx) override;
-
-private:
- /// True iff the option contains a value.
- bool m_has_value = false;
-};
-} // namespace
-
-bool OptionalFrontEnd::Update() {
- ValueObjectSP engaged_sp(
- m_backend.GetChildMemberWithName(ConstString("__engaged_"), true));
-
- if (!engaged_sp)
- return false;
-
- // __engaged_ is a bool flag and is true if the optional contains a value.
- // Converting it to unsigned gives us a size of 1 if it contains a value
- // and 0 if not.
- m_has_value = engaged_sp->GetValueAsUnsigned(0) == 1;
-
- return false;
-}
-
-ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) {
- if (!m_has_value)
- return ValueObjectSP();
-
- // __val_ contains the underlying value of an optional if it has one.
- // Currently because it is part of an anonymous union GetChildMemberWithName()
- // does not peer through and find it unless we are at the parent itself.
- // We can obtain the parent through __engaged_.
- ValueObjectSP val_sp(
- m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)
- ->GetParent()
- ->GetChildAtIndex(0, true)
- ->GetChildMemberWithName(ConstString("__val_"), true));
-
- if (!val_sp)
- return ValueObjectSP();
-
- CompilerType holder_type = val_sp->GetCompilerType();
-
- if (!holder_type)
- return ValueObjectSP();
-
- return val_sp->Clone(ConstString("Value"));
-}
-
-SyntheticChildrenFrontEnd *
-formatters::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *,
- lldb::ValueObjectSP valobj_sp) {
- if (valobj_sp)
- return new OptionalFrontEnd(*valobj_sp);
- return nullptr;
-}
#include <algorithm>
#include <cassert>
+#include <optional>
#include <unordered_map>
#include "lldb/Core/FileSpecList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RangeMap.h"
#include "lldb/Utility/Status.h"
LLDB_PLUGIN_DEFINE(ObjectFileELF)
-namespace {
-
// ELF note owner definitions
-const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
-const char *const LLDB_NT_OWNER_GNU = "GNU";
-const char *const LLDB_NT_OWNER_NETBSD = "NetBSD";
-const char *const LLDB_NT_OWNER_NETBSDCORE = "NetBSD-CORE";
-const char *const LLDB_NT_OWNER_OPENBSD = "OpenBSD";
-const char *const LLDB_NT_OWNER_ANDROID = "Android";
-const char *const LLDB_NT_OWNER_CORE = "CORE";
-const char *const LLDB_NT_OWNER_LINUX = "LINUX";
+static const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
+static const char *const LLDB_NT_OWNER_GNU = "GNU";
+static const char *const LLDB_NT_OWNER_NETBSD = "NetBSD";
+static const char *const LLDB_NT_OWNER_NETBSDCORE = "NetBSD-CORE";
+static const char *const LLDB_NT_OWNER_OPENBSD = "OpenBSD";
+static const char *const LLDB_NT_OWNER_ANDROID = "Android";
+static const char *const LLDB_NT_OWNER_CORE = "CORE";
+static const char *const LLDB_NT_OWNER_LINUX = "LINUX";
// ELF note type definitions
-const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01;
-const elf_word LLDB_NT_FREEBSD_ABI_SIZE = 4;
+static const elf_word LLDB_NT_FREEBSD_ABI_TAG = 0x01;
+static const elf_word LLDB_NT_FREEBSD_ABI_SIZE = 4;
-const elf_word LLDB_NT_GNU_ABI_TAG = 0x01;
-const elf_word LLDB_NT_GNU_ABI_SIZE = 16;
+static const elf_word LLDB_NT_GNU_ABI_TAG = 0x01;
+static const elf_word LLDB_NT_GNU_ABI_SIZE = 16;
-const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03;
+static const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03;
-const elf_word LLDB_NT_NETBSD_IDENT_TAG = 1;
-const elf_word LLDB_NT_NETBSD_IDENT_DESCSZ = 4;
-const elf_word LLDB_NT_NETBSD_IDENT_NAMESZ = 7;
-const elf_word LLDB_NT_NETBSD_PROCINFO = 1;
+static const elf_word LLDB_NT_NETBSD_IDENT_TAG = 1;
+static const elf_word LLDB_NT_NETBSD_IDENT_DESCSZ = 4;
+static const elf_word LLDB_NT_NETBSD_IDENT_NAMESZ = 7;
+static const elf_word LLDB_NT_NETBSD_PROCINFO = 1;
// GNU ABI note OS constants
-const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00;
-const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01;
-const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02;
+static const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00;
+static const elf_word LLDB_NT_GNU_ABI_OS_HURD = 0x01;
+static const elf_word LLDB_NT_GNU_ABI_OS_SOLARIS = 0x02;
+
+namespace {
//===----------------------------------------------------------------------===//
/// \class ELFRelocation
static unsigned RelocSymbol64(const ELFRelocation &rel);
- static unsigned RelocOffset32(const ELFRelocation &rel);
+ static elf_addr RelocOffset32(const ELFRelocation &rel);
- static unsigned RelocOffset64(const ELFRelocation &rel);
+ static elf_addr RelocOffset64(const ELFRelocation &rel);
- static unsigned RelocAddend32(const ELFRelocation &rel);
+ static elf_sxword RelocAddend32(const ELFRelocation &rel);
- static unsigned RelocAddend64(const ELFRelocation &rel);
+ static elf_sxword RelocAddend64(const ELFRelocation &rel);
+
+ bool IsRela() { return (reloc.is<ELFRela *>()); }
private:
typedef llvm::PointerUnion<ELFRel *, ELFRela *> RelocUnion;
RelocUnion reloc;
};
+} // end anonymous namespace
ELFRelocation::ELFRelocation(unsigned type) {
if (type == DT_REL || type == SHT_REL)
return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela *>());
}
-unsigned ELFRelocation::RelocOffset32(const ELFRelocation &rel) {
+elf_addr ELFRelocation::RelocOffset32(const ELFRelocation &rel) {
if (rel.reloc.is<ELFRel *>())
return rel.reloc.get<ELFRel *>()->r_offset;
else
return rel.reloc.get<ELFRela *>()->r_offset;
}
-unsigned ELFRelocation::RelocOffset64(const ELFRelocation &rel) {
+elf_addr ELFRelocation::RelocOffset64(const ELFRelocation &rel) {
if (rel.reloc.is<ELFRel *>())
return rel.reloc.get<ELFRel *>()->r_offset;
else
return rel.reloc.get<ELFRela *>()->r_offset;
}
-unsigned ELFRelocation::RelocAddend32(const ELFRelocation &rel) {
+elf_sxword ELFRelocation::RelocAddend32(const ELFRelocation &rel) {
if (rel.reloc.is<ELFRel *>())
return 0;
else
return rel.reloc.get<ELFRela *>()->r_addend;
}
-unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) {
+elf_sxword ELFRelocation::RelocAddend64(const ELFRelocation &rel) {
if (rel.reloc.is<ELFRel *>())
return 0;
else
return rel.reloc.get<ELFRela *>()->r_addend;
}
-} // end anonymous namespace
-
static user_id_t SegmentID(size_t PHdrIndex) {
return ~user_id_t(PHdrIndex);
}
const char *cstr = data.GetCStr(offset, llvm::alignTo(n_namesz, 4));
if (cstr == nullptr) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS));
+ Log *log = GetLog(LLDBLog::Symbols);
LLDB_LOGF(log, "Failed to parse note name lacking nul terminator");
return false;
}
}
+static uint32_t ppc64VariantFromElfFlags(const elf::ELFHeader &header) {
+ uint32_t endian = header.e_ident[EI_DATA];
+ if (endian == ELFDATA2LSB)
+ return ArchSpec::eCore_ppc64le_generic;
+ else
+ return ArchSpec::eCore_ppc64_generic;
+}
+
+static uint32_t loongarchVariantFromElfFlags(const elf::ELFHeader &header) {
+ uint32_t fileclass = header.e_ident[EI_CLASS];
+ switch (fileclass) {
+ case llvm::ELF::ELFCLASS32:
+ return ArchSpec::eLoongArchSubType_loongarch32;
+ case llvm::ELF::ELFCLASS64:
+ return ArchSpec::eLoongArchSubType_loongarch64;
+ default:
+ return ArchSpec::eLoongArchSubType_unknown;
+ }
+}
+
static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) {
if (header.e_machine == llvm::ELF::EM_MIPS)
return mipsVariantFromElfFlags(header);
+ else if (header.e_machine == llvm::ELF::EM_PPC64)
+ return ppc64VariantFromElfFlags(header);
else if (header.e_machine == llvm::ELF::EM_RISCV)
return riscvVariantFromElfFlags(header);
+ else if (header.e_machine == llvm::ELF::EM_LOONGARCH)
+ return loongarchVariantFromElfFlags(header);
return LLDB_INVALID_CPUTYPE;
}
PluginManager::UnregisterPlugin(CreateInstance);
}
-lldb_private::ConstString ObjectFileELF::GetPluginNameStatic() {
- static ConstString g_name("elf");
- return g_name;
-}
-
-const char *ObjectFileELF::GetPluginDescriptionStatic() {
- return "ELF object file reader.";
-}
-
ObjectFile *ObjectFileELF::CreateInstance(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp,
+ DataBufferSP data_sp,
lldb::offset_t data_offset,
const lldb_private::FileSpec *file,
lldb::offset_t file_offset,
lldb::offset_t length) {
+ bool mapped_writable = false;
if (!data_sp) {
- data_sp = MapFileData(*file, length, file_offset);
+ data_sp = MapFileDataWritable(*file, length, file_offset);
if (!data_sp)
return nullptr;
data_offset = 0;
+ mapped_writable = true;
}
assert(data_sp);
// Update the data to contain the entire file if it doesn't already
if (data_sp->GetByteSize() < length) {
- data_sp = MapFileData(*file, length, file_offset);
+ data_sp = MapFileDataWritable(*file, length, file_offset);
if (!data_sp)
return nullptr;
data_offset = 0;
+ mapped_writable = true;
+ magic = data_sp->GetBytes();
+ }
+
+ // If we didn't map the data as writable take ownership of the buffer.
+ if (!mapped_writable) {
+ data_sp = std::make_shared<DataBufferHeap>(data_sp->GetBytes(),
+ data_sp->GetByteSize());
+ data_offset = 0;
magic = data_sp->GetBytes();
}
}
ObjectFile *ObjectFileELF::CreateMemoryInstance(
- const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
+ const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,
const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT)) {
const uint8_t *magic = data_sp->GetBytes();
}
static uint32_t calc_crc32(uint32_t init, const DataExtractor &data) {
- return llvm::crc32(
- init, llvm::makeArrayRef(data.GetDataStart(), data.GetByteSize()));
+ return llvm::crc32(init,
+ llvm::ArrayRef(data.GetDataStart(), data.GetByteSize()));
}
uint32_t ObjectFileELF::CalculateELFNotesSegmentsCRC32(
const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
lldb::offset_t data_offset, lldb::offset_t file_offset,
lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
+ Log *log = GetLog(LLDBLog::Modules);
const size_t initial_count = specs.GetSize();
if (gnu_debuglink_crc) {
// Use 4 bytes of crc from the .gnu_debuglink section.
u32le data(gnu_debuglink_crc);
- uuid = UUID::fromData(&data, sizeof(data));
+ uuid = UUID(&data, sizeof(data));
} else if (core_notes_crc) {
// Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make
// it look different form .gnu_debuglink crc followed by 4 bytes
// of note segments crc.
u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)};
- uuid = UUID::fromData(data, sizeof(data));
+ uuid = UUID(data, sizeof(data));
}
}
return specs.GetSize() - initial_count;
}
-// PluginInterface protocol
-lldb_private::ConstString ObjectFileELF::GetPluginName() {
- return GetPluginNameStatic();
-}
-
-uint32_t ObjectFileELF::GetPluginVersion() { return m_plugin_version; }
// ObjectFile protocol
ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp, lldb::offset_t data_offset,
+ DataBufferSP data_sp, lldb::offset_t data_offset,
const FileSpec *file, lldb::offset_t file_offset,
lldb::offset_t length)
: ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {
}
ObjectFileELF::ObjectFileELF(const lldb::ModuleSP &module_sp,
- DataBufferSP &header_data_sp,
+ DataBufferSP header_data_sp,
const lldb::ProcessSP &process_sp,
addr_t header_addr)
: ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}
// look different form .gnu_debuglink crc - followed by 4 bytes of note
// segments crc.
u32le data[] = {u32le(g_core_uuid_magic), u32le(core_notes_crc)};
- m_uuid = UUID::fromData(data, sizeof(data));
+ m_uuid = UUID(data, sizeof(data));
}
} else {
if (!m_gnu_debuglink_crc)
if (m_gnu_debuglink_crc) {
// Use 4 bytes of crc from the .gnu_debuglink section.
u32le data(m_gnu_debuglink_crc);
- m_uuid = UUID::fromData(&data, sizeof(data));
+ m_uuid = UUID(&data, sizeof(data));
}
}
}
return m_uuid;
}
-llvm::Optional<FileSpec> ObjectFileELF::GetDebugLink() {
+std::optional<FileSpec> ObjectFileELF::GetDebugLink() {
if (m_gnu_debuglink_file.empty())
- return llvm::None;
+ return std::nullopt;
return FileSpec(m_gnu_debuglink_file);
}
ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
lldb_private::ArchSpec &arch_spec,
lldb_private::UUID &uuid) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
+ Log *log = GetLog(LLDBLog::Modules);
Status error;
lldb::offset_t offset = 0;
if (note.n_descsz >= 4) {
if (const uint8_t *buf = data.PeekData(offset, note.n_descsz)) {
// Save the build id as the UUID for the module.
- uuid = UUID::fromData(buf, note.n_descsz);
+ uuid = UUID(buf, note.n_descsz);
} else {
error.SetErrorString("failed to read GNU_BUILD_ID note payload");
return error;
// register info
arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
} else if (note.n_name == LLDB_NT_OWNER_CORE) {
- // Parse the NT_FILE to look for stuff in paths to shared libraries As
- // the contents look like this in a 64 bit ELF core file: count =
- // 0x000000000000000a (10) page_size = 0x0000000000001000 (4096) Index
- // start end file_ofs path =====
- // 0x0000000000401000 0x0000000000000000 /tmp/a.out [ 1]
- // 0x0000000000600000 0x0000000000601000 0x0000000000000000 /tmp/a.out [
- // 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 /tmp/a.out
- // [ 3] 0x00007fa79c9ed000 0x00007fa79cba8000 0x0000000000000000
- // /lib/x86_64-linux-gnu/libc-2.19.so [ 4] 0x00007fa79cba8000
- // 0x00007fa79cda7000 0x00000000000001bb /lib/x86_64-linux-
- // gnu/libc-2.19.so [ 5] 0x00007fa79cda7000 0x00007fa79cdab000
- // 0x00000000000001ba /lib/x86_64-linux-gnu/libc-2.19.so [ 6]
- // 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be /lib/x86_64
- // -linux-gnu/libc-2.19.so [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000
- // 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so [ 8]
- // 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64
- // -linux-gnu/ld-2.19.so [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000
- // 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so In the 32 bit ELFs
- // the count, page_size, start, end, file_ofs are uint32_t For reference:
- // see readelf source code (in binutils).
+ // Parse the NT_FILE to look for stuff in paths to shared libraries
+ // The contents look like this in a 64 bit ELF core file:
+ //
+ // count = 0x000000000000000a (10)
+ // page_size = 0x0000000000001000 (4096)
+ // Index start end file_ofs path
+ // ===== ------------------ ------------------ ------------------ -------------------------------------
+ // [ 0] 0x0000000000401000 0x0000000000000000 /tmp/a.out
+ // [ 1] 0x0000000000600000 0x0000000000601000 0x0000000000000000 /tmp/a.out
+ // [ 2] 0x0000000000601000 0x0000000000602000 0x0000000000000001 /tmp/a.out
+ // [ 3] 0x00007fa79c9ed000 0x00007fa79cba8000 0x0000000000000000 /lib/x86_64-linux-gnu/libc-2.19.so
+ // [ 4] 0x00007fa79cba8000 0x00007fa79cda7000 0x00000000000001bb /lib/x86_64-linux-gnu/libc-2.19.so
+ // [ 5] 0x00007fa79cda7000 0x00007fa79cdab000 0x00000000000001ba /lib/x86_64-linux-gnu/libc-2.19.so
+ // [ 6] 0x00007fa79cdab000 0x00007fa79cdad000 0x00000000000001be /lib/x86_64-linux-gnu/libc-2.19.so
+ // [ 7] 0x00007fa79cdb2000 0x00007fa79cdd5000 0x0000000000000000 /lib/x86_64-linux-gnu/ld-2.19.so
+ // [ 8] 0x00007fa79cfd4000 0x00007fa79cfd5000 0x0000000000000022 /lib/x86_64-linux-gnu/ld-2.19.so
+ // [ 9] 0x00007fa79cfd5000 0x00007fa79cfd6000 0x0000000000000023 /lib/x86_64-linux-gnu/ld-2.19.so
+ //
+ // In the 32 bit ELFs the count, page_size, start, end, file_ofs are
+ // uint32_t.
+ //
+ // For reference: see readelf source code (in binutils).
if (note.n_type == NT_FILE) {
uint64_t count = data.GetAddress(&offset);
const char *cstr;
arch_spec.SetFlags(ArchSpec::eARM_abi_hard_float);
}
+ if (arch_spec.GetMachine() == llvm::Triple::riscv32 ||
+ arch_spec.GetMachine() == llvm::Triple::riscv64) {
+ uint32_t flags = arch_spec.GetFlags();
+
+ if (header.e_flags & llvm::ELF::EF_RISCV_RVC)
+ flags |= ArchSpec::eRISCV_rvc;
+ if (header.e_flags & llvm::ELF::EF_RISCV_RVE)
+ flags |= ArchSpec::eRISCV_rve;
+
+ if ((header.e_flags & llvm::ELF::EF_RISCV_FLOAT_ABI_SINGLE) ==
+ llvm::ELF::EF_RISCV_FLOAT_ABI_SINGLE)
+ flags |= ArchSpec::eRISCV_float_abi_single;
+ else if ((header.e_flags & llvm::ELF::EF_RISCV_FLOAT_ABI_DOUBLE) ==
+ llvm::ELF::EF_RISCV_FLOAT_ABI_DOUBLE)
+ flags |= ArchSpec::eRISCV_float_abi_double;
+ else if ((header.e_flags & llvm::ELF::EF_RISCV_FLOAT_ABI_QUAD) ==
+ llvm::ELF::EF_RISCV_FLOAT_ABI_QUAD)
+ flags |= ArchSpec::eRISCV_float_abi_quad;
+
+ arch_spec.SetFlags(flags);
+ }
+
// If there are no section headers we are done.
if (header.e_shnum == 0)
return 0;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
+ Log *log = GetLog(LLDBLog::Modules);
section_headers.resize(header.e_shnum);
if (section_headers.size() != header.e_shnum)
}
static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
- if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
+ if (Name.consume_front(".debug_")) {
return llvm::StringSwitch<SectionType>(Name)
.Case("abbrev", eSectionTypeDWARFDebugAbbrev)
.Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
ObjectFile::Type ObjectType;
addr_t NextVMAddress = 0;
VMMap::Allocator Alloc;
- VMMap Segments = VMMap(Alloc);
- VMMap Sections = VMMap(Alloc);
- lldb_private::Log *Log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES);
+ VMMap Segments{Alloc};
+ VMMap Sections{Alloc};
+ lldb_private::Log *Log = GetLog(LLDBLog::Modules);
size_t SegmentCount = 0;
std::string SegmentName;
return llvm::formatv("{0}[{1}]", SegmentName, SegmentCount).str();
}
- llvm::Optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) {
+ std::optional<VMRange> GetAddressInfo(const ELFProgramHeader &H) {
if (H.p_memsz == 0) {
LLDB_LOG(Log, "Ignoring zero-sized {0} segment. Corrupt object file?",
SegmentName);
- return llvm::None;
+ return std::nullopt;
}
if (Segments.overlaps(H.p_vaddr, H.p_vaddr + H.p_memsz)) {
LLDB_LOG(Log, "Ignoring overlapping {0} segment. Corrupt object file?",
SegmentName);
- return llvm::None;
+ return std::nullopt;
}
return VMRange(H.p_vaddr, H.p_memsz);
}
- llvm::Optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) {
+ std::optional<SectionAddressInfo> GetAddressInfo(const ELFSectionHeader &H) {
VMRange Range = GetVMRange(H);
SectionSP Segment;
auto It = Segments.find(Range.GetRangeBase());
if (Range.GetByteSize() > 0 &&
Sections.overlaps(Range.GetRangeBase(), Range.GetRangeEnd())) {
LLDB_LOG(Log, "Ignoring overlapping section. Corrupt object file?");
- return llvm::None;
+ return std::nullopt;
}
if (Segment)
Range.Slide(-Segment->GetFileAddress());
auto err = lldb_private::lzma::uncompress(data.GetData(), uncompressedData);
if (err) {
GetModule()->ReportWarning(
- "An error occurred while decompression the section %s: %s",
+ "An error occurred while decompression the section {0}: {1}",
section->GetName().AsCString(), llvm::toString(std::move(err)).c_str());
return nullptr;
}
// symbols. See above for more details.
uint64_t symbol_value = symbol.st_value + symbol_value_offset;
- if (symbol_section_sp == nullptr && shndx == SHN_ABS &&
- symbol.st_size != 0) {
- // We don't have a section for a symbol with non-zero size. Create a new
- // section for it so the address range covered by the symbol is also
- // covered by the module (represented through the section list). It is
- // needed so module lookup for the addresses covered by this symbol will
- // be successfull. This case happens for absolute symbols.
- ConstString fake_section_name(std::string(".absolute.") + symbol_name);
- symbol_section_sp =
- std::make_shared<Section>(module_sp, this, SHN_ABS, fake_section_name,
- eSectionTypeAbsoluteAddress, symbol_value,
- symbol.st_size, 0, 0, 0, SHF_ALLOC);
-
- module_section_list->AddSection(symbol_section_sp);
- section_list->AddSection(symbol_section_sp);
- }
-
if (symbol_section_sp &&
CalculateType() != ObjectFile::Type::eTypeObjectFile)
symbol_value -= symbol_section_sp->GetFileAddress();
rel_data, symtab_data, strtab_data);
}
+static void ApplyELF64ABS64Relocation(Symtab *symtab, ELFRelocation &rel,
+ DataExtractor &debug_data,
+ Section *rel_section) {
+ Symbol *symbol = symtab->FindSymbolByID(ELFRelocation::RelocSymbol64(rel));
+ if (symbol) {
+ addr_t value = symbol->GetAddressRef().GetFileAddress();
+ DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer();
+ // ObjectFileELF creates a WritableDataBuffer in CreateInstance.
+ WritableDataBuffer *data_buffer =
+ llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
+ uint64_t *dst = reinterpret_cast<uint64_t *>(
+ data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset64(rel));
+ uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel);
+ memcpy(dst, &val_offset, sizeof(uint64_t));
+ }
+}
+
+static void ApplyELF64ABS32Relocation(Symtab *symtab, ELFRelocation &rel,
+ DataExtractor &debug_data,
+ Section *rel_section, bool is_signed) {
+ Symbol *symbol = symtab->FindSymbolByID(ELFRelocation::RelocSymbol64(rel));
+ if (symbol) {
+ addr_t value = symbol->GetAddressRef().GetFileAddress();
+ value += ELFRelocation::RelocAddend32(rel);
+ if ((!is_signed && (value > UINT32_MAX)) ||
+ (is_signed &&
+ ((int64_t)value > INT32_MAX || (int64_t)value < INT32_MIN))) {
+ Log *log = GetLog(LLDBLog::Modules);
+ LLDB_LOGF(log, "Failed to apply debug info relocations");
+ return;
+ }
+ uint32_t truncated_addr = (value & 0xFFFFFFFF);
+ DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer();
+ // ObjectFileELF creates a WritableDataBuffer in CreateInstance.
+ WritableDataBuffer *data_buffer =
+ llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
+ uint32_t *dst = reinterpret_cast<uint32_t *>(
+ data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset32(rel));
+ memcpy(dst, &truncated_addr, sizeof(uint32_t));
+ }
+}
+
unsigned ObjectFileELF::ApplyRelocations(
Symtab *symtab, const ELFHeader *hdr, const ELFSectionHeader *rel_hdr,
const ELFSectionHeader *symtab_hdr, const ELFSectionHeader *debug_hdr,
}
for (unsigned i = 0; i < num_relocations; ++i) {
- if (!rel.Parse(rel_data, &offset))
+ if (!rel.Parse(rel_data, &offset)) {
+ GetModule()->ReportError(".rel{0}[{1:d}] failed to parse relocation",
+ rel_section->GetName().AsCString(), i);
break;
-
+ }
Symbol *symbol = nullptr;
if (hdr->Is32Bit()) {
switch (reloc_type(rel)) {
case R_386_32:
- case R_386_PC32:
- default:
- // FIXME: This asserts with this input:
- //
- // foo.cpp
- // int main(int argc, char **argv) { return 0; }
- //
- // clang++.exe --target=i686-unknown-linux-gnu -g -c foo.cpp -o foo.o
- //
- // and running this on the foo.o module.
- assert(false && "unexpected relocation type");
- }
- } else {
- switch (reloc_type(rel)) {
- case R_AARCH64_ABS64:
- case R_X86_64_64: {
symbol = symtab->FindSymbolByID(reloc_symbol(rel));
if (symbol) {
- addr_t value = symbol->GetAddressRef().GetFileAddress();
+ addr_t f_offset =
+ rel_section->GetFileOffset() + ELFRelocation::RelocOffset32(rel);
DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer();
- uint64_t *dst = reinterpret_cast<uint64_t *>(
- data_buffer_sp->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset64(rel));
- uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel);
- memcpy(dst, &val_offset, sizeof(uint64_t));
- }
- break;
- }
- case R_X86_64_32:
- case R_X86_64_32S:
- case R_AARCH64_ABS32: {
- symbol = symtab->FindSymbolByID(reloc_symbol(rel));
- if (symbol) {
+ // ObjectFileELF creates a WritableDataBuffer in CreateInstance.
+ WritableDataBuffer *data_buffer =
+ llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
+ uint32_t *dst = reinterpret_cast<uint32_t *>(
+ data_buffer->GetBytes() + f_offset);
+
addr_t value = symbol->GetAddressRef().GetFileAddress();
- value += ELFRelocation::RelocAddend32(rel);
- if ((reloc_type(rel) == R_X86_64_32 && (value > UINT32_MAX)) ||
- (reloc_type(rel) == R_X86_64_32S &&
- ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN)) ||
- (reloc_type(rel) == R_AARCH64_ABS32 &&
- ((int64_t)value > INT32_MAX && (int64_t)value < INT32_MIN))) {
- Log *log =
- lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES);
- LLDB_LOGF(log, "Failed to apply debug info relocations");
- break;
+ if (rel.IsRela()) {
+ value += ELFRelocation::RelocAddend32(rel);
+ } else {
+ value += *dst;
}
- uint32_t truncated_addr = (value & 0xFFFFFFFF);
- DataBufferSP &data_buffer_sp = debug_data.GetSharedDataBuffer();
- uint32_t *dst = reinterpret_cast<uint32_t *>(
- data_buffer_sp->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset32(rel));
- memcpy(dst, &truncated_addr, sizeof(uint32_t));
+ *dst = value;
+ } else {
+ GetModule()->ReportError(".rel{0}[{1}] unknown symbol id: {2:d}",
+ rel_section->GetName().AsCString(), i,
+ reloc_symbol(rel));
}
break;
+ case R_386_PC32:
+ default:
+ GetModule()->ReportError("unsupported 32-bit relocation:"
+ " .rel{0}[{1}], type {2}",
+ rel_section->GetName().AsCString(), i,
+ reloc_type(rel));
}
- case R_X86_64_PC32:
+ } else {
+ switch (hdr->e_machine) {
+ case llvm::ELF::EM_AARCH64:
+ switch (reloc_type(rel)) {
+ case R_AARCH64_ABS64:
+ ApplyELF64ABS64Relocation(symtab, rel, debug_data, rel_section);
+ break;
+ case R_AARCH64_ABS32:
+ ApplyELF64ABS32Relocation(symtab, rel, debug_data, rel_section, true);
+ break;
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ break;
+ case llvm::ELF::EM_LOONGARCH:
+ switch (reloc_type(rel)) {
+ case R_LARCH_64:
+ ApplyELF64ABS64Relocation(symtab, rel, debug_data, rel_section);
+ break;
+ case R_LARCH_32:
+ ApplyELF64ABS32Relocation(symtab, rel, debug_data, rel_section, true);
+ break;
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ break;
+ case llvm::ELF::EM_X86_64:
+ switch (reloc_type(rel)) {
+ case R_X86_64_64:
+ ApplyELF64ABS64Relocation(symtab, rel, debug_data, rel_section);
+ break;
+ case R_X86_64_32:
+ ApplyELF64ABS32Relocation(symtab, rel, debug_data, rel_section,
+ false);
+ break;
+ case R_X86_64_32S:
+ ApplyELF64ABS32Relocation(symtab, rel, debug_data, rel_section, true);
+ break;
+ case R_X86_64_PC32:
+ default:
+ assert(false && "unexpected relocation type");
+ }
+ break;
default:
- assert(false && "unexpected relocation type");
+ assert(false && "unsupported machine");
}
}
}
return 0;
}
-Symtab *ObjectFileELF::GetSymtab() {
+void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
ModuleSP module_sp(GetModule());
if (!module_sp)
- return nullptr;
+ return;
- Progress progress(llvm::formatv("Parsing symbol table for {0}",
- m_file.GetFilename().AsCString("<Unknown>")));
+ Progress progress(
+ llvm::formatv("Parsing symbol table for {0}",
+ m_file.GetFilename().AsCString("<Unknown>")));
+ ElapsedTime elapsed(module_sp->GetSymtabParseTime());
// We always want to use the main object file so we (hopefully) only have one
// cached copy of our symtab, dynamic sections, etc.
ObjectFile *module_obj_file = module_sp->GetObjectFile();
if (module_obj_file && module_obj_file != this)
- return module_obj_file->GetSymtab();
-
- if (m_symtab_up == nullptr) {
- SectionList *section_list = module_sp->GetSectionList();
- if (!section_list)
- return nullptr;
+ return module_obj_file->ParseSymtab(lldb_symtab);
- uint64_t symbol_id = 0;
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
-
- // Sharable objects and dynamic executables usually have 2 distinct symbol
- // tables, one named ".symtab", and the other ".dynsym". The dynsym is a
- // smaller version of the symtab that only contains global symbols. The
- // information found in the dynsym is therefore also found in the symtab,
- // while the reverse is not necessarily true.
- Section *symtab =
- section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get();
- if (symtab) {
- m_symtab_up = std::make_unique<Symtab>(symtab->GetObjectFile());
- symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab);
- }
+ SectionList *section_list = module_sp->GetSectionList();
+ if (!section_list)
+ return;
- // The symtab section is non-allocable and can be stripped, while the
- // .dynsym section which should always be always be there. To support the
- // minidebuginfo case we parse .dynsym when there's a .gnu_debuginfo
- // section, nomatter if .symtab was already parsed or not. This is because
- // minidebuginfo normally removes the .symtab symbols which have their
- // matching .dynsym counterparts.
- if (!symtab ||
- GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) {
- Section *dynsym =
- section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
- .get();
- if (dynsym) {
- if (!m_symtab_up)
- m_symtab_up = std::make_unique<Symtab>(dynsym->GetObjectFile());
- symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym);
- }
- }
+ uint64_t symbol_id = 0;
- // DT_JMPREL
- // If present, this entry's d_ptr member holds the address of
- // relocation
- // entries associated solely with the procedure linkage table.
- // Separating
- // these relocation entries lets the dynamic linker ignore them during
- // process initialization, if lazy binding is enabled. If this entry is
- // present, the related entries of types DT_PLTRELSZ and DT_PLTREL must
- // also be present.
- const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL);
- if (symbol) {
- const ELFDynamic *pltrelsz = FindDynamicSymbol(DT_PLTRELSZ);
- assert(pltrelsz != NULL);
- // Synthesize trampoline symbols to help navigate the PLT.
- addr_t addr = symbol->d_ptr;
- Section *reloc_section =
- section_list->FindSectionContainingFileAddress(addr).get();
- if (reloc_section && pltrelsz->d_val > 0) {
- user_id_t reloc_id = reloc_section->GetID();
- const ELFSectionHeaderInfo *reloc_header =
- GetSectionHeaderByIndex(reloc_id);
- if (reloc_header) {
- if (m_symtab_up == nullptr)
- m_symtab_up =
- std::make_unique<Symtab>(reloc_section->GetObjectFile());
-
- ParseTrampolineSymbols(m_symtab_up.get(), symbol_id, reloc_header,
- reloc_id);
- }
- }
- }
-
- if (DWARFCallFrameInfo *eh_frame =
- GetModule()->GetUnwindTable().GetEHFrameInfo()) {
- if (m_symtab_up == nullptr)
- m_symtab_up = std::make_unique<Symtab>(this);
- ParseUnwindSymbols(m_symtab_up.get(), eh_frame);
+ // Sharable objects and dynamic executables usually have 2 distinct symbol
+ // tables, one named ".symtab", and the other ".dynsym". The dynsym is a
+ // smaller version of the symtab that only contains global symbols. The
+ // information found in the dynsym is therefore also found in the symtab,
+ // while the reverse is not necessarily true.
+ Section *symtab =
+ section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get();
+ if (symtab)
+ symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, symtab);
+
+ // The symtab section is non-allocable and can be stripped, while the
+ // .dynsym section which should always be always be there. To support the
+ // minidebuginfo case we parse .dynsym when there's a .gnu_debuginfo
+ // section, nomatter if .symtab was already parsed or not. This is because
+ // minidebuginfo normally removes the .symtab symbols which have their
+ // matching .dynsym counterparts.
+ if (!symtab ||
+ GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) {
+ Section *dynsym =
+ section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
+ .get();
+ if (dynsym)
+ symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, dynsym);
+ }
+
+ // DT_JMPREL
+ // If present, this entry's d_ptr member holds the address of
+ // relocation
+ // entries associated solely with the procedure linkage table.
+ // Separating
+ // these relocation entries lets the dynamic linker ignore them during
+ // process initialization, if lazy binding is enabled. If this entry is
+ // present, the related entries of types DT_PLTRELSZ and DT_PLTREL must
+ // also be present.
+ const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL);
+ if (symbol) {
+ const ELFDynamic *pltrelsz = FindDynamicSymbol(DT_PLTRELSZ);
+ assert(pltrelsz != NULL);
+ // Synthesize trampoline symbols to help navigate the PLT.
+ addr_t addr = symbol->d_ptr;
+ Section *reloc_section =
+ section_list->FindSectionContainingFileAddress(addr).get();
+ if (reloc_section && pltrelsz->d_val > 0) {
+ user_id_t reloc_id = reloc_section->GetID();
+ const ELFSectionHeaderInfo *reloc_header =
+ GetSectionHeaderByIndex(reloc_id);
+ if (reloc_header)
+ ParseTrampolineSymbols(&lldb_symtab, symbol_id, reloc_header, reloc_id);
}
+ }
- // If we still don't have any symtab then create an empty instance to avoid
- // do the section lookup next time.
- if (m_symtab_up == nullptr)
- m_symtab_up = std::make_unique<Symtab>(this);
-
- // In the event that there's no symbol entry for the entry point we'll
- // artificially create one. We delegate to the symtab object the figuring
- // out of the proper size, this will usually make it span til the next
- // symbol it finds in the section. This means that if there are missing
- // symbols the entry point might span beyond its function definition.
- // We're fine with this as it doesn't make it worse than not having a
- // symbol entry at all.
- if (CalculateType() == eTypeExecutable) {
- ArchSpec arch = GetArchitecture();
- auto entry_point_addr = GetEntryPointAddress();
- bool is_valid_entry_point =
- entry_point_addr.IsValid() && entry_point_addr.IsSectionOffset();
- addr_t entry_point_file_addr = entry_point_addr.GetFileAddress();
- if (is_valid_entry_point && !m_symtab_up->FindSymbolContainingFileAddress(
- entry_point_file_addr)) {
- uint64_t symbol_id = m_symtab_up->GetNumSymbols();
- // Don't set the name for any synthetic symbols, the Symbol
- // object will generate one if needed when the name is accessed
- // via accessors.
- SectionSP section_sp = entry_point_addr.GetSection();
- Symbol symbol(
- /*symID=*/symbol_id,
- /*name=*/llvm::StringRef(), // Name will be auto generated.
- /*type=*/eSymbolTypeCode,
- /*external=*/true,
- /*is_debug=*/false,
- /*is_trampoline=*/false,
- /*is_artificial=*/true,
- /*section_sp=*/section_sp,
- /*offset=*/0,
- /*size=*/0, // FDE can span multiple symbols so don't use its size.
- /*size_is_valid=*/false,
- /*contains_linker_annotations=*/false,
- /*flags=*/0);
- // When the entry point is arm thumb we need to explicitly set its
- // class address to reflect that. This is important because expression
- // evaluation relies on correctly setting a breakpoint at this
- // address.
- if (arch.GetMachine() == llvm::Triple::arm &&
- (entry_point_file_addr & 1)) {
- symbol.GetAddressRef().SetOffset(entry_point_addr.GetOffset() ^ 1);
- m_address_class_map[entry_point_file_addr ^ 1] =
- AddressClass::eCodeAlternateISA;
- } else {
- m_address_class_map[entry_point_file_addr] = AddressClass::eCode;
- }
- m_symtab_up->AddSymbol(symbol);
+ if (DWARFCallFrameInfo *eh_frame =
+ GetModule()->GetUnwindTable().GetEHFrameInfo()) {
+ ParseUnwindSymbols(&lldb_symtab, eh_frame);
+ }
+
+ // In the event that there's no symbol entry for the entry point we'll
+ // artificially create one. We delegate to the symtab object the figuring
+ // out of the proper size, this will usually make it span til the next
+ // symbol it finds in the section. This means that if there are missing
+ // symbols the entry point might span beyond its function definition.
+ // We're fine with this as it doesn't make it worse than not having a
+ // symbol entry at all.
+ if (CalculateType() == eTypeExecutable) {
+ ArchSpec arch = GetArchitecture();
+ auto entry_point_addr = GetEntryPointAddress();
+ bool is_valid_entry_point =
+ entry_point_addr.IsValid() && entry_point_addr.IsSectionOffset();
+ addr_t entry_point_file_addr = entry_point_addr.GetFileAddress();
+ if (is_valid_entry_point && !lldb_symtab.FindSymbolContainingFileAddress(
+ entry_point_file_addr)) {
+ uint64_t symbol_id = lldb_symtab.GetNumSymbols();
+ // Don't set the name for any synthetic symbols, the Symbol
+ // object will generate one if needed when the name is accessed
+ // via accessors.
+ SectionSP section_sp = entry_point_addr.GetSection();
+ Symbol symbol(
+ /*symID=*/symbol_id,
+ /*name=*/llvm::StringRef(), // Name will be auto generated.
+ /*type=*/eSymbolTypeCode,
+ /*external=*/true,
+ /*is_debug=*/false,
+ /*is_trampoline=*/false,
+ /*is_artificial=*/true,
+ /*section_sp=*/section_sp,
+ /*offset=*/0,
+ /*size=*/0, // FDE can span multiple symbols so don't use its size.
+ /*size_is_valid=*/false,
+ /*contains_linker_annotations=*/false,
+ /*flags=*/0);
+ // When the entry point is arm thumb we need to explicitly set its
+ // class address to reflect that. This is important because expression
+ // evaluation relies on correctly setting a breakpoint at this
+ // address.
+ if (arch.GetMachine() == llvm::Triple::arm &&
+ (entry_point_file_addr & 1)) {
+ symbol.GetAddressRef().SetOffset(entry_point_addr.GetOffset() ^ 1);
+ m_address_class_map[entry_point_file_addr ^ 1] =
+ AddressClass::eCodeAlternateISA;
+ } else {
+ m_address_class_map[entry_point_file_addr] = AddressClass::eCode;
}
+ lldb_symtab.AddSymbol(symbol);
}
-
- m_symtab_up->CalculateSymbolSizes();
}
-
- return m_symtab_up.get();
}
void ObjectFileELF::RelocateSection(lldb_private::Section *section)
return section->GetObjectFile()->ReadSectionData(section, section_data);
size_t result = ObjectFile::ReadSectionData(section, section_data);
- if (result == 0 || !llvm::object::Decompressor::isCompressedELFSection(
- section->Get(), section->GetName().GetStringRef()))
+ if (result == 0 || !(section->Get() & llvm::ELF::SHF_COMPRESSED))
return result;
auto Decompressor = llvm::object::Decompressor::create(
GetByteOrder() == eByteOrderLittle, GetAddressByteSize() == 8);
if (!Decompressor) {
GetModule()->ReportWarning(
- "Unable to initialize decompressor for section '%s': %s",
+ "Unable to initialize decompressor for section '{0}': {1}",
section->GetName().GetCString(),
llvm::toString(Decompressor.takeError()).c_str());
section_data.Clear();
auto buffer_sp =
std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0);
if (auto error = Decompressor->decompress(
- {reinterpret_cast<char *>(buffer_sp->GetBytes()),
- size_t(buffer_sp->GetByteSize())})) {
- GetModule()->ReportWarning(
- "Decompression of section '%s' failed: %s",
- section->GetName().GetCString(),
- llvm::toString(std::move(error)).c_str());
+ {buffer_sp->GetBytes(), size_t(buffer_sp->GetByteSize())})) {
+ GetModule()->ReportWarning("Decompression of section '{0}' failed: {1}",
+ section->GetName().GetCString(),
+ llvm::toString(std::move(error)).c_str());
section_data.Clear();
return 0;
}
}
return loadables;
}
+
+lldb::WritableDataBufferSP
+ObjectFileELF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
+ uint64_t Offset) {
+ return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,
+ Offset);
+}
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Status.h"
PlatformSP PlatformOpenBSD::CreateInstance(bool force, const ArchSpec *arch) {
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ Log *log = GetLog(LLDBLog::Platform);
LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
arch ? arch->GetArchitectureName() : "<null>",
arch ? arch->GetTriple().getTriple() : "<null>");
return PlatformSP();
}
-ConstString PlatformOpenBSD::GetPluginNameStatic(bool is_host) {
- if (is_host) {
- static ConstString g_host_name(Platform::GetHostPlatformName());
- return g_host_name;
- } else {
- static ConstString g_remote_name("remote-openbsd");
- return g_remote_name;
- }
-}
-
-const char *PlatformOpenBSD::GetPluginDescriptionStatic(bool is_host) {
+llvm::StringRef PlatformOpenBSD::GetPluginDescriptionStatic(bool is_host) {
if (is_host)
return "Local OpenBSD user platform plug-in.";
- else
- return "Remote OpenBSD user platform plug-in.";
-}
-
-ConstString PlatformOpenBSD::GetPluginName() {
- return GetPluginNameStatic(IsHost());
+ return "Remote OpenBSD user platform plug-in.";
}
void PlatformOpenBSD::Initialize() {
/// Default Constructor
PlatformOpenBSD::PlatformOpenBSD(bool is_host)
: PlatformPOSIX(is_host) // This is the local host platform
-{}
-
-bool PlatformOpenBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
- ArchSpec &arch) {
- if (IsHost()) {
- ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
- if (hostArch.GetTriple().isOSOpenBSD()) {
- if (idx == 0) {
- arch = hostArch;
- return arch.IsValid();
- }
- }
+{
+ if (is_host) {
+ m_supported_architectures.push_back(HostInfo::GetArchitecture());
} else {
- if (m_remote_platform_sp)
- return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
-
- llvm::Triple triple;
- // Set the OS to OpenBSD
- triple.setOS(llvm::Triple::OpenBSD);
- // Set the architecture
- switch (idx) {
- case 0:
- triple.setArchName("x86_64");
- break;
- case 1:
- triple.setArchName("i386");
- break;
- case 2:
- triple.setArchName("aarch64");
- break;
- case 3:
- triple.setArchName("arm");
- break;
- default:
- return false;
- }
- // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the
- // vendor by calling triple.SetVendorName("unknown") so that it is a
- // "unspecified unknown". This means when someone calls
- // triple.GetVendorName() it will return an empty string which indicates
- // that the vendor can be set when two architectures are merged
-
- // Now set the triple into "arch" and return true
- arch.SetTriple(triple);
- return true;
+ m_supported_architectures =
+ CreateArchList({llvm::Triple::x86_64, llvm::Triple::x86,
+ llvm::Triple::aarch64, llvm::Triple::arm},
+ llvm::Triple::OpenBSD);
}
- return false;
+}
+
+std::vector<ArchSpec>
+PlatformOpenBSD::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
+ return m_supported_architectures;
}
void PlatformOpenBSD::GetStatus(Stream &strm) {
}
}
-// For local debugging, OpenBSD will override the debug logic to use llgs-launch
-// rather than lldb-launch, llgs-attach. This differs from current lldb-
-// launch, debugserver-attach approach on MacOSX.
-lldb::ProcessSP
-PlatformOpenBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
- Target *target, // Can be NULL, if NULL create a new
- // target, else use existing one
- Status &error) {
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
- LLDB_LOG(log, "target {0}", target);
-
- // If we're a remote host, use standard behavior from parent class.
- if (!IsHost())
- return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error);
-
- //
- // For local debugging, we'll insist on having ProcessGDBRemote create the
- // process.
- //
-
- ProcessSP process_sp;
-
- // Make sure we stop at the entry point
- launch_info.GetFlags().Set(eLaunchFlagDebug);
-
- // We always launch the process we are going to debug in a separate process
- // group, since then we can handle ^C interrupts ourselves w/o having to
- // worry about the target getting them as well.
- launch_info.SetLaunchInSeparateProcessGroup(true);
-
- // Ensure we have a target.
- if (target == nullptr) {
- LLDB_LOG(log, "creating new target");
- TargetSP new_target_sp;
- error = debugger.GetTargetList().CreateTarget(debugger, "", "", eLoadDependentsNo,
- nullptr, new_target_sp);
- if (error.Fail()) {
- LLDB_LOG(log, "failed to create new target: {0}", error);
- return process_sp;
- }
-
- target = new_target_sp.get();
- if (!target) {
- error.SetErrorString("CreateTarget() returned nullptr");
- LLDB_LOG(log, "error: {0}", error);
- return process_sp;
- }
- }
-
- // Mark target as currently selected target.
- //debugger.GetTargetList().SetSelectedTarget(target);
-
- // Now create the gdb-remote process.
- LLDB_LOG(log, "having target create process with gdb-remote plugin");
- process_sp = target->CreateProcess(
- launch_info.GetListener(), "gdb-remote", nullptr, true);
-
- if (!process_sp) {
- error.SetErrorString("CreateProcess() failed for gdb-remote process");
- LLDB_LOG(log, "error: {0}", error);
- return process_sp;
- }
-
- LLDB_LOG(log, "successfully created process");
- // Adjust launch for a hijacker.
- ListenerSP listener_sp;
- if (!launch_info.GetHijackListener()) {
- LLDB_LOG(log, "setting up hijacker");
- listener_sp =
- Listener::MakeListener("lldb.PlatformOpenBSD.DebugProcess.hijack");
- launch_info.SetHijackListener(listener_sp);
- process_sp->HijackProcessEvents(listener_sp);
- }
-
- // Log file actions.
- if (log) {
- LLDB_LOG(log, "launching process with the following file actions:");
- StreamString stream;
- size_t i = 0;
- const FileAction *file_action;
- while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
- file_action->Dump(stream);
- LLDB_LOG(log, "{0}", stream.GetData());
- stream.Clear();
- }
- }
-
- // Do the launch.
- error = process_sp->Launch(launch_info);
- if (error.Success()) {
- // Handle the hijacking of process events.
- if (listener_sp) {
- const StateType state = process_sp->WaitForProcessToStop(
- llvm::None, NULL, false, listener_sp);
-
- LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state);
- }
-
- // Hook up process PTY if we have one (which we should for local debugging
- // with llgs).
- int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
- if (pty_fd != PseudoTerminal::invalid_fd) {
- process_sp->SetSTDIOFileDescriptor(pty_fd);
- LLDB_LOG(log, "hooked up STDIO pty to process");
- } else
- LLDB_LOG(log, "not using process STDIO pty");
- } else {
- LLDB_LOG(log, "process launch failed: {0}", error);
- // FIXME figure out appropriate cleanup here. Do we delete the target? Do
- // we delete the process? Does our caller do that?
- }
-
- return process_sp;
-}
-
void PlatformOpenBSD::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
}
// lldb_private::PluginInterface functions
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
- static ConstString GetPluginNameStatic(bool is_host);
-
- static const char *GetPluginDescriptionStatic(bool is_host);
+ static llvm::StringRef GetPluginNameStatic(bool is_host) {
+ return is_host ? Platform::GetHostPlatformName() : "remote-openbsd";
+ }
- ConstString GetPluginName() override;
+ static llvm::StringRef GetPluginDescriptionStatic(bool is_host);
- uint32_t GetPluginVersion() override { return 1; }
+ llvm::StringRef GetPluginName() override {
+ return GetPluginNameStatic(IsHost());
+ }
// lldb_private::Platform functions
- const char *GetDescription() override {
+ llvm::StringRef GetDescription() override {
return GetPluginDescriptionStatic(IsHost());
}
void GetStatus(Stream &strm) override;
- bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+ std::vector<ArchSpec>
+ GetSupportedArchitectures(const ArchSpec &process_host_arch) override;
bool CanDebugProcess() override;
- lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
- Target *target, Status &error) override;
-
void CalculateTrapHandlerSymbolNames() override;
MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
lldb_private::FileSpec LocateExecutable(const char *basename) override;
+ std::vector<ArchSpec> m_supported_architectures;
};
} // namespace platform_openbsd
add_subdirectory(elf-core)
add_subdirectory(mach-core)
add_subdirectory(minidump)
+add_subdirectory(FreeBSDKernel)
+++ /dev/null
-//===-- IntelPTManager.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include <algorithm>
-#include <fstream>
-#include <sstream>
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/MathExtras.h"
-
-#include "IntelPTManager.h"
-#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "lldb/Host/linux/Support.h"
-#include "lldb/Utility/StreamString.h"
-
-#include <sys/ioctl.h>
-#include <sys/syscall.h>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace process_linux;
-using namespace llvm;
-
-const char *kOSEventIntelPTTypeFile =
- "/sys/bus/event_source/devices/intel_pt/type";
-
-const char *kPSBPeriodCapFile =
- "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc";
-
-const char *kPSBPeriodValidValuesFile =
- "/sys/bus/event_source/devices/intel_pt/caps/psb_periods";
-
-const char *kTSCBitOffsetFile =
- "/sys/bus/event_source/devices/intel_pt/format/tsc";
-
-const char *kPSBPeriodBitOffsetFile =
- "/sys/bus/event_source/devices/intel_pt/format/psb_period";
-
-enum IntelPTConfigFileType {
- Hex = 0,
- // 0 or 1
- ZeroOne,
- Decimal,
- // a bit index file always starts with the prefix config: following by an int,
- // which represents the offset of the perf_event_attr.config value where to
- // store a given configuration.
- BitOffset
-};
-
-static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
- IntelPTConfigFileType type) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
- MemoryBuffer::getFileAsStream(file);
-
- if (!stream)
- return createStringError(inconvertibleErrorCode(),
- "Can't open the file '%s'", file);
-
- uint32_t value = 0;
- StringRef text_buffer = stream.get()->getBuffer();
-
- if (type == BitOffset) {
- const char *prefix = "config:";
- if (!text_buffer.startswith(prefix))
- return createStringError(inconvertibleErrorCode(),
- "The file '%s' contents doesn't start with '%s'",
- file, prefix);
- text_buffer = text_buffer.substr(strlen(prefix));
- }
-
- auto getRadix = [&]() {
- switch (type) {
- case Hex:
- return 16;
- case ZeroOne:
- case Decimal:
- case BitOffset:
- return 10;
- }
- };
-
- auto createError = [&](const char *expected_value_message) {
- return createStringError(
- inconvertibleErrorCode(),
- "The file '%s' has an invalid value. It should be %s.", file,
- expected_value_message);
- };
-
- if (text_buffer.trim().consumeInteger(getRadix(), value) ||
- (type == ZeroOne && value != 0 && value != 1)) {
- switch (type) {
- case Hex:
- return createError("an unsigned hexadecimal int");
- case ZeroOne:
- return createError("0 or 1");
- case Decimal:
- case BitOffset:
- return createError("an unsigned decimal int");
- }
- }
- return value;
-}
-/// Return the Linux perf event type for Intel PT.
-static Expected<uint32_t> GetOSEventType() {
- return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile,
- IntelPTConfigFileType::Decimal);
-}
-
-static Error CheckPsbPeriod(size_t psb_period) {
- Expected<uint32_t> cap =
- ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne);
- if (!cap)
- return cap.takeError();
- if (*cap == 0)
- return createStringError(inconvertibleErrorCode(),
- "psb_period is unsupported in the system.");
-
- Expected<uint32_t> valid_values = ReadIntelPTConfigFile(
- kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex);
- if (!valid_values)
- return valid_values.takeError();
-
- if (valid_values.get() & (1 << psb_period))
- return Error::success();
-
- std::ostringstream error;
- // 0 is always a valid value
- error << "Invalid psb_period. Valid values are: 0";
- uint32_t mask = valid_values.get();
- while (mask) {
- int index = __builtin_ctz(mask);
- if (index > 0)
- error << ", " << index;
- // clear the lowest bit
- mask &= mask - 1;
- }
- error << ".";
- return createStringError(inconvertibleErrorCode(), error.str().c_str());
-}
-
-size_t IntelPTThreadTrace::GetTraceBufferSize() const {
- return m_mmap_meta->aux_size;
-}
-
-static Expected<uint64_t>
-GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) {
- uint64_t config = 0;
- // tsc is always supported
- if (enable_tsc) {
- if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
- kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset))
- config |= 1 << *offset;
- else
- return offset.takeError();
- }
- if (psb_period) {
- if (Error error = CheckPsbPeriod(*psb_period))
- return std::move(error);
-
- if (Expected<uint32_t> offset = ReadIntelPTConfigFile(
- kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset))
- config |= *psb_period << *offset;
- else
- return offset.takeError();
- }
- return config;
-}
-
-Error IntelPTThreadTrace::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
- uint64_t buffer_size, bool enable_tsc,
- Optional<size_t> psb_period) {
-#ifndef PERF_ATTR_SIZE_VER5
- llvm_unreachable("Intel PT Linux perf event not supported");
-#else
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
- m_tid = tid;
- LLDB_LOG(log, "called thread id {0}", tid);
- uint64_t page_size = getpagesize();
-
- if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) {
- return createStringError(
- inconvertibleErrorCode(),
- "The trace buffer size must be a power of 2 greater than or equal to "
- "4096 (2^12) bytes. It was %" PRIu64 ".",
- buffer_size);
- }
- uint64_t numpages = static_cast<uint64_t>(
- llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size));
- numpages = std::max<uint64_t>(1, numpages);
- buffer_size = page_size * numpages;
-
- perf_event_attr attr;
- memset(&attr, 0, sizeof(attr));
- attr.size = sizeof(attr);
- attr.exclude_kernel = 1;
- attr.sample_type = PERF_SAMPLE_TIME;
- attr.sample_id_all = 1;
- attr.exclude_hv = 1;
- attr.exclude_idle = 1;
- attr.mmap = 1;
-
- if (Expected<uint64_t> config_value =
- GeneratePerfEventConfigValue(enable_tsc, psb_period)) {
- attr.config = *config_value;
- LLDB_LOG(log, "intel pt config {0}", attr.config);
- } else {
- return config_value.takeError();
- }
-
- if (Expected<uint32_t> intel_pt_type = GetOSEventType()) {
- attr.type = *intel_pt_type;
- LLDB_LOG(log, "intel pt type {0}", attr.type);
- } else {
- return intel_pt_type.takeError();
- }
-
- LLDB_LOG(log, "buffer size {0} ", buffer_size);
-
- errno = 0;
- auto fd =
- syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0);
- if (fd == -1) {
- LLDB_LOG(log, "syscall error {0}", errno);
- return createStringError(inconvertibleErrorCode(),
- "perf event syscall failed");
- }
-
- m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close());
-
- errno = 0;
- auto base =
- mmap(nullptr, (buffer_size + page_size), PROT_WRITE, MAP_SHARED, fd, 0);
-
- if (base == MAP_FAILED) {
- LLDB_LOG(log, "mmap base error {0}", errno);
- return createStringError(inconvertibleErrorCode(),
- "Meta buffer allocation failed");
- }
-
- m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
- reinterpret_cast<perf_event_mmap_page *>(base),
- munmap_delete(buffer_size + page_size));
-
- m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
- m_mmap_meta->aux_size = buffer_size;
-
- errno = 0;
- auto mmap_aux = mmap(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd,
- static_cast<long int>(m_mmap_meta->aux_offset));
-
- if (mmap_aux == MAP_FAILED) {
- LLDB_LOG(log, "second mmap done {0}", errno);
- return createStringError(inconvertibleErrorCode(),
- "Trace buffer allocation failed");
- }
- m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>(
- reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(buffer_size));
- return Error::success();
-#endif
-}
-
-llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetDataBuffer() const {
-#ifndef PERF_ATTR_SIZE_VER5
- llvm_unreachable("Intel PT Linux perf event not supported");
-#else
- return MutableArrayRef<uint8_t>(
- (reinterpret_cast<uint8_t *>(m_mmap_meta.get()) +
- m_mmap_meta->data_offset),
- m_mmap_meta->data_size);
-#endif
-}
-
-llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetAuxBuffer() const {
-#ifndef PERF_ATTR_SIZE_VER5
- llvm_unreachable("Intel PT Linux perf event not supported");
-#else
- return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size);
-#endif
-}
-
-Expected<ArrayRef<uint8_t>> IntelPTThreadTrace::GetCPUInfo() {
- static llvm::Optional<std::vector<uint8_t>> cpu_info;
- if (!cpu_info) {
- auto buffer_or_error = getProcFile("cpuinfo");
- if (!buffer_or_error)
- return Status(buffer_or_error.getError()).ToError();
- MemoryBuffer &buffer = **buffer_or_error;
- cpu_info = std::vector<uint8_t>(
- reinterpret_cast<const uint8_t *>(buffer.getBufferStart()),
- reinterpret_cast<const uint8_t *>(buffer.getBufferEnd()));
- }
- return *cpu_info;
-}
-
-llvm::Expected<IntelPTThreadTraceUP>
-IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size,
- bool enable_tsc, Optional<size_t> psb_period) {
- IntelPTThreadTraceUP thread_trace_up(new IntelPTThreadTrace());
-
- if (llvm::Error err = thread_trace_up->StartTrace(pid, tid, buffer_size,
- enable_tsc, psb_period))
- return std::move(err);
-
- return std::move(thread_trace_up);
-}
-
-Expected<std::vector<uint8_t>>
-IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const {
- std::vector<uint8_t> data(size, 0);
- MutableArrayRef<uint8_t> buffer_ref(data);
- Status error = ReadPerfTraceAux(buffer_ref, 0);
- if (error.Fail())
- return error.ToError();
- return data;
-}
-
-Status
-IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
- size_t offset) const {
-#ifndef PERF_ATTR_SIZE_VER5
- llvm_unreachable("perf event not supported");
-#else
- // Disable the perf event to force a flush out of the CPU's internal buffer.
- // Besides, we can guarantee that the CPU won't override any data as we are
- // reading the buffer.
- //
- // The Intel documentation says:
- //
- // Packets are first buffered internally and then written out asynchronously.
- // To collect packet output for postprocessing, a collector needs first to
- // ensure that all packet data has been flushed from internal buffers.
- // Software can ensure this by stopping packet generation by clearing
- // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
- // Section 35.2.7.2).
- //
- // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
- // in the man page of perf_event_open.
- ioctl(*m_fd, PERF_EVENT_IOC_DISABLE);
-
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
- Status error;
- uint64_t head = m_mmap_meta->aux_head;
-
- LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head);
-
- /**
- * When configured as ring buffer, the aux buffer keeps wrapping around
- * the buffer and its not possible to detect how many times the buffer
- * wrapped. Initially the buffer is filled with zeros,as shown below
- * so in order to get complete buffer we first copy firstpartsize, followed
- * by any left over part from beginning to aux_head
- *
- * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
- * aux_head->||<- firstpartsize ->|
- *
- * */
-
- ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset);
- LLDB_LOG(log, "ReadCyclic BUffer Done");
-
- // Reenable tracing now we have read the buffer
- ioctl(*m_fd, PERF_EVENT_IOC_ENABLE);
- return error;
-#endif
-}
-
-Status
-IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
- size_t offset) const {
-#ifndef PERF_ATTR_SIZE_VER5
- llvm_unreachable("perf event not supported");
-#else
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
- uint64_t bytes_remaining = buffer.size();
- Status error;
-
- uint64_t head = m_mmap_meta->data_head;
-
- /*
- * The data buffer and aux buffer have different implementations
- * with respect to their definition of head pointer. In the case
- * of Aux data buffer the head always wraps around the aux buffer
- * and we don't need to care about it, whereas the data_head keeps
- * increasing and needs to be wrapped by modulus operator
- */
-
- LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
-
- auto data_buffer = GetDataBuffer();
-
- if (head > data_buffer.size()) {
- head = head % data_buffer.size();
- LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head);
-
- ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset);
- bytes_remaining -= buffer.size();
- } else {
- LLDB_LOG(log, "Head - {0}", head);
- if (offset >= head) {
- LLDB_LOG(log, "Invalid Offset ");
- error.SetErrorString("invalid offset");
- buffer = buffer.slice(buffer.size());
- return error;
- }
-
- auto data = data_buffer.slice(offset, (head - offset));
- auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
- bytes_remaining -= (remaining - buffer.begin());
- }
- buffer = buffer.drop_back(bytes_remaining);
- return error;
-#endif
-}
-
-void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
- llvm::MutableArrayRef<uint8_t> src,
- size_t src_cyc_index, size_t offset) {
-
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
-
- if (dst.empty() || src.empty()) {
- dst = dst.drop_back(dst.size());
- return;
- }
-
- if (dst.data() == nullptr || src.data() == nullptr) {
- dst = dst.drop_back(dst.size());
- return;
- }
-
- if (src_cyc_index > src.size()) {
- dst = dst.drop_back(dst.size());
- return;
- }
-
- if (offset >= src.size()) {
- LLDB_LOG(log, "Too Big offset ");
- dst = dst.drop_back(dst.size());
- return;
- }
-
- llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = {
- src.slice(src_cyc_index), src.take_front(src_cyc_index)};
-
- if (offset > parts[0].size()) {
- parts[1] = parts[1].slice(offset - parts[0].size());
- parts[0] = parts[0].drop_back(parts[0].size());
- } else if (offset == parts[0].size()) {
- parts[0] = parts[0].drop_back(parts[0].size());
- } else {
- parts[0] = parts[0].slice(offset);
- }
- auto next = dst.begin();
- auto bytes_left = dst.size();
- for (auto part : parts) {
- size_t chunk_size = std::min(part.size(), bytes_left);
- next = std::copy_n(part.begin(), chunk_size, next);
- bytes_left -= chunk_size;
- }
- dst = dst.drop_back(bytes_left);
-}
-
-TraceThreadState IntelPTThreadTrace::GetState() const {
- return {static_cast<int64_t>(m_tid),
- {TraceBinaryData{"threadTraceBuffer",
- static_cast<int64_t>(GetTraceBufferSize())}}};
-}
-
-/// IntelPTThreadTraceCollection
-
-bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
- return m_thread_traces.count(tid);
-}
-
-Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) {
- auto it = m_thread_traces.find(tid);
- if (it == m_thread_traces.end())
- return createStringError(inconvertibleErrorCode(),
- "Thread %" PRIu64 " not currently traced", tid);
- m_total_buffer_size -= it->second->GetTraceBufferSize();
- m_thread_traces.erase(tid);
- return Error::success();
-}
-
-Error IntelPTThreadTraceCollection::TraceStart(
- lldb::tid_t tid, const TraceIntelPTStartRequest &request) {
- if (TracesThread(tid))
- return createStringError(inconvertibleErrorCode(),
- "Thread %" PRIu64 " already traced", tid);
-
- Expected<IntelPTThreadTraceUP> trace_up = IntelPTThreadTrace::Create(
- m_pid, tid, request.threadBufferSize, request.enableTsc,
- request.psbPeriod.map([](int64_t period) { return (size_t)period; }));
- if (!trace_up)
- return trace_up.takeError();
-
- m_total_buffer_size += (*trace_up)->GetTraceBufferSize();
- m_thread_traces.try_emplace(tid, std::move(*trace_up));
- return Error::success();
-}
-
-size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const {
- return m_total_buffer_size;
-}
-
-std::vector<TraceThreadState>
-IntelPTThreadTraceCollection::GetThreadStates() const {
- std::vector<TraceThreadState> states;
- for (const auto &it : m_thread_traces)
- states.push_back(it.second->GetState());
- return states;
-}
-
-Expected<const IntelPTThreadTrace &>
-IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const {
- auto it = m_thread_traces.find(tid);
- if (it == m_thread_traces.end())
- return createStringError(inconvertibleErrorCode(),
- "Thread %" PRIu64 " not currently traced", tid);
- return *it->second.get();
-}
-
-void IntelPTThreadTraceCollection::Clear() {
- m_thread_traces.clear();
- m_total_buffer_size = 0;
-}
-
-/// IntelPTProcessTrace
-
-bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const {
- return m_thread_traces.TracesThread(tid);
-}
-
-Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) {
- return m_thread_traces.TraceStop(tid);
-}
-
-Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) {
- if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize >
- static_cast<size_t>(*m_tracing_params.processBufferSizeLimit))
- return createStringError(
- inconvertibleErrorCode(),
- "Thread %" PRIu64 " can't be traced as the process trace size limit "
- "has been reached. Consider retracing with a higher "
- "limit.",
- tid);
-
- return m_thread_traces.TraceStart(tid, m_tracing_params);
-}
-
-const IntelPTThreadTraceCollection &
-IntelPTProcessTrace::GetThreadTraces() const {
- return m_thread_traces;
-}
-
-/// IntelPTManager
-
-Error IntelPTManager::TraceStop(lldb::tid_t tid) {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->TraceStop(tid);
- return m_thread_traces.TraceStop(tid);
-}
-
-Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
- if (request.IsProcessTracing()) {
- Clear();
- return Error::success();
- } else {
- Error error = Error::success();
- for (int64_t tid : *request.tids)
- error = joinErrors(std::move(error),
- TraceStop(static_cast<lldb::tid_t>(tid)));
- return error;
- }
-}
-
-Error IntelPTManager::TraceStart(
- const TraceIntelPTStartRequest &request,
- const std::vector<lldb::tid_t> &process_threads) {
- if (request.IsProcessTracing()) {
- if (IsProcessTracingEnabled()) {
- return createStringError(
- inconvertibleErrorCode(),
- "Process currently traced. Stop process tracing first");
- }
- m_process_trace = IntelPTProcessTrace(m_pid, request);
-
- Error error = Error::success();
- for (lldb::tid_t tid : process_threads)
- error = joinErrors(std::move(error), m_process_trace->TraceStart(tid));
- return error;
- } else {
- Error error = Error::success();
- for (int64_t tid : *request.tids)
- error = joinErrors(std::move(error),
- m_thread_traces.TraceStart(tid, request));
- return error;
- }
-}
-
-Error IntelPTManager::OnThreadCreated(lldb::tid_t tid) {
- if (!IsProcessTracingEnabled())
- return Error::success();
- return m_process_trace->TraceStart(tid);
-}
-
-Error IntelPTManager::OnThreadDestroyed(lldb::tid_t tid) {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->TraceStop(tid);
- else if (m_thread_traces.TracesThread(tid))
- return m_thread_traces.TraceStop(tid);
- return Error::success();
-}
-
-Expected<json::Value> IntelPTManager::GetState() const {
- Expected<ArrayRef<uint8_t>> cpu_info = IntelPTThreadTrace::GetCPUInfo();
- if (!cpu_info)
- return cpu_info.takeError();
-
- TraceGetStateResponse state;
- state.processBinaryData.push_back(
- {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
-
- std::vector<TraceThreadState> thread_states =
- m_thread_traces.GetThreadStates();
- state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
- thread_states.end());
-
- if (IsProcessTracingEnabled()) {
- thread_states = m_process_trace->GetThreadTraces().GetThreadStates();
- state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
- thread_states.end());
- }
- return toJSON(state);
-}
-
-Expected<const IntelPTThreadTrace &>
-IntelPTManager::GetTracedThread(lldb::tid_t tid) const {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->GetThreadTraces().GetTracedThread(tid);
- return m_thread_traces.GetTracedThread(tid);
-}
-
-Expected<std::vector<uint8_t>>
-IntelPTManager::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
- if (request.kind == "threadTraceBuffer") {
- if (Expected<const IntelPTThreadTrace &> trace =
- GetTracedThread(*request.tid))
- return trace->GetIntelPTBuffer(request.offset, request.size);
- else
- return trace.takeError();
- } else if (request.kind == "cpuInfo") {
- return IntelPTThreadTrace::GetCPUInfo();
- }
- return createStringError(inconvertibleErrorCode(),
- "Unsuported trace binary data kind: %s",
- request.kind.c_str());
-}
-
-void IntelPTManager::ClearProcessTracing() { m_process_trace = None; }
-
-bool IntelPTManager::IsSupported() {
- Expected<uint32_t> intel_pt_type = GetOSEventType();
- if (!intel_pt_type) {
- llvm::consumeError(intel_pt_type.takeError());
- return false;
- }
- return true;
-}
-
-bool IntelPTManager::IsProcessTracingEnabled() const {
- return (bool)m_process_trace;
-}
-
-void IntelPTManager::Clear() {
- ClearProcessTracing();
- m_thread_traces.Clear();
-}
+++ /dev/null
-//===-- IntelPTManager.h -------------------------------------- -*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_IntelPTManager_H_
-#define liblldb_IntelPTManager_H_
-
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
-#include "lldb/lldb-types.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/DenseSet.h"
-
-#include <linux/perf_event.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-namespace lldb_private {
-
-namespace process_linux {
-
-/// This class keeps track of one tracing instance of
-/// Intel(R) Processor Trace on Linux OS at thread level.
-///
-/// The kernel interface for us is the perf_event_open.
-class IntelPTThreadTrace;
-typedef std::unique_ptr<IntelPTThreadTrace> IntelPTThreadTraceUP;
-
-class IntelPTThreadTrace {
-
- class munmap_delete {
- size_t m_length;
-
- public:
- munmap_delete(size_t length) : m_length(length) {}
- void operator()(void *ptr) {
- if (m_length)
- munmap(ptr, m_length);
- }
- };
-
- class file_close {
-
- public:
- file_close() = default;
- void operator()(int *ptr) {
- if (ptr == nullptr)
- return;
- if (*ptr == -1)
- return;
- close(*ptr);
- std::default_delete<int>()(ptr);
- }
- };
-
- std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta;
- std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux;
- std::unique_ptr<int, file_close> m_fd;
- lldb::tid_t m_tid;
-
- /// Start tracing a thread
- ///
- /// \param[in] pid
- /// The pid of the process whose thread will be traced.
- ///
- /// \param[in] buffer_size
- /// Size of the thread buffer in bytes.
- ///
- /// \param[in] enable_tsc
- /// Whether to use enable TSC timestamps or not.
- /// More information in TraceIntelPT::GetStartConfigurationHelp().
- ///
- /// \param[in] psb_period
- /// This value defines the period in which PSB packets will be generated.
- /// More information in TraceIntelPT::GetStartConfigurationHelp().
- ///
- /// \return
- /// \a llvm::Error::success if tracing was successful, or an
- /// \a llvm::Error otherwise.
- llvm::Error StartTrace(lldb::pid_t pid, lldb::tid_t tid, uint64_t buffer_size,
- bool enable_tsc, llvm::Optional<size_t> psb_period);
-
- llvm::MutableArrayRef<uint8_t> GetAuxBuffer() const;
- llvm::MutableArrayRef<uint8_t> GetDataBuffer() const;
-
- IntelPTThreadTrace()
- : m_mmap_meta(nullptr, munmap_delete(0)),
- m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()) {}
-
-public:
- /// Get the content of /proc/cpuinfo that can be later used to decode traces.
- static llvm::Expected<llvm::ArrayRef<uint8_t>> GetCPUInfo();
-
- /// Start tracing a thread.
- ///
- /// See \a StartTrace.
- ///
- /// \return
- /// A \a IntelPTThreadTrace instance if tracing was successful, or
- /// an \a llvm::Error otherwise.
- static llvm::Expected<IntelPTThreadTraceUP>
- Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, bool enable_tsc,
- llvm::Optional<size_t> psb_period);
-
- /// Read the trace buffer of the currently traced thread.
- ///
- /// \param[in] offset
- /// Offset of the data to read.
- ///
- /// \param[in] size
- /// Number of bytes to read.
- ///
- /// \return
- /// A vector with the requested binary data. The vector will have the
- /// size of the requested \a size. Non-available positions will be
- /// filled with zeroes.
- llvm::Expected<std::vector<uint8_t>> GetIntelPTBuffer(size_t offset,
- size_t size) const;
-
- Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
- size_t offset = 0) const;
-
- Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
- size_t offset = 0) const;
-
- /// Get the size in bytes of the aux section of the thread or process traced
- /// by this object.
- size_t GetTraceBufferSize() const;
-
- /// Read data from a cyclic buffer
- ///
- /// \param[in] [out] buf
- /// Destination buffer, the buffer will be truncated to written size.
- ///
- /// \param[in] src
- /// Source buffer which must be a cyclic buffer.
- ///
- /// \param[in] src_cyc_index
- /// The index pointer (start of the valid data in the cyclic
- /// buffer).
- ///
- /// \param[in] offset
- /// The offset to begin reading the data in the cyclic buffer.
- static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
- llvm::MutableArrayRef<uint8_t> src,
- size_t src_cyc_index, size_t offset);
-
- /// Return the thread-specific part of the jLLDBTraceGetState packet.
- TraceThreadState GetState() const;
-};
-
-/// Manages a list of thread traces.
-class IntelPTThreadTraceCollection {
-public:
- IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {}
-
- /// Dispose of all traces
- void Clear();
-
- bool TracesThread(lldb::tid_t tid) const;
-
- size_t GetTotalBufferSize() const;
-
- std::vector<TraceThreadState> GetThreadStates() const;
-
- llvm::Expected<const IntelPTThreadTrace &>
- GetTracedThread(lldb::tid_t tid) const;
-
- llvm::Error TraceStart(lldb::tid_t tid,
- const TraceIntelPTStartRequest &request);
-
- llvm::Error TraceStop(lldb::tid_t tid);
-
-private:
- lldb::pid_t m_pid;
- llvm::DenseMap<lldb::tid_t, IntelPTThreadTraceUP> m_thread_traces;
- /// Total actual thread buffer size in bytes
- size_t m_total_buffer_size = 0;
-};
-
-/// Manages a "process trace" instance.
-class IntelPTProcessTrace {
-public:
- IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request)
- : m_thread_traces(pid), m_tracing_params(request) {}
-
- bool TracesThread(lldb::tid_t tid) const;
-
- const IntelPTThreadTraceCollection &GetThreadTraces() const;
-
- llvm::Error TraceStart(lldb::tid_t tid);
-
- llvm::Error TraceStop(lldb::tid_t tid);
-
-private:
- IntelPTThreadTraceCollection m_thread_traces;
- /// Params used to trace threads when the user started "process tracing".
- TraceIntelPTStartRequest m_tracing_params;
-};
-
-/// Main class that manages intel-pt process and thread tracing.
-class IntelPTManager {
-public:
- IntelPTManager(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {}
-
- static bool IsSupported();
-
- /// If "process tracing" is enabled, then trace the given thread.
- llvm::Error OnThreadCreated(lldb::tid_t tid);
-
- /// Stops tracing a tracing upon a destroy event.
- llvm::Error OnThreadDestroyed(lldb::tid_t tid);
-
- /// Implementation of the jLLDBTraceStop packet
- llvm::Error TraceStop(const TraceStopRequest &request);
-
- /// Implementation of the jLLDBTraceStart packet
- ///
- /// \param[in] process_threads
- /// A list of all threads owned by the process.
- llvm::Error TraceStart(const TraceIntelPTStartRequest &request,
- const std::vector<lldb::tid_t> &process_threads);
-
- /// Implementation of the jLLDBTraceGetState packet
- llvm::Expected<llvm::json::Value> GetState() const;
-
- /// Implementation of the jLLDBTraceGetBinaryData packet
- llvm::Expected<std::vector<uint8_t>>
- GetBinaryData(const TraceGetBinaryDataRequest &request) const;
-
- /// Dispose of all traces
- void Clear();
-
-private:
- llvm::Error TraceStop(lldb::tid_t tid);
-
- /// Start tracing a specific thread.
- llvm::Error TraceStart(lldb::tid_t tid,
- const TraceIntelPTStartRequest &request);
-
- llvm::Expected<const IntelPTThreadTrace &>
- GetTracedThread(lldb::tid_t tid) const;
-
- bool IsProcessTracingEnabled() const;
-
- void ClearProcessTracing();
-
- lldb::pid_t m_pid;
- /// Threads traced due to "thread tracing"
- IntelPTThreadTraceCollection m_thread_traces;
- /// Threads traced due to "process tracing". Only one active "process tracing"
- /// instance is assumed for a single process.
- llvm::Optional<IntelPTProcessTrace> m_process_trace;
-};
-
-} // namespace process_linux
-} // namespace lldb_private
-
-#endif // liblldb_IntelPTManager_H_
NativeProcessOpenBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
NativeDelegate &native_delegate,
MainLoop &mainloop) const {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
Status status;
::pid_t pid = ProcessLauncherPosixFork()
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
MainLoop &mainloop) const {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "pid = {0:x}", pid);
// Retrieve the architecture for the running process.
}
void NativeProcessOpenBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
Status NativeProcessOpenBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
int data, int *result) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Log *log = GetLog(POSIXLog::Process);
Status error;
int ret;
}
Status NativeProcessOpenBSD::Resume(const ResumeActionList &resume_actions) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "pid {0}", GetID());
const auto &thread = m_threads[0];
}
Status NativeProcessOpenBSD::Kill() {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
LLDB_LOG(log, "pid {0}", GetID());
Status error;
}
void NativeProcessOpenBSD::SigchldHandler() {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Process);
// Process all pending waitpid notifications.
int status;
::pid_t wait_pid =
NativeThreadOpenBSD &NativeProcessOpenBSD::AddThread(lldb::tid_t thread_id) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ Log *log = GetLog(POSIXLog::Thread);
LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
assert(!HasThreadNoLock(thread_id) &&
unsigned char *dst = static_cast<unsigned char *>(buf);
struct ptrace_io_desc io;
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ Log *log = GetLog(POSIXLog::Memory);
LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
bytes_read = 0;
Status error;
struct ptrace_io_desc io;
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ Log *log = GetLog(POSIXLog::Memory);
LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
bytes_written = 0;
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "llvm/ADT/APInt.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
// clang-format off
#include <sys/types.h>
NativeRegisterContextOpenBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
RegisterValue ®_value) {
Status error;
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Registers);
if (!reg_info) {
error.SetErrorString("reg_info NULL");
offset = reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset();
reg_value = (uint64_t)m_pacmask[offset > 0];
if (reg_value.GetByteSize() > reg_info->byte_size) {
- reg_value.SetType(reg_info);
+ reg_value.SetType(*reg_info);
}
return error;
}
if (reg_value.GetByteSize() > reg_info->byte_size) {
- reg_value.SetType(reg_info);
+ reg_value.SetType(*reg_info);
}
return error;
const RegisterInfo *reg_info, const RegisterValue ®_value) {
Status error;
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Log *log = GetLog(POSIXLog::Registers);
if (!reg_info) {
error.SetErrorString("reg_info NULL");
}
Status NativeRegisterContextOpenBSD_arm64::ReadAllRegisterValues(
- lldb::DataBufferSP &data_sp) {
+ lldb::WritableDataBufferSP &data_sp) {
Status error;
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
return error;
}
- uint8_t *src = data_sp->GetBytes();
+ const uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextOpenBSD_arm64::%s "
"DataBuffer::GetBytes() returned a null "
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue ®_value) override;
- Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
}
Status NativeRegisterContextOpenBSD_x86_64::ReadAllRegisterValues(
- lldb::DataBufferSP &data_sp) {
+ lldb::WritableDataBufferSP &data_sp) {
Status error;
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
return error;
}
- uint8_t *src = data_sp->GetBytes();
+ const uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextOpenBSD_x86_64::%s "
"DataBuffer::GetBytes() returned a null "
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue ®_value) override;
- Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+ Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
void NativeThreadOpenBSD::SetStoppedBySignal(uint32_t signo,
const siginfo_t *info) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ Log *log = GetLog(POSIXLog::Thread);
LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
SetStopped();
m_stop_info.reason = StopReason::eStopReasonSignal;
- m_stop_info.details.signal.signo = signo;
+ m_stop_info.signo = signo;
m_stop_description.clear();
if (info) {
void NativeThreadOpenBSD::SetStoppedByBreakpoint() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonBreakpoint;
- m_stop_info.details.signal.signo = SIGTRAP;
+ m_stop_info.signo = SIGTRAP;
}
void NativeThreadOpenBSD::SetStoppedByTrace() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonTrace;
- m_stop_info.details.signal.signo = SIGTRAP;
+ m_stop_info.signo = SIGTRAP;
}
void NativeThreadOpenBSD::SetStoppedByExec() {
SetStopped();
m_stop_info.reason = StopReason::eStopReasonExec;
- m_stop_info.details.signal.signo = SIGTRAP;
+ m_stop_info.signo = SIGTRAP;
}
void NativeThreadOpenBSD::SetStopped() {
bool NativeThreadOpenBSD::GetStopReason(ThreadStopInfo &stop_info,
std::string &description) {
- Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ Log *log = GetLog(POSIXLog::Thread);
description.clear();
add_lldb_library(lldbPluginProcessUtility
AuxVector.cpp
- DynamicRegisterInfo.cpp
FreeBSDSignals.cpp
GDBRemoteSignals.cpp
HistoryThread.cpp
RegisterContextOpenBSD_x86_64.cpp
RegisterContextPOSIX_arm.cpp
RegisterContextPOSIX_arm64.cpp
+ RegisterContextPOSIX_loongarch64.cpp
RegisterContextPOSIX_mips64.cpp
RegisterContextPOSIX_powerpc.cpp
RegisterContextPOSIX_ppc64le.cpp
+ RegisterContextPOSIX_riscv64.cpp
RegisterContextPOSIX_s390x.cpp
RegisterContextPOSIX_x86.cpp
RegisterContextThreadMemory.cpp
RegisterContextWindows_x86_64.cpp
RegisterInfoPOSIX_arm.cpp
RegisterInfoPOSIX_arm64.cpp
+ RegisterInfoPOSIX_loongarch64.cpp
RegisterInfoPOSIX_ppc64le.cpp
+ RegisterInfoPOSIX_riscv64.cpp
StopInfoMachException.cpp
ThreadMemory.cpp
lldbUtility
LINK_COMPONENTS
Support
+ TargetParser
)
+++ /dev/null
-//===-- DynamicRegisterInfo.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "DynamicRegisterInfo.h"
-
-#include "lldb/Core/StreamFile.h"
-#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/Host/StringConvert.h"
-#include "lldb/Interpreter/OptionArgParser.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/RegularExpression.h"
-#include "lldb/Utility/StringExtractor.h"
-#include "lldb/Utility/StructuredData.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-DynamicRegisterInfo::DynamicRegisterInfo(
- const lldb_private::StructuredData::Dictionary &dict,
- const lldb_private::ArchSpec &arch) {
- SetRegisterInfo(dict, arch);
-}
-
-DynamicRegisterInfo::DynamicRegisterInfo(DynamicRegisterInfo &&info) {
- MoveFrom(std::move(info));
-}
-
-DynamicRegisterInfo &
-DynamicRegisterInfo::operator=(DynamicRegisterInfo &&info) {
- MoveFrom(std::move(info));
- return *this;
-}
-
-void DynamicRegisterInfo::MoveFrom(DynamicRegisterInfo &&info) {
- m_regs = std::move(info.m_regs);
- m_sets = std::move(info.m_sets);
- m_set_reg_nums = std::move(info.m_set_reg_nums);
- m_set_names = std::move(info.m_set_names);
- m_value_regs_map = std::move(info.m_value_regs_map);
- m_invalidate_regs_map = std::move(info.m_invalidate_regs_map);
- m_dynamic_reg_size_map = std::move(info.m_dynamic_reg_size_map);
-
- m_reg_data_byte_size = info.m_reg_data_byte_size;
- m_finalized = info.m_finalized;
-
- if (m_finalized) {
- const size_t num_sets = m_sets.size();
- for (size_t set = 0; set < num_sets; ++set)
- m_sets[set].registers = m_set_reg_nums[set].data();
- }
-
- info.Clear();
-}
-
-size_t
-DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
- const ArchSpec &arch) {
- assert(!m_finalized);
- StructuredData::Array *sets = nullptr;
- if (dict.GetValueForKeyAsArray("sets", sets)) {
- const uint32_t num_sets = sets->GetSize();
- for (uint32_t i = 0; i < num_sets; ++i) {
- ConstString set_name;
- if (sets->GetItemAtIndexAsString(i, set_name) && !set_name.IsEmpty()) {
- m_sets.push_back({set_name.AsCString(), nullptr, 0, nullptr});
- } else {
- Clear();
- printf("error: register sets must have valid names\n");
- return 0;
- }
- }
- m_set_reg_nums.resize(m_sets.size());
- }
-
- StructuredData::Array *regs = nullptr;
- if (!dict.GetValueForKeyAsArray("registers", regs))
- return 0;
-
- const uint32_t num_regs = regs->GetSize();
- // typedef std::map<std::string, std::vector<std::string> >
- // InvalidateNameMap;
- // InvalidateNameMap invalidate_map;
- for (uint32_t i = 0; i < num_regs; ++i) {
- StructuredData::Dictionary *reg_info_dict = nullptr;
- if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) {
- Clear();
- printf("error: items in the 'registers' array must be dictionaries\n");
- regs->DumpToStdout();
- return 0;
- }
-
- // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16,
- // 'encoding':'uint' , 'format':'hex' , 'set': 0, 'ehframe' : 2,
- // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
- RegisterInfo reg_info;
- std::vector<uint32_t> value_regs;
- std::vector<uint32_t> invalidate_regs;
- memset(®_info, 0, sizeof(reg_info));
-
- ConstString name_val;
- ConstString alt_name_val;
- if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) {
- Clear();
- printf("error: registers must have valid names and offsets\n");
- reg_info_dict->DumpToStdout();
- return 0;
- }
- reg_info.name = name_val.GetCString();
- reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr);
- reg_info.alt_name = alt_name_val.GetCString();
-
- reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset,
- UINT32_MAX);
-
- const ByteOrder byte_order = arch.GetByteOrder();
-
- if (reg_info.byte_offset == UINT32_MAX) {
- // No offset for this register, see if the register has a value
- // expression which indicates this register is part of another register.
- // Value expressions are things like "rax[31:0]" which state that the
- // current register's value is in a concrete register "rax" in bits 31:0.
- // If there is a value expression we can calculate the offset
- bool success = false;
- llvm::StringRef slice_str;
- if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) {
- // Slices use the following format:
- // REGNAME[MSBIT:LSBIT]
- // REGNAME - name of the register to grab a slice of
- // MSBIT - the most significant bit at which the current register value
- // starts at
- // LSBIT - the least significant bit at which the current register value
- // ends at
- static RegularExpression g_bitfield_regex(
- llvm::StringRef("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"));
- llvm::SmallVector<llvm::StringRef, 4> matches;
- if (g_bitfield_regex.Execute(slice_str, &matches)) {
- std::string reg_name_str = matches[1].str();
- std::string msbit_str = matches[2].str();
- std::string lsbit_str = matches[3].str();
- const uint32_t msbit =
- StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
- const uint32_t lsbit =
- StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX);
- if (msbit != UINT32_MAX && lsbit != UINT32_MAX) {
- if (msbit > lsbit) {
- const uint32_t msbyte = msbit / 8;
- const uint32_t lsbyte = lsbit / 8;
-
- const RegisterInfo *containing_reg_info =
- GetRegisterInfo(reg_name_str);
- if (containing_reg_info) {
- const uint32_t max_bit = containing_reg_info->byte_size * 8;
- if (msbit < max_bit && lsbit < max_bit) {
- m_invalidate_regs_map[containing_reg_info
- ->kinds[eRegisterKindLLDB]]
- .push_back(i);
- m_value_regs_map[i].push_back(
- containing_reg_info->kinds[eRegisterKindLLDB]);
- m_invalidate_regs_map[i].push_back(
- containing_reg_info->kinds[eRegisterKindLLDB]);
-
- if (byte_order == eByteOrderLittle) {
- success = true;
- reg_info.byte_offset =
- containing_reg_info->byte_offset + lsbyte;
- } else if (byte_order == eByteOrderBig) {
- success = true;
- reg_info.byte_offset =
- containing_reg_info->byte_offset + msbyte;
- } else {
- llvm_unreachable("Invalid byte order");
- }
- } else {
- if (msbit > max_bit)
- printf("error: msbit (%u) must be less than the bitsize "
- "of the register (%u)\n",
- msbit, max_bit);
- else
- printf("error: lsbit (%u) must be less than the bitsize "
- "of the register (%u)\n",
- lsbit, max_bit);
- }
- } else {
- printf("error: invalid concrete register \"%s\"\n",
- reg_name_str.c_str());
- }
- } else {
- printf("error: msbit (%u) must be greater than lsbit (%u)\n",
- msbit, lsbit);
- }
- } else {
- printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit,
- lsbit);
- }
- } else {
- // TODO: print error invalid slice string that doesn't follow the
- // format
- printf("error: failed to match against register bitfield regex\n");
- }
- } else {
- StructuredData::Array *composite_reg_list = nullptr;
- if (reg_info_dict->GetValueForKeyAsArray("composite",
- composite_reg_list)) {
- const size_t num_composite_regs = composite_reg_list->GetSize();
- if (num_composite_regs > 0) {
- uint32_t composite_offset = UINT32_MAX;
- for (uint32_t composite_idx = 0; composite_idx < num_composite_regs;
- ++composite_idx) {
- ConstString composite_reg_name;
- if (composite_reg_list->GetItemAtIndexAsString(
- composite_idx, composite_reg_name, nullptr)) {
- const RegisterInfo *composite_reg_info =
- GetRegisterInfo(composite_reg_name.GetStringRef());
- if (composite_reg_info) {
- composite_offset = std::min(composite_offset,
- composite_reg_info->byte_offset);
- m_value_regs_map[i].push_back(
- composite_reg_info->kinds[eRegisterKindLLDB]);
- m_invalidate_regs_map[composite_reg_info
- ->kinds[eRegisterKindLLDB]]
- .push_back(i);
- m_invalidate_regs_map[i].push_back(
- composite_reg_info->kinds[eRegisterKindLLDB]);
- } else {
- // TODO: print error invalid slice string that doesn't follow
- // the format
- printf("error: failed to find composite register by name: "
- "\"%s\"\n",
- composite_reg_name.GetCString());
- }
- } else {
- printf(
- "error: 'composite' list value wasn't a python string\n");
- }
- }
- if (composite_offset != UINT32_MAX) {
- reg_info.byte_offset = composite_offset;
- success = m_value_regs_map.find(i) != m_value_regs_map.end();
- } else {
- printf("error: 'composite' registers must specify at least one "
- "real register\n");
- }
- } else {
- printf("error: 'composite' list was empty\n");
- }
- }
- }
-
- if (!success) {
- Clear();
- reg_info_dict->DumpToStdout();
- return 0;
- }
- }
-
- int64_t bitsize = 0;
- if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) {
- Clear();
- printf("error: invalid or missing 'bitsize' key/value pair in register "
- "dictionary\n");
- reg_info_dict->DumpToStdout();
- return 0;
- }
-
- reg_info.byte_size = bitsize / 8;
-
- llvm::StringRef dwarf_opcode_string;
- if (reg_info_dict->GetValueForKeyAsString("dynamic_size_dwarf_expr_bytes",
- dwarf_opcode_string)) {
- reg_info.dynamic_size_dwarf_len = dwarf_opcode_string.size() / 2;
- assert(reg_info.dynamic_size_dwarf_len > 0);
-
- std::vector<uint8_t> dwarf_opcode_bytes(reg_info.dynamic_size_dwarf_len);
- uint32_t j;
- StringExtractor opcode_extractor(dwarf_opcode_string);
- uint32_t ret_val = opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
- UNUSED_IF_ASSERT_DISABLED(ret_val);
- assert(ret_val == reg_info.dynamic_size_dwarf_len);
-
- for (j = 0; j < reg_info.dynamic_size_dwarf_len; ++j)
- m_dynamic_reg_size_map[i].push_back(dwarf_opcode_bytes[j]);
-
- reg_info.dynamic_size_dwarf_expr_bytes = m_dynamic_reg_size_map[i].data();
- }
-
- llvm::StringRef format_str;
- if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) {
- if (OptionArgParser::ToFormat(format_str.str().c_str(), reg_info.format,
- nullptr)
- .Fail()) {
- Clear();
- printf("error: invalid 'format' value in register dictionary\n");
- reg_info_dict->DumpToStdout();
- return 0;
- }
- } else {
- reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format,
- eFormatHex);
- }
-
- llvm::StringRef encoding_str;
- if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str))
- reg_info.encoding = Args::StringToEncoding(encoding_str, eEncodingUint);
- else
- reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding,
- eEncodingUint);
-
- size_t set = 0;
- if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) ||
- set >= m_sets.size()) {
- Clear();
- printf("error: invalid 'set' value in register dictionary, valid values "
- "are 0 - %i\n",
- (int)set);
- reg_info_dict->DumpToStdout();
- return 0;
- }
-
- // Fill in the register numbers
- reg_info.kinds[lldb::eRegisterKindLLDB] = i;
- reg_info.kinds[lldb::eRegisterKindProcessPlugin] = i;
- uint32_t eh_frame_regno = LLDB_INVALID_REGNUM;
- reg_info_dict->GetValueForKeyAsInteger("gcc", eh_frame_regno,
- LLDB_INVALID_REGNUM);
- if (eh_frame_regno == LLDB_INVALID_REGNUM)
- reg_info_dict->GetValueForKeyAsInteger("ehframe", eh_frame_regno,
- LLDB_INVALID_REGNUM);
- reg_info.kinds[lldb::eRegisterKindEHFrame] = eh_frame_regno;
- reg_info_dict->GetValueForKeyAsInteger(
- "dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
- llvm::StringRef generic_str;
- if (reg_info_dict->GetValueForKeyAsString("generic", generic_str))
- reg_info.kinds[lldb::eRegisterKindGeneric] =
- Args::StringToGenericRegister(generic_str);
- else
- reg_info_dict->GetValueForKeyAsInteger(
- "generic", reg_info.kinds[lldb::eRegisterKindGeneric],
- LLDB_INVALID_REGNUM);
-
- // Check if this register invalidates any other register values when it is
- // modified
- StructuredData::Array *invalidate_reg_list = nullptr;
- if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs",
- invalidate_reg_list)) {
- const size_t num_regs = invalidate_reg_list->GetSize();
- if (num_regs > 0) {
- for (uint32_t idx = 0; idx < num_regs; ++idx) {
- ConstString invalidate_reg_name;
- uint64_t invalidate_reg_num;
- if (invalidate_reg_list->GetItemAtIndexAsString(
- idx, invalidate_reg_name)) {
- const RegisterInfo *invalidate_reg_info =
- GetRegisterInfo(invalidate_reg_name.GetStringRef());
- if (invalidate_reg_info) {
- m_invalidate_regs_map[i].push_back(
- invalidate_reg_info->kinds[eRegisterKindLLDB]);
- } else {
- // TODO: print error invalid slice string that doesn't follow the
- // format
- printf("error: failed to find a 'invalidate-regs' register for "
- "\"%s\" while parsing register \"%s\"\n",
- invalidate_reg_name.GetCString(), reg_info.name);
- }
- } else if (invalidate_reg_list->GetItemAtIndexAsInteger(
- idx, invalidate_reg_num)) {
- if (invalidate_reg_num != UINT64_MAX)
- m_invalidate_regs_map[i].push_back(invalidate_reg_num);
- else
- printf("error: 'invalidate-regs' list value wasn't a valid "
- "integer\n");
- } else {
- printf("error: 'invalidate-regs' list value wasn't a python string "
- "or integer\n");
- }
- }
- } else {
- printf("error: 'invalidate-regs' contained an empty list\n");
- }
- }
-
- // Calculate the register offset
- const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
- if (m_reg_data_byte_size < end_reg_offset)
- m_reg_data_byte_size = end_reg_offset;
-
- m_regs.push_back(reg_info);
- m_set_reg_nums[set].push_back(i);
- }
- Finalize(arch);
- return m_regs.size();
-}
-
-void DynamicRegisterInfo::AddRegister(RegisterInfo ®_info,
- ConstString ®_name,
- ConstString ®_alt_name,
- ConstString &set_name) {
- assert(!m_finalized);
- const uint32_t reg_num = m_regs.size();
- reg_info.name = reg_name.AsCString();
- assert(reg_info.name);
- reg_info.alt_name = reg_alt_name.AsCString(nullptr);
- uint32_t i;
- if (reg_info.value_regs) {
- for (i = 0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
- m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
- }
- if (reg_info.invalidate_regs) {
- for (i = 0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
- m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
- }
- if (reg_info.dynamic_size_dwarf_expr_bytes) {
- for (i = 0; i < reg_info.dynamic_size_dwarf_len; ++i)
- m_dynamic_reg_size_map[reg_num].push_back(
- reg_info.dynamic_size_dwarf_expr_bytes[i]);
-
- reg_info.dynamic_size_dwarf_expr_bytes =
- m_dynamic_reg_size_map[reg_num].data();
- }
-
- m_regs.push_back(reg_info);
- uint32_t set = GetRegisterSetIndexByName(set_name, true);
- assert(set < m_sets.size());
- assert(set < m_set_reg_nums.size());
- assert(set < m_set_names.size());
- m_set_reg_nums[set].push_back(reg_num);
-}
-
-void DynamicRegisterInfo::Finalize(const ArchSpec &arch) {
- if (m_finalized)
- return;
-
- m_finalized = true;
- const size_t num_sets = m_sets.size();
- for (size_t set = 0; set < num_sets; ++set) {
- assert(m_sets.size() == m_set_reg_nums.size());
- m_sets[set].num_registers = m_set_reg_nums[set].size();
- m_sets[set].registers = m_set_reg_nums[set].data();
- }
-
- // sort and unique all value registers and make sure each is terminated with
- // LLDB_INVALID_REGNUM
-
- for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(),
- end = m_value_regs_map.end();
- pos != end; ++pos) {
- if (pos->second.size() > 1) {
- llvm::sort(pos->second.begin(), pos->second.end());
- reg_num_collection::iterator unique_end =
- std::unique(pos->second.begin(), pos->second.end());
- if (unique_end != pos->second.end())
- pos->second.erase(unique_end, pos->second.end());
- }
- assert(!pos->second.empty());
- if (pos->second.back() != LLDB_INVALID_REGNUM)
- pos->second.push_back(LLDB_INVALID_REGNUM);
- }
-
- // Now update all value_regs with each register info as needed
- const size_t num_regs = m_regs.size();
- for (size_t i = 0; i < num_regs; ++i) {
- if (m_value_regs_map.find(i) != m_value_regs_map.end())
- m_regs[i].value_regs = m_value_regs_map[i].data();
- else
- m_regs[i].value_regs = nullptr;
- }
-
- // Expand all invalidation dependencies
- for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(),
- end = m_invalidate_regs_map.end();
- pos != end; ++pos) {
- const uint32_t reg_num = pos->first;
-
- if (m_regs[reg_num].value_regs) {
- reg_num_collection extra_invalid_regs;
- for (const uint32_t invalidate_reg_num : pos->second) {
- reg_to_regs_map::iterator invalidate_pos =
- m_invalidate_regs_map.find(invalidate_reg_num);
- if (invalidate_pos != m_invalidate_regs_map.end()) {
- for (const uint32_t concrete_invalidate_reg_num :
- invalidate_pos->second) {
- if (concrete_invalidate_reg_num != reg_num)
- extra_invalid_regs.push_back(concrete_invalidate_reg_num);
- }
- }
- }
- pos->second.insert(pos->second.end(), extra_invalid_regs.begin(),
- extra_invalid_regs.end());
- }
- }
-
- // sort and unique all invalidate registers and make sure each is terminated
- // with LLDB_INVALID_REGNUM
- for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(),
- end = m_invalidate_regs_map.end();
- pos != end; ++pos) {
- if (pos->second.size() > 1) {
- llvm::sort(pos->second.begin(), pos->second.end());
- reg_num_collection::iterator unique_end =
- std::unique(pos->second.begin(), pos->second.end());
- if (unique_end != pos->second.end())
- pos->second.erase(unique_end, pos->second.end());
- }
- assert(!pos->second.empty());
- if (pos->second.back() != LLDB_INVALID_REGNUM)
- pos->second.push_back(LLDB_INVALID_REGNUM);
- }
-
- // Now update all invalidate_regs with each register info as needed
- for (size_t i = 0; i < num_regs; ++i) {
- if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end())
- m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data();
- else
- m_regs[i].invalidate_regs = nullptr;
- }
-
- // Check if we need to automatically set the generic registers in case they
- // weren't set
- bool generic_regs_specified = false;
- for (const auto ® : m_regs) {
- if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) {
- generic_regs_specified = true;
- break;
- }
- }
-
- if (!generic_regs_specified) {
- switch (arch.GetMachine()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::aarch64_be:
- for (auto ® : m_regs) {
- if (strcmp(reg.name, "pc") == 0)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- else if ((strcmp(reg.name, "fp") == 0) ||
- (strcmp(reg.name, "x29") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if ((strcmp(reg.name, "lr") == 0) ||
- (strcmp(reg.name, "x30") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- else if ((strcmp(reg.name, "sp") == 0) ||
- (strcmp(reg.name, "x31") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- else if (strcmp(reg.name, "cpsr") == 0)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- }
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- for (auto ® : m_regs) {
- if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- else if ((strcmp(reg.name, "sp") == 0) ||
- (strcmp(reg.name, "r13") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- else if ((strcmp(reg.name, "lr") == 0) ||
- (strcmp(reg.name, "r14") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
- else if ((strcmp(reg.name, "r7") == 0) &&
- arch.GetTriple().getVendor() == llvm::Triple::Apple)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if ((strcmp(reg.name, "r11") == 0) &&
- arch.GetTriple().getVendor() != llvm::Triple::Apple)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if (strcmp(reg.name, "fp") == 0)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if (strcmp(reg.name, "cpsr") == 0)
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- }
- break;
-
- case llvm::Triple::x86:
- for (auto ® : m_regs) {
- if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- else if ((strcmp(reg.name, "esp") == 0) ||
- (strcmp(reg.name, "sp") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- else if ((strcmp(reg.name, "ebp") == 0) ||
- (strcmp(reg.name, "fp") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if ((strcmp(reg.name, "eflags") == 0) ||
- (strcmp(reg.name, "flags") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- }
- break;
-
- case llvm::Triple::x86_64:
- for (auto ® : m_regs) {
- if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
- else if ((strcmp(reg.name, "rsp") == 0) ||
- (strcmp(reg.name, "sp") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
- else if ((strcmp(reg.name, "rbp") == 0) ||
- (strcmp(reg.name, "fp") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
- else if ((strcmp(reg.name, "rflags") == 0) ||
- (strcmp(reg.name, "flags") == 0))
- reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
- }
- break;
-
- default:
- break;
- }
- }
-
- // At this stage call ConfigureOffsets to calculate register offsets for
- // targets supporting dynamic offset calculation. It also calculates
- // total byte size of register data.
- ConfigureOffsets();
-
- // Check if register info is reconfigurable
- // AArch64 SVE register set has configurable register sizes
- if (arch.GetTriple().isAArch64()) {
- for (const auto ® : m_regs) {
- if (strcmp(reg.name, "vg") == 0) {
- m_is_reconfigurable = true;
- break;
- }
- }
- }
-}
-
-void DynamicRegisterInfo::ConfigureOffsets() {
- // We are going to create a map between remote (eRegisterKindProcessPlugin)
- // and local (eRegisterKindLLDB) register numbers. This map will give us
- // remote register numbers in increasing order for offset calculation.
- std::map<uint32_t, uint32_t> remote_to_local_regnum_map;
- for (const auto ® : m_regs)
- remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] =
- reg.kinds[eRegisterKindLLDB];
-
- // At this stage we manually calculate g/G packet offsets of all primary
- // registers, only if target XML or qRegisterInfo packet did not send
- // an offset explicitly.
- uint32_t reg_offset = 0;
- for (auto const ®num_pair : remote_to_local_regnum_map) {
- if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 &&
- m_regs[regnum_pair.second].value_regs == nullptr) {
- m_regs[regnum_pair.second].byte_offset = reg_offset;
-
- reg_offset = m_regs[regnum_pair.second].byte_offset +
- m_regs[regnum_pair.second].byte_size;
- }
- }
-
- // Now update all value_regs with each register info as needed
- for (auto ® : m_regs) {
- if (reg.value_regs != nullptr) {
- // Assign a valid offset to all pseudo registers if not assigned by stub.
- // Pseudo registers with value_regs list populated will share same offset
- // as that of their corresponding primary register in value_regs list.
- if (reg.byte_offset == LLDB_INVALID_INDEX32) {
- uint32_t value_regnum = reg.value_regs[0];
- if (value_regnum != LLDB_INVALID_INDEX32)
- reg.byte_offset =
- GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum])
- ->byte_offset;
- }
- }
-
- reg_offset = reg.byte_offset + reg.byte_size;
- if (m_reg_data_byte_size < reg_offset)
- m_reg_data_byte_size = reg_offset;
- }
-}
-
-bool DynamicRegisterInfo::IsReconfigurable() { return m_is_reconfigurable; }
-
-size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); }
-
-size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); }
-
-size_t DynamicRegisterInfo::GetRegisterDataByteSize() const {
- return m_reg_data_byte_size;
-}
-
-const RegisterInfo *
-DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) const {
- if (i < m_regs.size())
- return &m_regs[i];
- return nullptr;
-}
-
-RegisterInfo *DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) {
- if (i < m_regs.size())
- return &m_regs[i];
- return nullptr;
-}
-
-const RegisterInfo *DynamicRegisterInfo::GetRegisterInfo(uint32_t kind,
- uint32_t num) const {
- uint32_t reg_index = ConvertRegisterKindToRegisterNumber(kind, num);
- if (reg_index != LLDB_INVALID_REGNUM)
- return &m_regs[reg_index];
- return nullptr;
-}
-
-const RegisterSet *DynamicRegisterInfo::GetRegisterSet(uint32_t i) const {
- if (i < m_sets.size())
- return &m_sets[i];
- return nullptr;
-}
-
-uint32_t DynamicRegisterInfo::GetRegisterSetIndexByName(ConstString &set_name,
- bool can_create) {
- name_collection::iterator pos, end = m_set_names.end();
- for (pos = m_set_names.begin(); pos != end; ++pos) {
- if (*pos == set_name)
- return std::distance(m_set_names.begin(), pos);
- }
-
- m_set_names.push_back(set_name);
- m_set_reg_nums.resize(m_set_reg_nums.size() + 1);
- RegisterSet new_set = {set_name.AsCString(), nullptr, 0, nullptr};
- m_sets.push_back(new_set);
- return m_sets.size() - 1;
-}
-
-uint32_t
-DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber(uint32_t kind,
- uint32_t num) const {
- reg_collection::const_iterator pos, end = m_regs.end();
- for (pos = m_regs.begin(); pos != end; ++pos) {
- if (pos->kinds[kind] == num)
- return std::distance(m_regs.begin(), pos);
- }
-
- return LLDB_INVALID_REGNUM;
-}
-
-void DynamicRegisterInfo::Clear() {
- m_regs.clear();
- m_sets.clear();
- m_set_reg_nums.clear();
- m_set_names.clear();
- m_value_regs_map.clear();
- m_invalidate_regs_map.clear();
- m_dynamic_reg_size_map.clear();
- m_reg_data_byte_size = 0;
- m_finalized = false;
-}
-
-void DynamicRegisterInfo::Dump() const {
- StreamFile s(stdout, false);
- const size_t num_regs = m_regs.size();
- s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n",
- static_cast<const void *>(this), static_cast<uint64_t>(num_regs));
- for (size_t i = 0; i < num_regs; ++i) {
- s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name);
- s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s",
- m_regs[i].byte_size, m_regs[i].byte_offset, m_regs[i].encoding,
- FormatManager::GetFormatAsCString(m_regs[i].format));
- if (m_regs[i].kinds[eRegisterKindProcessPlugin] != LLDB_INVALID_REGNUM)
- s.Printf(", process plugin = %3u",
- m_regs[i].kinds[eRegisterKindProcessPlugin]);
- if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
- s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]);
- if (m_regs[i].kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM)
- s.Printf(", ehframe = %3u", m_regs[i].kinds[eRegisterKindEHFrame]);
- if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
- s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]);
- if (m_regs[i].alt_name)
- s.Printf(", alt-name = %s", m_regs[i].alt_name);
- if (m_regs[i].value_regs) {
- s.Printf(", value_regs = [ ");
- for (size_t j = 0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j) {
- s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name);
- }
- s.Printf("]");
- }
- if (m_regs[i].invalidate_regs) {
- s.Printf(", invalidate_regs = [ ");
- for (size_t j = 0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM;
- ++j) {
- s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name);
- }
- s.Printf("]");
- }
- s.EOL();
- }
-
- const size_t num_sets = m_sets.size();
- s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n",
- static_cast<const void *>(this), static_cast<uint64_t>(num_sets));
- for (size_t i = 0; i < num_sets; ++i) {
- s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i,
- m_sets[i].name);
- for (size_t idx = 0; idx < m_sets[i].num_registers; ++idx) {
- s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
- }
- s.Printf("]\n");
- }
-}
-
-const lldb_private::RegisterInfo *
-DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const {
- for (auto ®_info : m_regs)
- if (reg_info.name == reg_name)
- return ®_info;
- return nullptr;
-}
+++ /dev/null
-//===-- DynamicRegisterInfo.h -----------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H
-#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H
-
-#include <map>
-#include <vector>
-
-#include "lldb/Utility/ConstString.h"
-#include "lldb/Utility/StructuredData.h"
-#include "lldb/lldb-private.h"
-
-class DynamicRegisterInfo {
-protected:
- DynamicRegisterInfo(DynamicRegisterInfo &) = default;
- DynamicRegisterInfo &operator=(DynamicRegisterInfo &) = default;
-
-public:
- DynamicRegisterInfo() = default;
-
- DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
- const lldb_private::ArchSpec &arch);
-
- virtual ~DynamicRegisterInfo() = default;
-
- DynamicRegisterInfo(DynamicRegisterInfo &&info);
- DynamicRegisterInfo &operator=(DynamicRegisterInfo &&info);
-
- size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
- const lldb_private::ArchSpec &arch);
-
- void AddRegister(lldb_private::RegisterInfo ®_info,
- lldb_private::ConstString ®_name,
- lldb_private::ConstString ®_alt_name,
- lldb_private::ConstString &set_name);
-
- void Finalize(const lldb_private::ArchSpec &arch);
-
- size_t GetNumRegisters() const;
-
- size_t GetNumRegisterSets() const;
-
- size_t GetRegisterDataByteSize() const;
-
- const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(uint32_t i) const;
-
- lldb_private::RegisterInfo *GetRegisterInfoAtIndex(uint32_t i);
-
- const lldb_private::RegisterSet *GetRegisterSet(uint32_t i) const;
-
- uint32_t GetRegisterSetIndexByName(lldb_private::ConstString &set_name,
- bool can_create);
-
- uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind,
- uint32_t num) const;
-
- const lldb_private::RegisterInfo *GetRegisterInfo(uint32_t kind,
- uint32_t num) const;
-
- void Dump() const;
-
- void Clear();
-
- bool IsReconfigurable();
-
- const lldb_private::RegisterInfo *
- GetRegisterInfo(llvm::StringRef reg_name) const;
-
-protected:
- // Classes that inherit from DynamicRegisterInfo can see and modify these
- typedef std::vector<lldb_private::RegisterInfo> reg_collection;
- typedef std::vector<lldb_private::RegisterSet> set_collection;
- typedef std::vector<uint32_t> reg_num_collection;
- typedef std::vector<reg_num_collection> set_reg_num_collection;
- typedef std::vector<lldb_private::ConstString> name_collection;
- typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map;
- typedef std::vector<uint8_t> dwarf_opcode;
- typedef std::map<uint32_t, dwarf_opcode> dynamic_reg_size_map;
-
- void MoveFrom(DynamicRegisterInfo &&info);
-
- void ConfigureOffsets();
-
- reg_collection m_regs;
- set_collection m_sets;
- set_reg_num_collection m_set_reg_nums;
- name_collection m_set_names;
- reg_to_regs_map m_value_regs_map;
- reg_to_regs_map m_invalidate_regs_map;
- dynamic_reg_size_map m_dynamic_reg_size_map;
- size_t m_reg_data_byte_size = 0u; // The number of bytes required to store
- // all registers
- bool m_finalized = false;
- bool m_is_reconfigurable = false;
-};
-#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H
+++ /dev/null
-//===-- GDBRemoteCommunicationReplayServer.cpp ----------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include <cerrno>
-
-#include "lldb/Host/Config.h"
-#include "llvm/ADT/ScopeExit.h"
-
-#include "GDBRemoteCommunicationReplayServer.h"
-#include "ProcessGDBRemoteLog.h"
-
-// C Includes
-// C++ Includes
-#include <cstring>
-
-// Project includes
-#include "lldb/Host/ThreadLauncher.h"
-#include "lldb/Utility/ConstString.h"
-#include "lldb/Utility/Event.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/StringExtractorGDBRemote.h"
-
-using namespace llvm;
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::process_gdb_remote;
-
-/// Check if the given expected packet matches the actual packet.
-static bool unexpected(llvm::StringRef expected, llvm::StringRef actual) {
- // The 'expected' string contains the raw data, including the leading $ and
- // trailing checksum. The 'actual' string contains only the packet's content.
- if (expected.contains(actual))
- return false;
- // Contains a PID which might be different.
- if (expected.contains("vAttach"))
- return false;
- // Contains a ascii-hex-path.
- if (expected.contains("QSetSTD"))
- return false;
- // Contains environment values.
- if (expected.contains("QEnvironment"))
- return false;
-
- return true;
-}
-
-/// Check if we should reply to the given packet.
-static bool skip(llvm::StringRef data) {
- assert(!data.empty() && "Empty packet?");
-
- // We've already acknowledge the '+' packet so we're done here.
- if (data == "+")
- return true;
-
- /// Don't 't reply to ^C. We need this because of stop reply packets, which
- /// are only returned when the target halts. Reproducers synchronize these
- /// 'asynchronous' replies, by recording them as a regular replies to the
- /// previous packet (e.g. vCont). As a result, we should ignore real
- /// asynchronous requests.
- if (data.data()[0] == 0x03)
- return true;
-
- return false;
-}
-
-GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
- : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"),
- m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"),
- m_async_listener_sp(
- Listener::MakeListener("lldb.gdb-replay.async-listener")),
- m_async_thread_state_mutex() {
- m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
- "async thread continue");
- m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
- "async thread should exit");
-
- const uint32_t async_event_mask =
- eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
- m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
- async_event_mask);
-}
-
-GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
- StopAsyncThread();
-}
-
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
- Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
- std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
-
- StringExtractorGDBRemote packet;
- PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
-
- if (packet_result != PacketResult::Success) {
- if (!IsConnected()) {
- error.SetErrorString("lost connection");
- quit = true;
- } else {
- error.SetErrorString("timeout");
- }
- return packet_result;
- }
-
- m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
-
- // Check if we should reply to this packet.
- if (skip(packet.GetStringRef()))
- return PacketResult::Success;
-
- // This completes the handshake. Since m_send_acks was true, we can unset it
- // already.
- if (packet.GetStringRef() == "QStartNoAckMode")
- m_send_acks = false;
-
- // A QEnvironment packet is sent for every environment variable. If the
- // number of environment variables is different during replay, the replies
- // become out of sync.
- if (packet.GetStringRef().find("QEnvironment") == 0)
- return SendRawPacketNoLock("$OK#9a");
-
- Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- while (!m_packet_history.empty()) {
- // Pop last packet from the history.
- GDBRemotePacket entry = m_packet_history.back();
- m_packet_history.pop_back();
-
- // Decode run-length encoding.
- const std::string expanded_data =
- GDBRemoteCommunication::ExpandRLE(entry.packet.data);
-
- // We've handled the handshake implicitly before. Skip the packet and move
- // on.
- if (entry.packet.data == "+")
- continue;
-
- if (entry.type == GDBRemotePacket::ePacketTypeSend) {
- if (unexpected(expanded_data, packet.GetStringRef())) {
- LLDB_LOG(log,
- "GDBRemoteCommunicationReplayServer expected packet: '{0}'",
- expanded_data);
- LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
- packet.GetStringRef());
-#ifndef NDEBUG
- // This behaves like a regular assert, but prints the expected and
- // received packet before aborting.
- printf("Reproducer expected packet: '%s'\n", expanded_data.c_str());
- printf("Reproducer received packet: '%s'\n",
- packet.GetStringRef().data());
- llvm::report_fatal_error("Encountered unexpected packet during replay");
-#endif
- return PacketResult::ErrorSendFailed;
- }
-
- // Ignore QEnvironment packets as they're handled earlier.
- if (expanded_data.find("QEnvironment") == 1) {
- assert(m_packet_history.back().type ==
- GDBRemotePacket::ePacketTypeRecv);
- m_packet_history.pop_back();
- }
-
- continue;
- }
-
- if (entry.type == GDBRemotePacket::ePacketTypeInvalid) {
- LLDB_LOG(
- log,
- "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'",
- packet.GetStringRef());
- continue;
- }
-
- LLDB_LOG(log,
- "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'",
- packet.GetStringRef(), entry.packet.data);
- return SendRawPacketNoLock(entry.packet.data);
- }
-
- quit = true;
-
- return packet_result;
-}
-
-llvm::Error
-GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
- auto error_or_file = MemoryBuffer::getFile(path.GetPath());
- if (auto err = error_or_file.getError())
- return errorCodeToError(err);
-
- yaml::Input yin((*error_or_file)->getBuffer());
- yin >> m_packet_history;
-
- if (auto err = yin.error())
- return errorCodeToError(err);
-
- // We want to manipulate the vector like a stack so we need to reverse the
- // order of the packets to have the oldest on at the back.
- std::reverse(m_packet_history.begin(), m_packet_history.end());
-
- return Error::success();
-}
-
-bool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
- std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
- if (!m_async_thread.IsJoinable()) {
- // Create a thread that watches our internal state and controls which
- // events make it to clients (into the DCProcess event queue).
- llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread(
- "<lldb.gdb-replay.async>",
- GDBRemoteCommunicationReplayServer::AsyncThread, this);
- if (!async_thread) {
- LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
- async_thread.takeError(),
- "failed to launch host thread: {}");
- return false;
- }
- m_async_thread = *async_thread;
- }
-
- // Wait for handshake.
- m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
-
- return m_async_thread.IsJoinable();
-}
-
-void GDBRemoteCommunicationReplayServer::StopAsyncThread() {
- std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
-
- if (!m_async_thread.IsJoinable())
- return;
-
- // Request thread to stop.
- m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
-
- // Disconnect client.
- Disconnect();
-
- // Stop the thread.
- m_async_thread.Join(nullptr);
- m_async_thread.Reset();
-}
-
-void GDBRemoteCommunicationReplayServer::ReceivePacket(
- GDBRemoteCommunicationReplayServer &server, bool &done) {
- Status error;
- bool interrupt;
- auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
- error, interrupt, done);
- if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
- packet_result !=
- GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
- done = true;
- } else {
- server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
- }
-}
-
-thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
- GDBRemoteCommunicationReplayServer *server =
- (GDBRemoteCommunicationReplayServer *)arg;
- auto D = make_scope_exit([&]() { server->Disconnect(); });
- EventSP event_sp;
- bool done = false;
- while (!done) {
- if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
- const uint32_t event_type = event_sp->GetType();
- if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
- switch (event_type) {
- case eBroadcastBitAsyncContinue:
- ReceivePacket(*server, done);
- if (done)
- return {};
- break;
- case eBroadcastBitAsyncThreadShouldExit:
- default:
- return {};
- }
- }
- }
- }
-
- return {};
-}
-
-Status GDBRemoteCommunicationReplayServer::Connect(
- process_gdb_remote::GDBRemoteCommunicationClient &client) {
- repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
- if (!loader)
- return Status("No loader provided.");
-
- static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
- multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create(
- repro::Reproducer::Instance().GetLoader());
- if (!multi_loader)
- return Status("No gdb remote provider found.");
-
- llvm::Optional<std::string> history_file = multi_loader->GetNextFile();
- if (!history_file)
- return Status("No gdb remote packet log found.");
-
- if (auto error = LoadReplayHistory(FileSpec(*history_file)))
- return Status("Unable to load replay history");
-
- if (auto error = GDBRemoteCommunication::ConnectLocally(client, *this))
- return Status("Unable to connect to replay server");
-
- return {};
-}
+++ /dev/null
-//===-- GDBRemoteCommunicationReplayServer.h --------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H
-#define LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H
-
-// Other libraries and framework includes
-#include "GDBRemoteCommunication.h"
-#include "GDBRemoteCommunicationClient.h"
-#include "GDBRemoteCommunicationHistory.h"
-
-// Project includes
-#include "lldb/Host/HostThread.h"
-#include "lldb/Utility/Broadcaster.h"
-#include "lldb/lldb-private-forward.h"
-#include "llvm/Support/Error.h"
-
-// C Includes
-// C++ Includes
-#include <functional>
-#include <map>
-#include <thread>
-
-class StringExtractorGDBRemote;
-
-namespace lldb_private {
-namespace process_gdb_remote {
-
-class ProcessGDBRemote;
-
-/// Dummy GDB server that replays packets from the GDB Remote Communication
-/// history. This is used to replay GDB packets.
-class GDBRemoteCommunicationReplayServer : public GDBRemoteCommunication {
-public:
- GDBRemoteCommunicationReplayServer();
-
- ~GDBRemoteCommunicationReplayServer() override;
-
- PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout,
- Status &error, bool &interrupt,
- bool &quit);
-
- bool HandshakeWithClient() { return GetAck() == PacketResult::Success; }
-
- llvm::Error LoadReplayHistory(const FileSpec &path);
-
- bool StartAsyncThread();
- void StopAsyncThread();
-
- Status Connect(process_gdb_remote::GDBRemoteCommunicationClient &client);
-
-protected:
- enum {
- eBroadcastBitAsyncContinue = (1 << 0),
- eBroadcastBitAsyncThreadShouldExit = (1 << 1),
- };
-
- static void ReceivePacket(GDBRemoteCommunicationReplayServer &server,
- bool &done);
- static lldb::thread_result_t AsyncThread(void *arg);
-
- /// Replay history with the oldest packet at the end.
- std::vector<GDBRemotePacket> m_packet_history;
-
- /// Server thread.
- Broadcaster m_async_broadcaster;
- lldb::ListenerSP m_async_listener_sp;
- HostThread m_async_thread;
- std::recursive_mutex m_async_thread_state_mutex;
-
- bool m_skip_acks = false;
-
-private:
- GDBRemoteCommunicationReplayServer(
- const GDBRemoteCommunicationReplayServer &) = delete;
- const GDBRemoteCommunicationReplayServer &
- operator=(const GDBRemoteCommunicationReplayServer &) = delete;
-};
-
-} // namespace process_gdb_remote
-} // namespace lldb_private
-
-#endif // LLDB_SOURCE_PLUGINS_PROCESS_GDB_REMOTE_GDBREMOTECOMMUNICATIONREPLAYSERVER_H
#include <chrono>
#include <cstring>
+#include <optional>
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Config.h"
#include "lldb/Target/Platform.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/GDBRemote.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
#endif
// GDBRemoteCommunicationServerCommon constructor
-GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(
- const char *comm_name, const char *listener_name)
- : GDBRemoteCommunicationServer(comm_name, listener_name),
- m_process_launch_info(), m_process_launch_error(), m_proc_infos(),
- m_proc_infos_index(0) {
+GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon()
+ : GDBRemoteCommunicationServer(), m_process_launch_info(),
+ m_process_launch_error(), m_proc_infos(), m_proc_infos_index(0) {
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A,
&GDBRemoteCommunicationServerCommon::Handle_A);
RegisterMemberFunctionHandler(
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_vFile_size,
&GDBRemoteCommunicationServerCommon::Handle_vFile_Size);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vFile_fstat,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_FStat);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_vFile_stat,
&GDBRemoteCommunicationServerCommon::Handle_vFile_Stat);
}
#endif
- std::string s;
- if (HostInfo::GetOSBuildString(s)) {
+ if (std::optional<std::string> s = HostInfo::GetOSBuildString()) {
response.PutCString("os_build:");
- response.PutStringAsRawHex8(s);
+ response.PutStringAsRawHex8(*s);
response.PutChar(';');
}
- if (HostInfo::GetOSKernelDescription(s)) {
+ if (std::optional<std::string> s = HostInfo::GetOSKernelDescription()) {
response.PutCString("os_kernel:");
- response.PutStringAsRawHex8(s);
+ response.PutStringAsRawHex8(*s);
response.PutChar(';');
}
+ std::string s;
#if defined(__APPLE__)
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
response.PutChar(';');
}
#endif // #if defined(__APPLE__)
-
+ // coverity[unsigned_compare]
if (g_default_packet_timeout_sec > 0)
response.Printf("default_packet_timeout:%u;", g_default_packet_timeout_sec);
GDBRemoteCommunicationServerCommon::Handle_qUserName(
StringExtractorGDBRemote &packet) {
#if LLDB_ENABLE_POSIX
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Log *log = GetLog(LLDBLog::Process);
LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__);
// Packet format: "qUserName:%i" where %i is the uid
packet.SetFilePos(::strlen("qUserName:"));
uint32_t uid = packet.GetU32(UINT32_MAX);
if (uid != UINT32_MAX) {
- if (llvm::Optional<llvm::StringRef> name =
+ if (std::optional<llvm::StringRef> name =
HostInfo::GetUserIDResolver().GetUserName(uid)) {
StreamString response;
response.PutStringAsRawHex8(*name);
packet.SetFilePos(::strlen("qGroupName:"));
uint32_t gid = packet.GetU32(UINT32_MAX);
if (gid != UINT32_MAX) {
- if (llvm::Optional<llvm::StringRef> name =
+ if (std::optional<llvm::StringRef> name =
HostInfo::GetUserIDResolver().GetGroupName(gid)) {
StreamString response;
response.PutStringAsRawHex8(*name);
packet.GetHexByteStringTerminatedBy(path, ',');
if (!path.empty()) {
if (packet.GetChar() == ',') {
- // FIXME
- // The flag values for OpenOptions do not match the values used by GDB
- // * https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags
- // * rdar://problem/46788934
auto flags = File::OpenOptions(packet.GetHexMaxU32(false, 0));
if (packet.GetChar() == ',') {
mode_t mode = packet.GetHexMaxU32(false, 0600);
// Do not close fd.
auto file = FileSystem::Instance().Open(path_spec, flags, mode, false);
- int save_errno = 0;
+ StreamString response;
+ response.PutChar('F');
+
int descriptor = File::kInvalidDescriptor;
if (file) {
descriptor = file.get()->GetDescriptor();
+ response.Printf("%x", descriptor);
} else {
+ response.PutCString("-1");
std::error_code code = errorToErrorCode(file.takeError());
if (code.category() == std::system_category()) {
- save_errno = code.value();
+ response.Printf(",%x", code.value());
}
}
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", descriptor);
- if (save_errno)
- response.Printf(",%i", save_errno);
return SendPacketNoLock(response.GetString());
}
}
return SendErrorResponse(18);
}
+static GDBErrno system_errno_to_gdb(int err) {
+ switch (err) {
+#define HANDLE_ERRNO(name, value) \
+ case name: \
+ return GDB_##name;
+#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"
+ default:
+ return GDB_EUNKNOWN;
+ }
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_vFile_Close(
StringExtractorGDBRemote &packet) {
packet.SetFilePos(::strlen("vFile:close:"));
- int fd = packet.GetS32(-1);
+ int fd = packet.GetS32(-1, 16);
int err = -1;
int save_errno = 0;
if (fd >= 0) {
}
StreamString response;
response.PutChar('F');
- response.Printf("%i", err);
+ response.Printf("%x", err);
if (save_errno)
- response.Printf(",%i", save_errno);
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
return SendPacketNoLock(response.GetString());
}
StringExtractorGDBRemote &packet) {
StreamGDBRemote response;
packet.SetFilePos(::strlen("vFile:pread:"));
- int fd = packet.GetS32(-1);
+ int fd = packet.GetS32(-1, 16);
if (packet.GetChar() == ',') {
- size_t count = packet.GetU64(SIZE_MAX);
+ size_t count = packet.GetHexMaxU64(false, SIZE_MAX);
if (packet.GetChar() == ',') {
- off_t offset = packet.GetU64(UINT32_MAX);
+ off_t offset = packet.GetHexMaxU32(false, UINT32_MAX);
if (count == SIZE_MAX) {
- response.Printf("F-1:%i", EINVAL);
+ response.Printf("F-1:%x", EINVAL);
return SendPacketNoLock(response.GetString());
}
std::string buffer(count, 0);
- NativeFile file(fd, File::eOpenOptionRead, false);
+ NativeFile file(fd, File::eOpenOptionReadOnly, false);
Status error = file.Read(static_cast<void *>(&buffer[0]), count, offset);
- const ssize_t bytes_read = error.Success() ? count : -1;
const int save_errno = error.GetError();
response.PutChar('F');
- response.Printf("%zi", bytes_read);
- if (save_errno)
- response.Printf(",%i", save_errno);
- else {
+ if (error.Success()) {
+ response.Printf("%zx", count);
response.PutChar(';');
- response.PutEscapedBytes(&buffer[0], bytes_read);
+ response.PutEscapedBytes(&buffer[0], count);
+ } else {
+ response.PutCString("-1");
+ if (save_errno)
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
}
return SendPacketNoLock(response.GetString());
}
StreamGDBRemote response;
response.PutChar('F');
- int fd = packet.GetU32(UINT32_MAX);
+ int fd = packet.GetS32(-1, 16);
if (packet.GetChar() == ',') {
- off_t offset = packet.GetU64(UINT32_MAX);
+ off_t offset = packet.GetHexMaxU32(false, UINT32_MAX);
if (packet.GetChar() == ',') {
std::string buffer;
if (packet.GetEscapedBinaryData(buffer)) {
- NativeFile file(fd, File::eOpenOptionWrite, false);
+ NativeFile file(fd, File::eOpenOptionWriteOnly, false);
size_t count = buffer.size();
Status error =
file.Write(static_cast<const void *>(&buffer[0]), count, offset);
- const ssize_t bytes_written = error.Success() ? count : -1;
const int save_errno = error.GetError();
- response.Printf("%zi", bytes_written);
- if (save_errno)
- response.Printf(",%i", save_errno);
+ if (error.Success())
+ response.Printf("%zx", count);
+ else {
+ response.PutCString("-1");
+ if (save_errno)
+ response.Printf(",%x", system_errno_to_gdb(save_errno));
+ }
} else {
- response.Printf("-1,%i", EINVAL);
+ response.Printf("-1,%x", EINVAL);
}
return SendPacketNoLock(response.GetString());
}
std::error_code ec;
const uint32_t mode = FileSystem::Instance().GetPermissions(file_spec, ec);
StreamString response;
- response.Printf("F%u", mode);
- if (mode == 0 || ec)
- response.Printf(",%i", (int)Status(ec).GetError());
+ if (mode != llvm::sys::fs::perms_not_known)
+ response.Printf("F%x", mode);
+ else
+ response.Printf("F-1,%x", (int)Status(ec).GetError());
return SendPacketNoLock(response.GetString());
}
return SendErrorResponse(23);
Status error = FileSystem::Instance().Symlink(src_spec, FileSpec(dst));
StreamString response;
- response.Printf("F%u,%u", error.GetError(), error.GetError());
+ response.Printf("F%x,%x", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetString());
}
packet.GetHexByteString(path);
Status error(llvm::sys::fs::remove(path));
StreamString response;
- response.Printf("F%u,%u", error.GetError(), error.GetError());
+ response.Printf("F%x,%x", error.GetError(), error.GetError());
return SendPacketNoLock(response.GetString());
}
return SendErrorResponse(24);
}
+template <typename T, typename U>
+static void fill_clamp(T &dest, U src, typename T::value_type fallback) {
+ static_assert(std::is_unsigned<typename T::value_type>::value,
+ "Destination type must be unsigned.");
+ using UU = std::make_unsigned_t<U>;
+ constexpr auto T_max = std::numeric_limits<typename T::value_type>::max();
+ dest = src >= 0 && static_cast<UU>(src) <= T_max ? src : fallback;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_FStat(
+ StringExtractorGDBRemote &packet) {
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:fstat:"));
+ int fd = packet.GetS32(-1, 16);
+
+ struct stat file_stats;
+ if (::fstat(fd, &file_stats) == -1) {
+ const int save_errno = errno;
+ response.Printf("F-1,%x", system_errno_to_gdb(save_errno));
+ return SendPacketNoLock(response.GetString());
+ }
+
+ GDBRemoteFStatData data;
+ fill_clamp(data.gdb_st_dev, file_stats.st_dev, 0);
+ fill_clamp(data.gdb_st_ino, file_stats.st_ino, 0);
+ data.gdb_st_mode = file_stats.st_mode;
+ fill_clamp(data.gdb_st_nlink, file_stats.st_nlink, UINT32_MAX);
+ fill_clamp(data.gdb_st_uid, file_stats.st_uid, 0);
+ fill_clamp(data.gdb_st_gid, file_stats.st_gid, 0);
+ fill_clamp(data.gdb_st_rdev, file_stats.st_rdev, 0);
+ data.gdb_st_size = file_stats.st_size;
+#if !defined(_WIN32)
+ data.gdb_st_blksize = file_stats.st_blksize;
+ data.gdb_st_blocks = file_stats.st_blocks;
+#else
+ data.gdb_st_blksize = 0;
+ data.gdb_st_blocks = 0;
+#endif
+ fill_clamp(data.gdb_st_atime, file_stats.st_atime, 0);
+ fill_clamp(data.gdb_st_mtime, file_stats.st_mtime, 0);
+ fill_clamp(data.gdb_st_ctime, file_stats.st_ctime, 0);
+
+ response.Printf("F%zx;", sizeof(data));
+ response.PutEscapedBytes(&data, sizeof(data));
+ return SendPacketNoLock(response.GetString());
+}
+
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_vFile_Stat(
StringExtractorGDBRemote &packet) {
Status error(llvm::sys::fs::create_directory(path, mode));
StreamGDBRemote response;
- response.Printf("F%u", error.GetError());
+ response.Printf("F%x", error.GetError());
return SendPacketNoLock(response.GetString());
}
Status error(llvm::sys::fs::setPermissions(path, perms));
StreamGDBRemote response;
- response.Printf("F%u", error.GetError());
+ response.Printf("F%x", error.GetError());
return SendPacketNoLock(response.GetString());
}
// encoded argument value list, but we will stay true to the documented
// version of the 'A' packet here...
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Log *log = GetLog(LLDBLog::Process);
int actual_arg_index = 0;
packet.SetFilePos(1); // Skip the 'A'
response.PutChar(';');
response.PutCString("file_path:");
- response.PutStringAsRawHex8(matched_module_spec.GetFileSpec().GetCString());
+ response.PutStringAsRawHex8(
+ matched_module_spec.GetFileSpec().GetPath().c_str());
response.PutChar(';');
response.PutCString("file_offset:");
response.PutHex64(file_offset);
proc_info.GetUserID(), proc_info.GetGroupID(),
proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID());
response.PutCString("name:");
- response.PutStringAsRawHex8(proc_info.GetExecutableFile().GetCString());
+ response.PutStringAsRawHex8(proc_info.GetExecutableFile().GetPath().c_str());
response.PutChar(';');
response.PutCString("args:");
llvm::formatv("PacketSize={0}", max_packet_size),
"QStartNoAckMode+",
"qEcho+",
+ "native-signals+",
};
}
+++ /dev/null
-//===-- SWIGPythonBridge.cpp ----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Config.h"
-#include "lldb/lldb-enumerations.h"
-
-#if LLDB_ENABLE_PYTHON
-
-// LLDB Python header must be included first
-#include "lldb-python.h"
-
-#include "SWIGPythonBridge.h"
-
-using namespace lldb;
-
-namespace lldb_private {
-
-template <typename T> const char *GetPythonValueFormatString(T t);
-template <> const char *GetPythonValueFormatString(char *) { return "s"; }
-template <> const char *GetPythonValueFormatString(char) { return "b"; }
-template <> const char *GetPythonValueFormatString(unsigned char) {
- return "B";
-}
-template <> const char *GetPythonValueFormatString(short) { return "h"; }
-template <> const char *GetPythonValueFormatString(unsigned short) {
- return "H";
-}
-template <> const char *GetPythonValueFormatString(int) { return "i"; }
-template <> const char *GetPythonValueFormatString(unsigned int) { return "I"; }
-template <> const char *GetPythonValueFormatString(long) { return "l"; }
-template <> const char *GetPythonValueFormatString(unsigned long) {
- return "k";
-}
-template <> const char *GetPythonValueFormatString(long long) { return "L"; }
-template <> const char *GetPythonValueFormatString(unsigned long long) {
- return "K";
-}
-template <> const char *GetPythonValueFormatString(float) { return "f"; }
-template <> const char *GetPythonValueFormatString(double) { return "d"; }
-
-} // namespace lldb_private
-
-#endif // LLDB_ENABLE_PYTHON
+++ /dev/null
-//===-- TraceSessionFileParser.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===/
-
-#include "TraceSessionFileParser.h"
-#include "ThreadPostMortemTrace.h"
-
-#include <sstream>
-
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace llvm;
-
-void TraceSessionFileParser::NormalizePath(lldb_private::FileSpec &file_spec) {
- if (file_spec.IsRelative())
- file_spec.PrependPathComponent(m_session_file_dir);
-}
-
-Error TraceSessionFileParser::ParseModule(lldb::TargetSP &target_sp,
- const JSONModule &module) {
- FileSpec system_file_spec(module.system_path);
- NormalizePath(system_file_spec);
-
- FileSpec local_file_spec(module.file.hasValue() ? *module.file
- : module.system_path);
- NormalizePath(local_file_spec);
-
- ModuleSpec module_spec;
- module_spec.GetFileSpec() = local_file_spec;
- module_spec.GetPlatformFileSpec() = system_file_spec;
-
- if (module.uuid.hasValue())
- module_spec.GetUUID().SetFromStringRef(*module.uuid);
-
- Status error;
- ModuleSP module_sp =
- target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error);
-
- if (error.Fail())
- return error.ToError();
-
- bool load_addr_changed = false;
- module_sp->SetLoadAddress(*target_sp, module.load_address.value, false,
- load_addr_changed);
- return llvm::Error::success();
-}
-
-Error TraceSessionFileParser::CreateJSONError(json::Path::Root &root,
- const json::Value &value) {
- std::string err;
- raw_string_ostream os(err);
- root.printErrorContext(value, os);
- return createStringError(
- std::errc::invalid_argument, "%s\n\nContext:\n%s\n\nSchema:\n%s",
- toString(root.getError()).c_str(), os.str().c_str(), m_schema.data());
-}
-
-std::string TraceSessionFileParser::BuildSchema(StringRef plugin_schema) {
- std::ostringstream schema_builder;
- schema_builder << "{\n \"trace\": ";
- schema_builder << plugin_schema.data() << ",";
- schema_builder << R"(
- "processes": [
- {
- "pid": integer,
- "triple": string, // llvm-triple
- "threads": [
- {
- "tid": integer,
- "traceFile": string
- }
- ],
- "modules": [
- {
- "systemPath": string, // original path of the module at runtime
- "file"?: string, // copy of the file if not available at "systemPath"
- "loadAddress": string, // string address in hex or decimal form
- "uuid"?: string,
- }
- ]
- }
- ]
- // Notes:
- // All paths are either absolute or relative to the session file.
-}
-)";
- return schema_builder.str();
-}
-
-ThreadPostMortemTraceSP
-TraceSessionFileParser::ParseThread(ProcessSP &process_sp,
- const JSONThread &thread) {
- lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
-
- FileSpec trace_file(thread.trace_file);
- NormalizePath(trace_file);
-
- ThreadPostMortemTraceSP thread_sp =
- std::make_shared<ThreadPostMortemTrace>(*process_sp, tid, trace_file);
- process_sp->GetThreadList().AddThread(thread_sp);
- return thread_sp;
-}
-
-Expected<TraceSessionFileParser::ParsedProcess>
-TraceSessionFileParser::ParseProcess(const JSONProcess &process) {
- TargetSP target_sp;
- Status error = m_debugger.GetTargetList().CreateTarget(
- m_debugger, /*user_exe_path*/ StringRef(), process.triple,
- eLoadDependentsNo,
- /*platform_options*/ nullptr, target_sp);
-
- if (!target_sp)
- return error.ToError();
-
- ParsedProcess parsed_process;
- parsed_process.target_sp = target_sp;
-
- ProcessSP process_sp = target_sp->CreateProcess(
- /*listener*/ nullptr, "trace",
- /*crash_file*/ nullptr,
- /*can_connect*/ false);
-
- process_sp->SetID(static_cast<lldb::pid_t>(process.pid));
-
- for (const JSONThread &thread : process.threads)
- parsed_process.threads.push_back(ParseThread(process_sp, thread));
-
- for (const JSONModule &module : process.modules)
- if (Error err = ParseModule(target_sp, module))
- return std::move(err);
-
- if (!process.threads.empty())
- process_sp->GetThreadList().SetSelectedThreadByIndexID(0);
-
- // We invoke DidAttach to create a correct stopped state for the process and
- // its threads.
- ArchSpec process_arch;
- process_sp->DidAttach(process_arch);
-
- return parsed_process;
-}
-
-Expected<std::vector<TraceSessionFileParser::ParsedProcess>>
-TraceSessionFileParser::ParseCommonSessionFile(
- const JSONTraceSessionBase &session) {
- std::vector<ParsedProcess> parsed_processes;
-
- auto onError = [&]() {
- // Delete all targets that were created so far in case of failures
- for (ParsedProcess &parsed_process : parsed_processes)
- m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp);
- };
-
- for (const JSONProcess &process : session.processes) {
- if (Expected<ParsedProcess> parsed_process = ParseProcess(process))
- parsed_processes.push_back(std::move(*parsed_process));
- else {
- onError();
- return parsed_process.takeError();
- }
- }
- return parsed_processes;
-}
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(const Value &value, TraceSessionFileParser::JSONAddress &address,
- Path path) {
- Optional<StringRef> s = value.getAsString();
- if (s.hasValue() && !s->getAsInteger(0, address.value))
- return true;
-
- path.report("expected numeric string");
- return false;
-}
-
-bool fromJSON(const Value &value, TraceSessionFileParser::JSONModule &module,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("systemPath", module.system_path) &&
- o.map("file", module.file) &&
- o.map("loadAddress", module.load_address) &&
- o.map("uuid", module.uuid);
-}
-
-bool fromJSON(const Value &value, TraceSessionFileParser::JSONThread &thread,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("tid", thread.tid) && o.map("traceFile", thread.trace_file);
-}
-
-bool fromJSON(const Value &value, TraceSessionFileParser::JSONProcess &process,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("pid", process.pid) && o.map("triple", process.triple) &&
- o.map("threads", process.threads) && o.map("modules", process.modules);
-}
-
-bool fromJSON(const Value &value,
- TraceSessionFileParser::JSONTracePluginSettings &plugin_settings,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("type", plugin_settings.type);
-}
-
-bool fromJSON(const Value &value,
- TraceSessionFileParser::JSONTraceSessionBase &session,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("processes", session.processes);
-}
-
-} // namespace json
-} // namespace llvm
+++ /dev/null
-//===-- TraceSessionFileParser.h --------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_TARGET_TRACESESSIONPARSER_H
-#define LLDB_TARGET_TRACESESSIONPARSER_H
-
-#include "llvm/Support/JSON.h"
-
-#include "ThreadPostMortemTrace.h"
-
-namespace lldb_private {
-
-/// \class TraceSessionFileParser TraceSessionFileParser.h
-///
-/// Base class for parsing the common information of JSON trace session files.
-/// Contains the basic C++ structs that represent the JSON data, which include
-/// \a JSONTraceSession as the root object.
-///
-/// See \a Trace::FindPlugin for more information regarding these JSON files.
-class TraceSessionFileParser {
-public:
- /// C++ structs representing the JSON trace session.
- /// \{
- struct JSONAddress {
- lldb::addr_t value;
- };
-
- struct JSONModule {
- std::string system_path;
- llvm::Optional<std::string> file;
- JSONAddress load_address;
- llvm::Optional<std::string> uuid;
- };
-
- struct JSONThread {
- int64_t tid;
- std::string trace_file;
- };
-
- struct JSONProcess {
- int64_t pid;
- std::string triple;
- std::vector<JSONThread> threads;
- std::vector<JSONModule> modules;
- };
-
- struct JSONTracePluginSettings {
- std::string type;
- };
-
- struct JSONTraceSessionBase {
- std::vector<JSONProcess> processes;
- };
-
- /// The trace plug-in implementation should provide its own TPluginSettings,
- /// which corresponds to the "trace" section of the schema.
- template <class TPluginSettings>
- struct JSONTraceSession : JSONTraceSessionBase {
- TPluginSettings trace;
- };
- /// \}
-
- /// Helper struct holding the objects created when parsing a process
- struct ParsedProcess {
- lldb::TargetSP target_sp;
- std::vector<lldb::ThreadPostMortemTraceSP> threads;
- };
-
- TraceSessionFileParser(Debugger &debugger, llvm::StringRef session_file_dir,
- llvm::StringRef schema)
- : m_debugger(debugger), m_session_file_dir(session_file_dir),
- m_schema(schema) {}
-
- /// Build the full schema for a Trace plug-in.
- ///
- /// \param[in] plugin_schema
- /// The subschema that corresponds to the "trace" section of the schema.
- ///
- /// \return
- /// The full schema containing the common attributes and the plug-in
- /// specific attributes.
- static std::string BuildSchema(llvm::StringRef plugin_schema);
-
- /// Parse the fields common to all trace session schemas.
- ///
- /// \param[in] session
- /// The session json objects already deserialized.
- ///
- /// \return
- /// A list of \a ParsedProcess containing all threads and targets created
- /// during the parsing, or an error in case of failures. In case of
- /// errors, no side effects are produced.
- llvm::Expected<std::vector<ParsedProcess>>
- ParseCommonSessionFile(const JSONTraceSessionBase &session);
-
-protected:
- /// Resolve non-absolute paths relative to the session file folder. It
- /// modifies the given file_spec.
- void NormalizePath(lldb_private::FileSpec &file_spec);
-
- lldb::ThreadPostMortemTraceSP ParseThread(lldb::ProcessSP &process_sp,
- const JSONThread &thread);
-
- llvm::Expected<ParsedProcess> ParseProcess(const JSONProcess &process);
-
- llvm::Error ParseModule(lldb::TargetSP &target_sp, const JSONModule &module);
-
- /// Create a user-friendly error message upon a JSON-parsing failure using the
- /// \a json::ObjectMapper functionality.
- ///
- /// \param[in] root
- /// The \a llvm::json::Path::Root used to parse the JSON \a value.
- ///
- /// \param[in] value
- /// The json value that failed to parse.
- ///
- /// \return
- /// An \a llvm::Error containing the user-friendly error message.
- llvm::Error CreateJSONError(llvm::json::Path::Root &root,
- const llvm::json::Value &value);
-
- Debugger &m_debugger;
- std::string m_session_file_dir;
- llvm::StringRef m_schema;
-};
-} // namespace lldb_private
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(const Value &value,
- lldb_private::TraceSessionFileParser::JSONAddress &address,
- Path path);
-
-bool fromJSON(const Value &value,
- lldb_private::TraceSessionFileParser::JSONModule &module,
- Path path);
-
-bool fromJSON(const Value &value,
- lldb_private::TraceSessionFileParser::JSONThread &thread,
- Path path);
-
-bool fromJSON(const Value &value,
- lldb_private::TraceSessionFileParser::JSONProcess &process,
- Path path);
-
-bool fromJSON(const Value &value,
- lldb_private::TraceSessionFileParser::JSONTracePluginSettings
- &plugin_settings,
- Path path);
-
-bool fromJSON(
- const Value &value,
- lldb_private::TraceSessionFileParser::JSONTraceSessionBase &session,
- Path path);
-
-template <class TPluginSettings>
-bool fromJSON(
- const Value &value,
- lldb_private::TraceSessionFileParser::JSONTraceSession<TPluginSettings>
- &session,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("trace", session.trace) &&
- fromJSON(value,
- (lldb_private::TraceSessionFileParser::JSONTraceSessionBase &)
- session,
- path);
-}
-
-} // namespace json
-} // namespace llvm
-
-#endif // LLDB_TARGET_TRACESESSIONPARSER_H
+++ /dev/null
-//===-- IntelPTDecoder.cpp --======----------------------------------------===//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "IntelPTDecoder.h"
-
-#include "llvm/Support/MemoryBuffer.h"
-
-#include "../common/ThreadPostMortemTrace.h"
-#include "DecodedThread.h"
-#include "TraceIntelPT.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/StringExtractor.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::trace_intel_pt;
-using namespace llvm;
-
-/// Move the decoder forward to the next synchronization point (i.e. next PSB
-/// packet).
-///
-/// Once the decoder is at that sync. point, it can start decoding instructions.
-///
-/// \return
-/// A negative number with the libipt error if we couldn't synchronize.
-/// Otherwise, a positive number with the synchronization status will be
-/// returned.
-static int FindNextSynchronizationPoint(pt_insn_decoder &decoder) {
- // Try to sync the decoder. If it fails, then get
- // the decoder_offset and try to sync again from
- // the next synchronization point. If the
- // new_decoder_offset is same as decoder_offset
- // then we can't move to the next synchronization
- // point. Otherwise, keep resyncing until either
- // end of trace stream (eos) is reached or
- // pt_insn_sync_forward() passes.
- int errcode = pt_insn_sync_forward(&decoder);
-
- if (errcode != -pte_eos && errcode < 0) {
- uint64_t decoder_offset = 0;
- int errcode_off = pt_insn_get_offset(&decoder, &decoder_offset);
- if (errcode_off >= 0) { // we could get the offset
- while (true) {
- errcode = pt_insn_sync_forward(&decoder);
- if (errcode >= 0 || errcode == -pte_eos)
- break;
-
- uint64_t new_decoder_offset = 0;
- errcode_off = pt_insn_get_offset(&decoder, &new_decoder_offset);
- if (errcode_off < 0)
- break; // We can't further synchronize.
- else if (new_decoder_offset <= decoder_offset) {
- // We tried resyncing the decoder and
- // decoder didn't make any progress because
- // the offset didn't change. We will not
- // make any progress further. Hence,
- // stopping in this situation.
- break;
- }
- // We'll try again starting from a new offset.
- decoder_offset = new_decoder_offset;
- }
- }
- }
-
- return errcode;
-}
-
-/// Before querying instructions, we need to query the events associated that
-/// instruction e.g. timing events like ptev_tick, or paging events like
-/// ptev_paging.
-///
-/// \return
-/// 0 if there were no errors processing the events, or a negative libipt
-/// error code in case of errors.
-static int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) {
- while (errcode & pts_event_pending) {
- pt_event event;
- errcode = pt_insn_event(&decoder, &event, sizeof(event));
- if (errcode < 0)
- return errcode;
- }
- return 0;
-}
-
-/// Decode all the instructions from a configured decoder.
-/// The decoding flow is based on
-/// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop
-/// but with some relaxation to allow for gaps in the trace.
-///
-/// Error codes returned by libipt while decoding are:
-/// - negative: actual errors
-/// - positive or zero: not an error, but a list of bits signaling the status of
-/// the decoder
-///
-/// \param[in] decoder
-/// A configured libipt \a pt_insn_decoder.
-///
-/// \return
-/// The decoded instructions.
-static std::vector<IntelPTInstruction>
-DecodeInstructions(pt_insn_decoder &decoder) {
- std::vector<IntelPTInstruction> instructions;
-
- while (true) {
- int errcode = FindNextSynchronizationPoint(decoder);
- if (errcode == -pte_eos)
- break;
-
- if (errcode < 0) {
- instructions.emplace_back(make_error<IntelPTError>(errcode));
- break;
- }
-
- // We have synchronized, so we can start decoding
- // instructions and events.
- while (true) {
- errcode = ProcessPTEvents(decoder, errcode);
- if (errcode < 0) {
- instructions.emplace_back(make_error<IntelPTError>(errcode));
- break;
- }
- pt_insn insn;
-
- errcode = pt_insn_next(&decoder, &insn, sizeof(insn));
- if (errcode == -pte_eos)
- break;
-
- if (errcode < 0) {
- instructions.emplace_back(make_error<IntelPTError>(errcode, insn.ip));
- break;
- }
-
- uint64_t time;
- int time_error = pt_insn_time(&decoder, &time, nullptr, nullptr);
- if (time_error == -pte_invalid) {
- // This happens if we invoke the pt_insn_time method incorrectly,
- // but the instruction is good though.
- instructions.emplace_back(
- make_error<IntelPTError>(time_error, insn.ip));
- instructions.emplace_back(insn);
- break;
- }
- if (time_error == -pte_no_time) {
- // We simply don't have time information, i.e. None of TSC, MTC or CYC
- // was enabled.
- instructions.emplace_back(insn);
- } else {
- instructions.emplace_back(insn, time);
- }
- }
- }
-
- return instructions;
-}
-
-/// Callback used by libipt for reading the process memory.
-///
-/// More information can be found in
-/// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md
-static int ReadProcessMemory(uint8_t *buffer, size_t size,
- const pt_asid * /* unused */, uint64_t pc,
- void *context) {
- Process *process = static_cast<Process *>(context);
-
- Status error;
- int bytes_read = process->ReadMemory(pc, buffer, size, error);
- if (error.Fail())
- return -pte_nomap;
- return bytes_read;
-}
-
-static Expected<std::vector<IntelPTInstruction>>
-DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt,
- MutableArrayRef<uint8_t> buffer) {
- Expected<pt_cpu> cpu_info = trace_intel_pt.GetCPUInfo();
- if (!cpu_info)
- return cpu_info.takeError();
-
- pt_config config;
- pt_config_init(&config);
- config.cpu = *cpu_info;
-
- if (int errcode = pt_cpu_errata(&config.errata, &config.cpu))
- return make_error<IntelPTError>(errcode);
-
- config.begin = buffer.data();
- config.end = buffer.data() + buffer.size();
-
- pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config);
- if (!decoder)
- return make_error<IntelPTError>(-pte_nomem);
-
- pt_image *image = pt_insn_get_image(decoder);
-
- int errcode = pt_image_set_callback(image, ReadProcessMemory, &process);
- assert(errcode == 0);
- (void)errcode;
-
- std::vector<IntelPTInstruction> instructions = DecodeInstructions(*decoder);
-
- pt_insn_free_decoder(decoder);
- return instructions;
-}
-
-static Expected<std::vector<IntelPTInstruction>>
-DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt,
- const FileSpec &trace_file, size_t &raw_trace_size) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
- MemoryBuffer::getFile(trace_file.GetPath());
- if (std::error_code err = trace_or_error.getError())
- return errorCodeToError(err);
-
- MemoryBuffer &trace = **trace_or_error;
- MutableArrayRef<uint8_t> trace_data(
- // The libipt library does not modify the trace buffer, hence the
- // following cast is safe.
- reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart())),
- trace.getBufferSize());
- raw_trace_size = trace_data.size();
- return DecodeInMemoryTrace(process, trace_intel_pt, trace_data);
-}
-
-static Expected<std::vector<IntelPTInstruction>>
-DecodeLiveThread(Thread &thread, TraceIntelPT &trace, size_t &raw_trace_size) {
- Expected<std::vector<uint8_t>> buffer =
- trace.GetLiveThreadBuffer(thread.GetID());
- if (!buffer)
- return buffer.takeError();
- raw_trace_size = buffer->size();
- if (Expected<pt_cpu> cpu_info = trace.GetCPUInfo())
- return DecodeInMemoryTrace(*thread.GetProcess(), trace,
- MutableArrayRef<uint8_t>(*buffer));
- else
- return cpu_info.takeError();
-}
-
-DecodedThreadSP ThreadDecoder::Decode() {
- if (!m_decoded_thread.hasValue())
- m_decoded_thread = DoDecode();
- return *m_decoded_thread;
-}
-
-PostMortemThreadDecoder::PostMortemThreadDecoder(
- const lldb::ThreadPostMortemTraceSP &trace_thread, TraceIntelPT &trace)
- : m_trace_thread(trace_thread), m_trace(trace) {}
-
-DecodedThreadSP PostMortemThreadDecoder::DoDecode() {
- size_t raw_trace_size = 0;
- if (Expected<std::vector<IntelPTInstruction>> instructions =
- DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace,
- m_trace_thread->GetTraceFile(), raw_trace_size))
- return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
- std::move(*instructions),
- raw_trace_size);
- else
- return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
- instructions.takeError());
-}
-
-LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace)
- : m_thread_sp(thread.shared_from_this()), m_trace(trace) {}
-
-DecodedThreadSP LiveThreadDecoder::DoDecode() {
- size_t raw_trace_size = 0;
- if (Expected<std::vector<IntelPTInstruction>> instructions =
- DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size))
- return std::make_shared<DecodedThread>(
- m_thread_sp, std::move(*instructions), raw_trace_size);
- else
- return std::make_shared<DecodedThread>(m_thread_sp,
- instructions.takeError());
-}
+++ /dev/null
-//===-- IntelPTDecoder.h --======--------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H
-#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H
-
-#include "intel-pt.h"
-
-#include "DecodedThread.h"
-#include "forward-declarations.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Utility/FileSpec.h"
-
-namespace lldb_private {
-namespace trace_intel_pt {
-
-/// Base class that handles the decoding of a thread and caches the result.
-class ThreadDecoder {
-public:
- virtual ~ThreadDecoder() = default;
-
- ThreadDecoder() = default;
-
- /// Decode the thread and store the result internally, to avoid
- /// recomputations.
- ///
- /// \return
- /// A \a DecodedThread instance.
- DecodedThreadSP Decode();
-
- ThreadDecoder(const ThreadDecoder &other) = delete;
- ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
-
-protected:
- /// Decode the thread.
- ///
- /// \return
- /// A \a DecodedThread instance.
- virtual DecodedThreadSP DoDecode() = 0;
-
- llvm::Optional<DecodedThreadSP> m_decoded_thread;
-};
-
-/// Decoder implementation for \a lldb_private::ThreadPostMortemTrace, which are
-/// non-live processes that come trace session files.
-class PostMortemThreadDecoder : public ThreadDecoder {
-public:
- /// \param[in] trace_thread
- /// The thread whose trace file will be decoded.
- ///
- /// \param[in] trace
- /// The main Trace object who owns this decoder and its data.
- PostMortemThreadDecoder(const lldb::ThreadPostMortemTraceSP &trace_thread,
- TraceIntelPT &trace);
-
-private:
- DecodedThreadSP DoDecode() override;
-
- lldb::ThreadPostMortemTraceSP m_trace_thread;
- TraceIntelPT &m_trace;
-};
-
-class LiveThreadDecoder : public ThreadDecoder {
-public:
- /// \param[in] thread
- /// The thread whose traces will be decoded.
- ///
- /// \param[in] trace
- /// The main Trace object who owns this decoder and its data.
- LiveThreadDecoder(Thread &thread, TraceIntelPT &trace);
-
-private:
- DecodedThreadSP DoDecode() override;
-
- lldb::ThreadSP m_thread_sp;
- TraceIntelPT &m_trace;
-};
-
-} // namespace trace_intel_pt
-} // namespace lldb_private
-
-#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H
+++ /dev/null
-//===-- TraceIntelPTSessionFileParser.cpp ---------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TraceIntelPTSessionFileParser.h"
-
-#include "../common/ThreadPostMortemTrace.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/ThreadList.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::trace_intel_pt;
-using namespace llvm;
-
-StringRef TraceIntelPTSessionFileParser::GetSchema() {
- static std::string schema;
- if (schema.empty()) {
- schema = TraceSessionFileParser::BuildSchema(R"({
- "type": "intel-pt",
- "cpuInfo": {
- "vendor": "intel" | "unknown",
- "family": integer,
- "model": integer,
- "stepping": integer
- }
- })");
- }
- return schema;
-}
-
-pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU(
- const JSONTraceIntelPTCPUInfo &cpu_info) {
- return {cpu_info.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown,
- static_cast<uint16_t>(cpu_info.family),
- static_cast<uint8_t>(cpu_info.model),
- static_cast<uint8_t>(cpu_info.stepping)};
-}
-
-TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
- const pt_cpu &cpu_info, std::vector<ParsedProcess> &parsed_processes) {
- std::vector<ThreadPostMortemTraceSP> threads;
- for (const ParsedProcess &parsed_process : parsed_processes)
- threads.insert(threads.end(), parsed_process.threads.begin(),
- parsed_process.threads.end());
-
- TraceSP trace_instance(new TraceIntelPT(cpu_info, threads));
- for (const ParsedProcess &parsed_process : parsed_processes)
- parsed_process.target_sp->SetTrace(trace_instance);
-
- return trace_instance;
-}
-
-Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
- json::Path::Root root("traceSession");
- TraceSessionFileParser::JSONTraceSession<JSONTraceIntelPTSettings> session;
- if (!json::fromJSON(m_trace_session_file, session, root))
- return CreateJSONError(root, m_trace_session_file);
-
- if (Expected<std::vector<ParsedProcess>> parsed_processes =
- ParseCommonSessionFile(session))
- return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.cpuInfo),
- *parsed_processes);
- else
- return parsed_processes.takeError();
-}
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(
- const Value &value,
- TraceIntelPTSessionFileParser::JSONTraceIntelPTSettings &plugin_settings,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("cpuInfo", plugin_settings.cpuInfo) &&
- fromJSON(
- value,
- (TraceSessionFileParser::JSONTracePluginSettings &)plugin_settings,
- path);
-}
-
-bool fromJSON(const json::Value &value,
- TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info,
- Path path) {
- ObjectMapper o(value, path);
- return o && o.map("vendor", cpu_info.vendor) &&
- o.map("family", cpu_info.family) && o.map("model", cpu_info.model) &&
- o.map("stepping", cpu_info.stepping);
-}
-
-Value toJSON(
- const TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info) {
- return Value(Object{{"family", cpu_info.family},
- {"model", cpu_info.model},
- {"stepping", cpu_info.stepping},
- {"vendor", cpu_info.vendor}});
-}
-
-} // namespace json
-} // namespace llvm
+++ /dev/null
-//===-- TraceIntelPTSessionFileParser.h -----------------------*- C++ //-*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H
-#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H
-
-#include "TraceIntelPT.h"
-
-#include "../common/TraceSessionFileParser.h"
-
-namespace lldb_private {
-namespace trace_intel_pt {
-
-class TraceIntelPT;
-
-class TraceIntelPTSessionFileParser : public TraceSessionFileParser {
-public:
- struct JSONTraceIntelPTCPUInfo {
- int64_t family;
- int64_t model;
- int64_t stepping;
- std::string vendor;
- };
-
- struct JSONTraceIntelPTSettings
- : TraceSessionFileParser::JSONTracePluginSettings {
- JSONTraceIntelPTCPUInfo cpuInfo;
- };
-
- /// See \a TraceSessionFileParser::TraceSessionFileParser for the description
- /// of these fields.
- TraceIntelPTSessionFileParser(Debugger &debugger,
- const llvm::json::Value &trace_session_file,
- llvm::StringRef session_file_dir)
- : TraceSessionFileParser(debugger, session_file_dir, GetSchema()),
- m_trace_session_file(trace_session_file) {}
-
- /// \return
- /// The JSON schema for the session data.
- static llvm::StringRef GetSchema();
-
- /// Parse the structured data trace session and create the corresponding \a
- /// Target objects. In case of an error, no targets are created.
- ///
- /// \return
- /// A \a lldb::TraceSP instance with the trace session data. In case of
- /// errors, return a null pointer.
- llvm::Expected<lldb::TraceSP> Parse();
-
- lldb::TraceSP
- CreateTraceIntelPTInstance(const pt_cpu &cpu_info,
- std::vector<ParsedProcess> &parsed_processes);
-
-private:
- static pt_cpu ParsePTCPU(const JSONTraceIntelPTCPUInfo &cpu_info);
-
- const llvm::json::Value &m_trace_session_file;
-};
-
-} // namespace trace_intel_pt
-} // namespace lldb_private
-
-namespace llvm {
-namespace json {
-
-bool fromJSON(const Value &value,
- lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
- JSONTraceIntelPTSettings &plugin_settings,
- Path path);
-
-bool fromJSON(const llvm::json::Value &value,
- lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
- JSONTraceIntelPTCPUInfo &packet,
- llvm::json::Path path);
-
-llvm::json::Value
-toJSON(const lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser::
- JSONTraceIntelPTCPUInfo &packet);
-
-} // namespace json
-} // namespace llvm
-
-#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H
: m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM),
m_machine_sp_regnum(LLDB_INVALID_REGNUM),
m_machine_fp_regnum(LLDB_INVALID_REGNUM),
+ m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM),
m_lldb_ip_regnum(LLDB_INVALID_REGNUM),
m_lldb_sp_regnum(LLDB_INVALID_REGNUM),
m_lldb_fp_regnum(LLDB_INVALID_REGNUM),
-
- m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1),
+ m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch),
+ m_cpu(k_cpu_unspecified), m_wordsize(-1),
m_register_map_initialized(false), m_disasm_context() {
m_disasm_context =
::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,
// The second byte is a ModR/M /4 byte, strip off the registers
uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7;
- // Don't handle 0x24 disp32, because the target address is
- // knowable statically - pc_rel_branch_or_jump_p() will
- // return the target address.
-
// [reg]
if (second_byte_sans_reg == 0x20)
return true;
if (second_byte_sans_reg == 0xe0)
return true;
- // disp32
- // jumps to an address stored in memory, the value can't be cached
- // in an unwind plan.
- if (second_byte_sans_reg == 0x24)
- return true;
-
- // use SIB byte
- // ff 24 fe jmpq *(%rsi,%rdi,8)
- if (second_byte_sans_reg == 0x24)
- return true;
-
return false;
}
// path jumps over the mid-function epilogue
UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
- int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the
+ int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the
// epilogue started executed
- bool prologue_completed_is_aligned;
+ bool prologue_completed_is_aligned = false;
std::vector<bool> prologue_completed_saved_registers;
while (current_func_text_offset < size) {
+++ /dev/null
-//===-- TraceInstructionDumper.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/TraceInstructionDumper.h"
-
-#include "lldb/Core/Module.h"
-#include "lldb/Symbol/Function.h"
-#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/SectionLoadList.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace llvm;
-
-TraceInstructionDumper::TraceInstructionDumper(lldb::TraceCursorUP &&cursor_up,
- int initial_index, bool raw,
- bool show_tsc)
- : m_cursor_up(std::move(cursor_up)), m_index(initial_index), m_raw(raw),
- m_show_tsc(show_tsc) {}
-
-/// \return
-/// Return \b true if the cursor could move one step.
-bool TraceInstructionDumper::TryMoveOneStep() {
- if (!m_cursor_up->Next()) {
- SetNoMoreData();
- return false;
- }
- m_index += m_cursor_up->IsForwards() ? 1 : -1;
- return true;
-}
-
-/// \return
-/// The number of characters that would be needed to print the given
-/// integer.
-static int GetNumberOfChars(int num) {
- if (num == 0)
- return 1;
- return (num < 0 ? 1 : 0) + static_cast<int>(log10(abs(num))) + 1;
-}
-
-/// Helper struct that holds symbol, disassembly and address information of an
-/// instruction.
-struct InstructionSymbolInfo {
- SymbolContext sc;
- Address address;
- lldb::addr_t load_address;
- lldb::DisassemblerSP disassembler;
- lldb::InstructionSP instruction;
- lldb_private::ExecutionContext exe_ctx;
-};
-
-// This custom LineEntry validator is neded because some line_entries have
-// 0 as line, which is meaningless. Notice that LineEntry::IsValid only
-// checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX.
-static bool IsLineEntryValid(const LineEntry &line_entry) {
- return line_entry.IsValid() && line_entry.line > 0;
-}
-
-/// \return
-/// \b true if the provided line entries match line, column and source file.
-/// This function assumes that the line entries are valid.
-static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) {
- if (a.line != b.line)
- return false;
- if (a.column != b.column)
- return false;
- return a.file == b.file;
-}
-
-/// Compare the symbol contexts of the provided \a InstructionSymbolInfo
-/// objects.
-///
-/// \return
-/// \a true if both instructions belong to the same scope level analized
-/// in the following order:
-/// - module
-/// - symbol
-/// - function
-/// - line
-static bool
-IsSameInstructionSymbolContext(const InstructionSymbolInfo &prev_insn,
- const InstructionSymbolInfo &insn) {
- // module checks
- if (insn.sc.module_sp != prev_insn.sc.module_sp)
- return false;
-
- // symbol checks
- if (insn.sc.symbol != prev_insn.sc.symbol)
- return false;
-
- // function checks
- if (!insn.sc.function && !prev_insn.sc.function)
- return true;
- else if (insn.sc.function != prev_insn.sc.function)
- return false;
-
- // line entry checks
- const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry);
- const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry);
- if (curr_line_valid && prev_line_valid)
- return FileLineAndColumnMatches(insn.sc.line_entry,
- prev_insn.sc.line_entry);
- return curr_line_valid == prev_line_valid;
-}
-
-/// Dump the symbol context of the given instruction address if it's different
-/// from the symbol context of the previous instruction in the trace.
-///
-/// \param[in] prev_sc
-/// The symbol context of the previous instruction in the trace.
-///
-/// \param[in] address
-/// The address whose symbol information will be dumped.
-///
-/// \return
-/// The symbol context of the current address, which might differ from the
-/// previous one.
-static void
-DumpInstructionSymbolContext(Stream &s,
- Optional<InstructionSymbolInfo> prev_insn,
- InstructionSymbolInfo &insn) {
- if (prev_insn && IsSameInstructionSymbolContext(*prev_insn, insn))
- return;
-
- s.Printf(" ");
-
- if (!insn.sc.module_sp)
- s.Printf("(none)");
- else if (!insn.sc.function && !insn.sc.symbol)
- s.Printf("%s`(none)",
- insn.sc.module_sp->GetFileSpec().GetFilename().AsCString());
- else
- insn.sc.DumpStopContext(&s, insn.exe_ctx.GetTargetPtr(), insn.address,
- /*show_fullpath=*/false,
- /*show_module=*/true, /*show_inlined_frames=*/false,
- /*show_function_arguments=*/true,
- /*show_function_name=*/true);
- s.Printf("\n");
-}
-
-static void DumpInstructionDisassembly(Stream &s, InstructionSymbolInfo &insn) {
- if (!insn.instruction)
- return;
- s.Printf(" ");
- insn.instruction->Dump(&s, /*show_address=*/false, /*show_bytes=*/false,
- /*max_opcode_byte_size=*/0, &insn.exe_ctx, &insn.sc,
- /*prev_sym_ctx=*/nullptr,
- /*disassembly_addr_format=*/nullptr,
- /*max_address_text_size=*/0);
-}
-
-void TraceInstructionDumper::SetNoMoreData() { m_no_more_data = true; }
-
-bool TraceInstructionDumper::HasMoreData() { return !m_no_more_data; }
-
-void TraceInstructionDumper::DumpInstructions(Stream &s, size_t count) {
- ThreadSP thread_sp = m_cursor_up->GetExecutionContextRef().GetThreadSP();
- if (!thread_sp) {
- s.Printf("invalid thread");
- return;
- }
-
- s.Printf("thread #%u: tid = %" PRIu64 "\n", thread_sp->GetIndexID(),
- thread_sp->GetID());
-
- int digits_count = GetNumberOfChars(
- m_cursor_up->IsForwards() ? m_index + count - 1 : m_index - count + 1);
- bool was_prev_instruction_an_error = false;
-
- auto printMissingInstructionsMessage = [&]() {
- s.Printf(" ...missing instructions\n");
- };
-
- auto printInstructionIndex = [&]() {
- s.Printf(" [%*d] ", digits_count, m_index);
-
- if (m_show_tsc) {
- s.Printf("[tsc=");
-
- if (Optional<uint64_t> timestamp = m_cursor_up->GetTimestampCounter())
- s.Printf("0x%016" PRIx64, *timestamp);
- else
- s.Printf("unavailable");
-
- s.Printf("] ");
- }
- };
-
- InstructionSymbolInfo prev_insn_info;
-
- Target &target = thread_sp->GetProcess()->GetTarget();
- ExecutionContext exe_ctx;
- target.CalculateExecutionContext(exe_ctx);
- const ArchSpec &arch = target.GetArchitecture();
-
- // Find the symbol context for the given address reusing the previous
- // instruction's symbol context when possible.
- auto calculateSymbolContext = [&](const Address &address) {
- AddressRange range;
- if (prev_insn_info.sc.GetAddressRange(eSymbolContextEverything, 0,
- /*inline_block_range*/ false,
- range) &&
- range.Contains(address))
- return prev_insn_info.sc;
-
- SymbolContext sc;
- address.CalculateSymbolContext(&sc, eSymbolContextEverything);
- return sc;
- };
-
- // Find the disassembler for the given address reusing the previous
- // instruction's disassembler when possible.
- auto calculateDisass = [&](const Address &address, const SymbolContext &sc) {
- if (prev_insn_info.disassembler) {
- if (InstructionSP instruction =
- prev_insn_info.disassembler->GetInstructionList()
- .GetInstructionAtAddress(address))
- return std::make_tuple(prev_insn_info.disassembler, instruction);
- }
-
- if (sc.function) {
- if (DisassemblerSP disassembler =
- sc.function->GetInstructions(exe_ctx, nullptr)) {
- if (InstructionSP instruction =
- disassembler->GetInstructionList().GetInstructionAtAddress(
- address))
- return std::make_tuple(disassembler, instruction);
- }
- }
- // We fallback to a single instruction disassembler
- AddressRange range(address, arch.GetMaximumOpcodeByteSize());
- DisassemblerSP disassembler =
- Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr,
- /*flavor*/ nullptr, target, range);
- return std::make_tuple(disassembler,
- disassembler ? disassembler->GetInstructionList()
- .GetInstructionAtAddress(address)
- : InstructionSP());
- };
-
- for (size_t i = 0; i < count; i++) {
- if (!HasMoreData()) {
- s.Printf(" no more data\n");
- break;
- }
-
- if (Error err = m_cursor_up->GetError()) {
- if (!m_cursor_up->IsForwards() && !was_prev_instruction_an_error)
- printMissingInstructionsMessage();
-
- was_prev_instruction_an_error = true;
-
- printInstructionIndex();
- s << toString(std::move(err));
- } else {
- if (m_cursor_up->IsForwards() && was_prev_instruction_an_error)
- printMissingInstructionsMessage();
-
- was_prev_instruction_an_error = false;
-
- InstructionSymbolInfo insn_info;
-
- if (!m_raw) {
- insn_info.load_address = m_cursor_up->GetLoadAddress();
- insn_info.exe_ctx = exe_ctx;
- insn_info.address.SetLoadAddress(insn_info.load_address, &target);
- insn_info.sc = calculateSymbolContext(insn_info.address);
- std::tie(insn_info.disassembler, insn_info.instruction) =
- calculateDisass(insn_info.address, insn_info.sc);
-
- DumpInstructionSymbolContext(s, prev_insn_info, insn_info);
- }
-
- printInstructionIndex();
- s.Printf("0x%016" PRIx64, m_cursor_up->GetLoadAddress());
-
- if (!m_raw)
- DumpInstructionDisassembly(s, insn_info);
-
- prev_insn_info = insn_info;
- }
-
- s.Printf("\n");
- TryMoveOneStep();
- }
-}
#include "Plugins/Process/Utility/NetBSDSignals.h"
#include "Plugins/Process/Utility/OpenBSDSignals.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Utility/ArchSpec.h"
+#include <optional>
using namespace lldb_private;
+using namespace llvm;
UnixSignals::Signal::Signal(const char *name, bool default_suppress,
bool default_stop, bool default_notify,
const char *description, const char *alias)
: m_name(name), m_alias(alias), m_description(),
m_suppress(default_suppress), m_stop(default_stop),
- m_notify(default_notify) {
+ m_notify(default_notify),
+ m_default_suppress(default_suppress), m_default_stop(default_stop),
+ m_default_notify(default_notify) {
if (description)
m_description.assign(description);
}
return pos->first;
}
- const int32_t signo =
- StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
- if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ int32_t signo;
+ if (llvm::to_integer(name, signo))
return signo;
return LLDB_INVALID_SIGNAL_NUMBER;
}
uint64_t UnixSignals::GetVersion() const { return m_version; }
std::vector<int32_t>
-UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
- llvm::Optional<bool> should_stop,
- llvm::Optional<bool> should_notify) {
+UnixSignals::GetFilteredSignals(std::optional<bool> should_suppress,
+ std::optional<bool> should_stop,
+ std::optional<bool> should_notify) {
std::vector<int32_t> result;
for (int32_t signo = GetFirstSignalNumber();
signo != LLDB_INVALID_SIGNAL_NUMBER;
// If any of filtering conditions are not met, we move on to the next
// signal.
- if (should_suppress.hasValue() &&
- signal_suppress != should_suppress.getValue())
+ if (should_suppress && signal_suppress != *should_suppress)
continue;
- if (should_stop.hasValue() && signal_stop != should_stop.getValue())
+ if (should_stop && signal_stop != *should_stop)
continue;
- if (should_notify.hasValue() && signal_notify != should_notify.getValue())
+ if (should_notify && signal_notify != *should_notify)
continue;
result.push_back(signo);
return result;
}
+
+void UnixSignals::IncrementSignalHitCount(int signo) {
+ collection::iterator pos = m_signals.find(signo);
+ if (pos != m_signals.end())
+ pos->second.m_hit_count += 1;
+}
+
+json::Value UnixSignals::GetHitCountStatistics() const {
+ json::Array json_signals;
+ for (const auto &pair: m_signals) {
+ if (pair.second.m_hit_count > 0)
+ json_signals.emplace_back(json::Object{
+ { pair.second.m_name.GetCString(), pair.second.m_hit_count }
+ });
+ }
+ return std::move(json_signals);
+}
+
+void UnixSignals::Signal::Reset(bool reset_stop, bool reset_notify,
+ bool reset_suppress) {
+ if (reset_stop)
+ m_stop = m_default_stop;
+ if (reset_notify)
+ m_notify = m_default_notify;
+ if (reset_suppress)
+ m_suppress = m_default_suppress;
+}
+
+bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop,
+ bool reset_notify, bool reset_suppress) {
+ auto elem = m_signals.find(signo);
+ if (elem == m_signals.end())
+ return false;
+ (*elem).second.Reset(reset_stop, reset_notify, reset_suppress);
+ return true;
+}
+
//===----------------------------------------------------------------------===//
#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StringList.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Support/ARMTargetParser.h"
#include "llvm/Support/Compiler.h"
using namespace lldb;
{eByteOrderLittle, 8, 2, 4, llvm::Triple::riscv64, ArchSpec::eCore_riscv64,
"riscv64"},
+ {eByteOrderLittle, 4, 4, 4, llvm::Triple::loongarch32,
+ ArchSpec::eCore_loongarch32, "loongarch32"},
+ {eByteOrderLittle, 8, 4, 4, llvm::Triple::loongarch64,
+ ArchSpec::eCore_loongarch64, "loongarch64"},
+
{eByteOrderLittle, 4, 4, 4, llvm::Triple::UnknownArch,
ArchSpec::eCore_uknownMach32, "unknown-mach-32"},
{eByteOrderLittle, 8, 4, 4, llvm::Triple::UnknownArch,
};
void ArchSpec::ListSupportedArchNames(StringList &list) {
- for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i)
- list.AppendString(g_core_definitions[i].name);
+ for (const auto &def : g_core_definitions)
+ list.AppendString(def.name);
}
void ArchSpec::AutoComplete(CompletionRequest &request) {
- for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i)
- request.TryCompleteCurrentArg(g_core_definitions[i].name);
+ for (const auto &def : g_core_definitions)
+ request.TryCompleteCurrentArg(def.name);
}
#define CPU_ANY (UINT32_MAX)
{ArchSpec::eCore_uknownMach64, llvm::MachO::CPU_ARCH_ABI64, 0, 0xFF000000u, 0x00000000u}};
// clang-format on
-static const ArchDefinition g_macho_arch_def = {
- eArchTypeMachO, llvm::array_lengthof(g_macho_arch_entries),
- g_macho_arch_entries, "mach-o"};
+static const ArchDefinition g_macho_arch_def = {eArchTypeMachO,
+ std::size(g_macho_arch_entries),
+ g_macho_arch_entries, "mach-o"};
//===----------------------------------------------------------------------===//
// A table that gets searched linearly for matches. This table is used to
0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel MCU // FIXME: is this correct?
{ArchSpec::eCore_ppc_generic, llvm::ELF::EM_PPC, LLDB_INVALID_CPUTYPE,
0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC
- {ArchSpec::eCore_ppc64le_generic, llvm::ELF::EM_PPC64, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64le
- {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64
+ {ArchSpec::eCore_ppc64le_generic, llvm::ELF::EM_PPC64,
+ ArchSpec::eCore_ppc64le_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64le
+ {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64,
+ ArchSpec::eCore_ppc64_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64
{ArchSpec::eCore_arm_generic, llvm::ELF::EM_ARM, LLDB_INVALID_CPUTYPE,
0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM
{ArchSpec::eCore_arm_aarch64, llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE,
LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // HEXAGON
{ArchSpec::eCore_arc, llvm::ELF::EM_ARC_COMPACT2, LLDB_INVALID_CPUTYPE,
0xFFFFFFFFu, 0xFFFFFFFFu}, // ARC
- {ArchSpec::eCore_avr, llvm::ELF::EM_AVR, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // AVR
+ {ArchSpec::eCore_avr, llvm::ELF::EM_AVR, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // AVR
{ArchSpec::eCore_riscv32, llvm::ELF::EM_RISCV,
ArchSpec::eRISCVSubType_riscv32, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv32
{ArchSpec::eCore_riscv64, llvm::ELF::EM_RISCV,
ArchSpec::eRISCVSubType_riscv64, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv64
+ {ArchSpec::eCore_loongarch32, llvm::ELF::EM_LOONGARCH,
+ ArchSpec::eLoongArchSubType_loongarch32, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // loongarch32
+ {ArchSpec::eCore_loongarch64, llvm::ELF::EM_LOONGARCH,
+ ArchSpec::eLoongArchSubType_loongarch64, 0xFFFFFFFFu,
+ 0xFFFFFFFFu}, // loongarch64
};
static const ArchDefinition g_elf_arch_def = {
eArchTypeELF,
- llvm::array_lengthof(g_elf_arch_entries),
+ std::size(g_elf_arch_entries),
g_elf_arch_entries,
"elf",
};
static const ArchDefinition g_coff_arch_def = {
eArchTypeCOFF,
- llvm::array_lengthof(g_coff_arch_entries),
+ std::size(g_coff_arch_entries),
g_coff_arch_entries,
"pe-coff",
};
static const ArchDefinition *g_arch_definitions[] = {
&g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def};
-static const size_t k_num_arch_definitions =
- llvm::array_lengthof(g_arch_definitions);
-
//===----------------------------------------------------------------------===//
// Static helper functions.
// Get the architecture definition for a given object type.
static const ArchDefinition *FindArchDefinition(ArchitectureType arch_type) {
- for (unsigned int i = 0; i < k_num_arch_definitions; ++i) {
- const ArchDefinition *def = g_arch_definitions[i];
+ for (const ArchDefinition *def : g_arch_definitions) {
if (def->type == arch_type)
return def;
}
// Get an architecture definition by name.
static const CoreDefinition *FindCoreDefinition(llvm::StringRef name) {
- for (unsigned int i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) {
- if (name.equals_insensitive(g_core_definitions[i].name))
- return &g_core_definitions[i];
+ for (const auto &def : g_core_definitions) {
+ if (name.equals_insensitive(def.name))
+ return &def;
}
return nullptr;
}
static inline const CoreDefinition *FindCoreDefinition(ArchSpec::Core core) {
- if (core < llvm::array_lengthof(g_core_definitions))
+ if (core < std::size(g_core_definitions))
return &g_core_definitions[core];
return nullptr;
}
std::string ArchSpec::GetClangTargetCPU() const {
std::string cpu;
-
if (IsMIPS()) {
switch (m_core) {
case ArchSpec::eCore_mips32:
break;
}
}
+
+ if (GetTriple().isARM())
+ cpu = llvm::ARM::getARMCPUForArch(GetTriple(), "").str();
return cpu;
}
m_triple.setArch(core_def->machine);
}
} else {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET | LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_PLATFORM));
+ Log *log(GetLog(LLDBLog::Target | LLDBLog::Process | LLDBLog::Platform));
LLDB_LOGF(log,
"Unable to find a core definition for cpu 0x%" PRIx32
" sub %" PRId32,
return 0;
}
-bool ArchSpec::IsExactMatch(const ArchSpec &rhs) const {
- return IsEqualTo(rhs, true);
-}
-
-bool ArchSpec::IsCompatibleMatch(const ArchSpec &rhs) const {
- return IsEqualTo(rhs, false);
-}
-
static bool IsCompatibleEnvironment(llvm::Triple::EnvironmentType lhs,
llvm::Triple::EnvironmentType rhs) {
if (lhs == rhs)
return false;
}
-bool ArchSpec::IsEqualTo(const ArchSpec &rhs, bool exact_match) const {
+bool ArchSpec::IsMatch(const ArchSpec &rhs, MatchType match) const {
// explicitly ignoring m_distribution_id in this method.
if (GetByteOrder() != rhs.GetByteOrder() ||
- !cores_match(GetCore(), rhs.GetCore(), true, exact_match))
+ !cores_match(GetCore(), rhs.GetCore(), true, match == ExactMatch))
return false;
const llvm::Triple &lhs_triple = GetTriple();
const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor();
const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor();
- if (lhs_triple_vendor != rhs_triple_vendor) {
+
+ const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS();
+ const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS();
+
+ bool both_windows = lhs_triple.isOSWindows() && rhs_triple.isOSWindows();
+
+ // On Windows, the vendor field doesn't have any practical effect, but
+ // it is often set to either "pc" or "w64".
+ if ((lhs_triple_vendor != rhs_triple_vendor) &&
+ (match == ExactMatch || !both_windows)) {
const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified();
const bool lhs_vendor_specified = TripleVendorWasSpecified();
// Both architectures had the vendor specified, so if they aren't equal
return false;
}
- const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS();
- const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS();
const llvm::Triple::EnvironmentType lhs_triple_env =
lhs_triple.getEnvironment();
const llvm::Triple::EnvironmentType rhs_triple_env =
rhs_triple.getEnvironment();
- if (!exact_match) {
+ if (match == CompatibleMatch) {
// x86_64-apple-ios-macabi, x86_64-apple-macosx are compatible, no match.
if ((lhs_triple_os == llvm::Triple::IOS &&
lhs_triple_env == llvm::Triple::MacABI &&
return false;
// If the pair of os+env is both unspecified, match any other os+env combo.
- if (!exact_match && ((!lhs_os_specified && !lhs_triple.hasEnvironment()) ||
- (!rhs_os_specified && !rhs_triple.hasEnvironment())))
+ if (match == CompatibleMatch &&
+ ((!lhs_os_specified && !lhs_triple.hasEnvironment()) ||
+ (!rhs_os_specified && !rhs_triple.hasEnvironment())))
return true;
}
+ if (match == CompatibleMatch && both_windows)
+ return true; // The Windows environments (MSVC vs GNU) are compatible
+
return IsCompatibleEnvironment(lhs_triple_env, rhs_triple_env);
}
case ArchSpec::eCore_arm_generic:
if (enforce_exact_match)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ArchSpec::kCore_arm_any:
if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last)
return true;
}
bool ArchSpec::IsFullySpecifiedTriple() const {
- const auto &user_specified_triple = GetTriple();
-
- bool user_triple_fully_specified = false;
-
- if ((user_specified_triple.getOS() != llvm::Triple::UnknownOS) ||
- TripleOSWasSpecified()) {
- if ((user_specified_triple.getVendor() != llvm::Triple::UnknownVendor) ||
- TripleVendorWasSpecified()) {
- const unsigned unspecified = 0;
- if (!user_specified_triple.isOSDarwin() ||
- user_specified_triple.getOSMajorVersion() != unspecified) {
- user_triple_fully_specified = true;
- }
- }
- }
+ if (!TripleOSWasSpecified())
+ return false;
+
+ if (!TripleVendorWasSpecified())
+ return false;
- return user_triple_fully_specified;
+ const unsigned unspecified = 0;
+ const llvm::Triple &triple = GetTriple();
+ if (triple.isOSDarwin() && triple.getOSMajorVersion() == unspecified)
+ return false;
+
+ return true;
}
void ArchSpec::PiecewiseTripleCompare(
if (!environ_str.empty())
s << "-" << environ_str;
}
-
-void llvm::yaml::ScalarTraits<ArchSpec>::output(const ArchSpec &Val, void *,
- raw_ostream &Out) {
- Val.DumpTriple(Out);
-}
-
-llvm::StringRef
-llvm::yaml::ScalarTraits<ArchSpec>::input(llvm::StringRef Scalar, void *,
- ArchSpec &Val) {
- Val = ArchSpec(Scalar);
- return {};
-}
+++ /dev/null
-//===-- Logging.cpp -------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Logging.h"
-#include "lldb/Utility/Log.h"
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include <cstdarg>
-
-using namespace lldb_private;
-
-static constexpr Log::Category g_categories[] = {
- {{"api"}, {"log API calls and return values"}, LIBLLDB_LOG_API},
- {{"ast"}, {"log AST"}, LIBLLDB_LOG_AST},
- {{"break"}, {"log breakpoints"}, LIBLLDB_LOG_BREAKPOINTS},
- {{"commands"}, {"log command argument parsing"}, LIBLLDB_LOG_COMMANDS},
- {{"comm"}, {"log communication activities"}, LIBLLDB_LOG_COMMUNICATION},
- {{"conn"}, {"log connection details"}, LIBLLDB_LOG_CONNECTION},
- {{"demangle"}, {"log mangled names to catch demangler crashes"}, LIBLLDB_LOG_DEMANGLE},
- {{"dyld"}, {"log shared library related activities"}, LIBLLDB_LOG_DYNAMIC_LOADER},
- {{"event"}, {"log broadcaster, listener and event queue activities"}, LIBLLDB_LOG_EVENTS},
- {{"expr"}, {"log expressions"}, LIBLLDB_LOG_EXPRESSIONS},
- {{"formatters"}, {"log data formatters related activities"}, LIBLLDB_LOG_DATAFORMATTERS},
- {{"host"}, {"log host activities"}, LIBLLDB_LOG_HOST},
- {{"jit"}, {"log JIT events in the target"}, LIBLLDB_LOG_JIT_LOADER},
- {{"language"}, {"log language runtime events"}, LIBLLDB_LOG_LANGUAGE},
- {{"mmap"}, {"log mmap related activities"}, LIBLLDB_LOG_MMAP},
- {{"module"}, {"log module activities such as when modules are created, destroyed, replaced, and more"}, LIBLLDB_LOG_MODULES},
- {{"object"}, {"log object construction/destruction for important objects"}, LIBLLDB_LOG_OBJECT},
- {{"os"}, {"log OperatingSystem plugin related activities"}, LIBLLDB_LOG_OS},
- {{"platform"}, {"log platform events and activities"}, LIBLLDB_LOG_PLATFORM},
- {{"process"}, {"log process events and activities"}, LIBLLDB_LOG_PROCESS},
- {{"script"}, {"log events about the script interpreter"}, LIBLLDB_LOG_SCRIPT},
- {{"state"}, {"log private and public process state changes"}, LIBLLDB_LOG_STATE},
- {{"step"}, {"log step related activities"}, LIBLLDB_LOG_STEP},
- {{"symbol"}, {"log symbol related issues and warnings"}, LIBLLDB_LOG_SYMBOLS},
- {{"system-runtime"}, {"log system runtime events"}, LIBLLDB_LOG_SYSTEM_RUNTIME},
- {{"target"}, {"log target events and activities"}, LIBLLDB_LOG_TARGET},
- {{"temp"}, {"log internal temporary debug messages"}, LIBLLDB_LOG_TEMPORARY},
- {{"thread"}, {"log thread events and activities"}, LIBLLDB_LOG_THREAD},
- {{"types"}, {"log type system related activities"}, LIBLLDB_LOG_TYPES},
- {{"unwind"}, {"log stack unwind activities"}, LIBLLDB_LOG_UNWIND},
- {{"watch"}, {"log watchpoint related activities"}, LIBLLDB_LOG_WATCHPOINTS},
-};
-
-static Log::Channel g_log_channel(g_categories, LIBLLDB_LOG_DEFAULT);
-
-void lldb_private::InitializeLldbChannel() {
- Log::Register("lldb", g_log_channel);
-}
-
-Log *lldb_private::GetLogIfAllCategoriesSet(uint32_t mask) {
- return g_log_channel.GetLogIfAll(mask);
-}
-
-Log *lldb_private::GetLogIfAnyCategoriesSet(uint32_t mask) {
- return g_log_channel.GetLogIfAny(mask);
-}
+++ /dev/null
-//===-- Reproducer.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/ReproducerProvider.h"
-#include "lldb/Utility/Timer.h"
-
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Threading.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace llvm;
-using namespace llvm::yaml;
-
-Reproducer &Reproducer::Instance() { return *InstanceImpl(); }
-
-llvm::Error Reproducer::Initialize(ReproducerMode mode,
- llvm::Optional<FileSpec> root) {
- lldbassert(!InstanceImpl() && "Already initialized.");
- InstanceImpl().emplace();
-
- switch (mode) {
- case ReproducerMode::Capture: {
- if (!root) {
- SmallString<128> repro_dir;
- auto ec = sys::fs::createUniqueDirectory("reproducer", repro_dir);
- if (ec)
- return make_error<StringError>(
- "unable to create unique reproducer directory", ec);
- root.emplace(repro_dir);
- } else {
- auto ec = sys::fs::create_directory(root->GetPath());
- if (ec)
- return make_error<StringError>("unable to create reproducer directory",
- ec);
- }
- return Instance().SetCapture(root);
- } break;
- case ReproducerMode::Replay:
- return Instance().SetReplay(root, /*passive*/ false);
- case ReproducerMode::PassiveReplay:
- return Instance().SetReplay(root, /*passive*/ true);
- case ReproducerMode::Off:
- break;
- };
-
- return Error::success();
-}
-
-void Reproducer::Initialize() {
- llvm::cantFail(Initialize(repro::ReproducerMode::Off, llvm::None));
-}
-
-bool Reproducer::Initialized() { return InstanceImpl().operator bool(); }
-
-void Reproducer::Terminate() {
- lldbassert(InstanceImpl() && "Already terminated.");
- InstanceImpl().reset();
-}
-
-Optional<Reproducer> &Reproducer::InstanceImpl() {
- static Optional<Reproducer> g_reproducer;
- return g_reproducer;
-}
-
-const Generator *Reproducer::GetGenerator() const {
- std::lock_guard<std::mutex> guard(m_mutex);
- if (m_generator)
- return &(*m_generator);
- return nullptr;
-}
-
-const Loader *Reproducer::GetLoader() const {
- std::lock_guard<std::mutex> guard(m_mutex);
- if (m_loader)
- return &(*m_loader);
- return nullptr;
-}
-
-Generator *Reproducer::GetGenerator() {
- std::lock_guard<std::mutex> guard(m_mutex);
- if (m_generator)
- return &(*m_generator);
- return nullptr;
-}
-
-Loader *Reproducer::GetLoader() {
- std::lock_guard<std::mutex> guard(m_mutex);
- if (m_loader)
- return &(*m_loader);
- return nullptr;
-}
-
-llvm::Error Reproducer::SetCapture(llvm::Optional<FileSpec> root) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
- if (root && m_loader)
- return make_error<StringError>(
- "cannot generate a reproducer when replay one",
- inconvertibleErrorCode());
-
- if (!root) {
- m_generator.reset();
- return Error::success();
- }
-
- m_generator.emplace(*root);
- return Error::success();
-}
-
-llvm::Error Reproducer::SetReplay(llvm::Optional<FileSpec> root, bool passive) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
- if (root && m_generator)
- return make_error<StringError>(
- "cannot replay a reproducer when generating one",
- inconvertibleErrorCode());
-
- if (!root) {
- m_loader.reset();
- return Error::success();
- }
-
- m_loader.emplace(*root, passive);
- if (auto e = m_loader->LoadIndex())
- return e;
-
- return Error::success();
-}
-
-FileSpec Reproducer::GetReproducerPath() const {
- if (auto g = GetGenerator())
- return g->GetRoot();
- if (auto l = GetLoader())
- return l->GetRoot();
- return {};
-}
-
-static FileSpec MakeAbsolute(const FileSpec &file_spec) {
- SmallString<128> path;
- file_spec.GetPath(path, false);
- llvm::sys::fs::make_absolute(path);
- return FileSpec(path, file_spec.GetPathStyle());
-}
-
-Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) {
- GetOrCreate<repro::WorkingDirectoryProvider>();
- GetOrCreate<repro::HomeDirectoryProvider>();
-}
-
-Generator::~Generator() {
- if (!m_done) {
- if (m_auto_generate) {
- Keep();
- llvm::cantFail(Finalize(GetRoot()));
- } else {
- Discard();
- }
- }
-}
-
-ProviderBase *Generator::Register(std::unique_ptr<ProviderBase> provider) {
- std::lock_guard<std::mutex> lock(m_providers_mutex);
- std::pair<const void *, std::unique_ptr<ProviderBase>> key_value(
- provider->DynamicClassID(), std::move(provider));
- auto e = m_providers.insert(std::move(key_value));
- return e.first->getSecond().get();
-}
-
-void Generator::Keep() {
- LLDB_SCOPED_TIMER();
- assert(!m_done);
- m_done = true;
-
- for (auto &provider : m_providers)
- provider.second->Keep();
-
- AddProvidersToIndex();
-}
-
-void Generator::Discard() {
- LLDB_SCOPED_TIMER();
- assert(!m_done);
- m_done = true;
-
- for (auto &provider : m_providers)
- provider.second->Discard();
-
- llvm::sys::fs::remove_directories(m_root.GetPath());
-}
-
-void Generator::SetAutoGenerate(bool b) { m_auto_generate = b; }
-
-bool Generator::IsAutoGenerate() const { return m_auto_generate; }
-
-const FileSpec &Generator::GetRoot() const { return m_root; }
-
-void Generator::AddProvidersToIndex() {
- FileSpec index = m_root;
- index.AppendPathComponent("index.yaml");
-
- std::error_code EC;
- auto strm = std::make_unique<raw_fd_ostream>(index.GetPath(), EC,
- sys::fs::OpenFlags::OF_None);
- yaml::Output yout(*strm);
-
- std::vector<std::string> files;
- files.reserve(m_providers.size());
- for (auto &provider : m_providers) {
- files.emplace_back(provider.second->GetFile());
- }
-
- yout << files;
-}
-
-Loader::Loader(FileSpec root, bool passive)
- : m_root(MakeAbsolute(std::move(root))), m_loaded(false),
- m_passive_replay(passive) {}
-
-llvm::Error Loader::LoadIndex() {
- if (m_loaded)
- return llvm::Error::success();
-
- FileSpec index = m_root.CopyByAppendingPathComponent("index.yaml");
-
- auto error_or_file = MemoryBuffer::getFile(index.GetPath());
- if (auto err = error_or_file.getError())
- return make_error<StringError>("unable to load reproducer index", err);
-
- yaml::Input yin((*error_or_file)->getBuffer());
- yin >> m_files;
- if (auto err = yin.error())
- return make_error<StringError>("unable to read reproducer index", err);
-
- // Sort files to speed up search.
- llvm::sort(m_files);
-
- // Remember that we've loaded the index.
- m_loaded = true;
-
- return llvm::Error::success();
-}
-
-bool Loader::HasFile(StringRef file) {
- assert(m_loaded);
- auto it = std::lower_bound(m_files.begin(), m_files.end(), file.str());
- return (it != m_files.end()) && (*it == file);
-}
-
-void Verifier::Verify(
- llvm::function_ref<void(llvm::StringRef)> error_callback,
- llvm::function_ref<void(llvm::StringRef)> warning_callback,
- llvm::function_ref<void(llvm::StringRef)> note_callack) const {
- if (!m_loader) {
- error_callback("invalid loader");
- return;
- }
-
- FileSpec vfs_mapping = m_loader->GetFile<FileProvider::Info>();
- ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
- vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
- if (!buffer) {
- error_callback("unable to read files: " + buffer.getError().message());
- return;
- }
-
- IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
- std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
- if (!vfs) {
- error_callback("unable to initialize the virtual file system");
- return;
- }
-
- auto &redirecting_vfs = static_cast<vfs::RedirectingFileSystem &>(*vfs);
- redirecting_vfs.setFallthrough(false);
-
- {
- llvm::Expected<std::string> working_dir =
- GetDirectoryFrom<WorkingDirectoryProvider>(m_loader);
- if (working_dir) {
- if (!vfs->exists(*working_dir))
- warning_callback("working directory '" + *working_dir + "' not in VFS");
- vfs->setCurrentWorkingDirectory(*working_dir);
- } else {
- warning_callback("no working directory in reproducer: " +
- toString(working_dir.takeError()));
- }
- }
-
- {
- llvm::Expected<std::string> home_dir =
- GetDirectoryFrom<HomeDirectoryProvider>(m_loader);
- if (home_dir) {
- if (!vfs->exists(*home_dir))
- warning_callback("home directory '" + *home_dir + "' not in VFS");
- } else {
- warning_callback("no home directory in reproducer: " +
- toString(home_dir.takeError()));
- }
- }
-
- {
- Expected<std::string> symbol_files =
- m_loader->LoadBuffer<SymbolFileProvider>();
- if (symbol_files) {
- std::vector<SymbolFileProvider::Entry> entries;
- llvm::yaml::Input yin(*symbol_files);
- yin >> entries;
- for (const auto &entry : entries) {
- if (!entry.module_path.empty() && !vfs->exists(entry.module_path)) {
- warning_callback("'" + entry.module_path + "': module path for " +
- entry.uuid + " not in VFS");
- }
- if (!entry.symbol_path.empty() && !vfs->exists(entry.symbol_path)) {
- warning_callback("'" + entry.symbol_path + "': symbol path for " +
- entry.uuid + " not in VFS");
- }
- }
- } else {
- llvm::consumeError(symbol_files.takeError());
- }
- }
-
- // Missing files in the VFS are notes rather than warnings. Because the VFS
- // is a snapshot, temporary files could have been removed between when they
- // were recorded and when the reproducer was generated.
- std::vector<llvm::StringRef> roots = redirecting_vfs.getRoots();
- for (llvm::StringRef root : roots) {
- std::error_code ec;
- vfs::recursive_directory_iterator iter(*vfs, root, ec);
- vfs::recursive_directory_iterator end;
- for (; iter != end && !ec; iter.increment(ec)) {
- ErrorOr<vfs::Status> status = vfs->status(iter->path());
- if (!status)
- note_callack("'" + iter->path().str() +
- "': " + status.getError().message());
- }
- }
-}
-
-static llvm::Error addPaths(StringRef path,
- function_ref<void(StringRef)> callback) {
- auto buffer = llvm::MemoryBuffer::getFile(path);
- if (!buffer)
- return errorCodeToError(buffer.getError());
-
- SmallVector<StringRef, 0> paths;
- (*buffer)->getBuffer().split(paths, '\0');
- for (StringRef p : paths) {
- if (!p.empty() && llvm::sys::fs::exists(p))
- callback(p);
- }
-
- return errorCodeToError(llvm::sys::fs::remove(path));
-}
-
-llvm::Error repro::Finalize(Loader *loader) {
- if (!loader)
- return make_error<StringError>("invalid loader",
- llvm::inconvertibleErrorCode());
-
- FileSpec reproducer_root = loader->GetRoot();
- std::string files_path =
- reproducer_root.CopyByAppendingPathComponent("files.txt").GetPath();
- std::string dirs_path =
- reproducer_root.CopyByAppendingPathComponent("dirs.txt").GetPath();
-
- FileCollector collector(
- reproducer_root.CopyByAppendingPathComponent("root").GetPath(),
- reproducer_root.GetPath());
-
- if (Error e =
- addPaths(files_path, [&](StringRef p) { collector.addFile(p); }))
- return e;
-
- if (Error e =
- addPaths(dirs_path, [&](StringRef p) { collector.addDirectory(p); }))
- return e;
-
- FileSpec mapping =
- reproducer_root.CopyByAppendingPathComponent(FileProvider::Info::file);
- if (auto ec = collector.copyFiles(/*stop_on_error=*/false))
- return errorCodeToError(ec);
- collector.writeMapping(mapping.GetPath());
-
- return llvm::Error::success();
-}
-
-llvm::Error repro::Finalize(const FileSpec &root) {
- Loader loader(root);
- if (Error e = loader.LoadIndex())
- return e;
- return Finalize(&loader);
-}
+++ /dev/null
-//===-- ReproducerInstrumentation.cpp -------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/ReproducerInstrumentation.h"
-#include "lldb/Utility/Reproducer.h"
-#include <cstdio>
-#include <cstdlib>
-#include <limits>
-#include <thread>
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-
-void *IndexToObject::GetObjectForIndexImpl(unsigned idx) {
- return m_mapping.lookup(idx);
-}
-
-void IndexToObject::AddObjectForIndexImpl(unsigned idx, void *object) {
- assert(idx != 0 && "Cannot add object for sentinel");
- m_mapping[idx] = object;
-}
-
-std::vector<void *> IndexToObject::GetAllObjects() const {
- std::vector<std::pair<unsigned, void *>> pairs;
- for (auto &e : m_mapping) {
- pairs.emplace_back(e.first, e.second);
- }
-
- // Sort based on index.
- std::sort(pairs.begin(), pairs.end(),
- [](auto &lhs, auto &rhs) { return lhs.first < rhs.first; });
-
- std::vector<void *> objects;
- objects.reserve(pairs.size());
- for (auto &p : pairs) {
- objects.push_back(p.second);
- }
-
- return objects;
-}
-
-template <> const uint8_t *Deserializer::Deserialize<const uint8_t *>() {
- return Deserialize<uint8_t *>();
-}
-
-template <> void *Deserializer::Deserialize<void *>() {
- return const_cast<void *>(Deserialize<const void *>());
-}
-
-template <> const void *Deserializer::Deserialize<const void *>() {
- return nullptr;
-}
-
-template <> char *Deserializer::Deserialize<char *>() {
- return const_cast<char *>(Deserialize<const char *>());
-}
-
-template <> const char *Deserializer::Deserialize<const char *>() {
- const size_t size = Deserialize<size_t>();
- if (size == std::numeric_limits<size_t>::max())
- return nullptr;
- assert(HasData(size + 1));
- const char *str = m_buffer.data();
- m_buffer = m_buffer.drop_front(size + 1);
-#ifdef LLDB_REPRO_INSTR_TRACE
- llvm::errs() << "Deserializing with " << LLVM_PRETTY_FUNCTION << " -> \""
- << str << "\"\n";
-#endif
- return str;
-}
-
-template <> const char **Deserializer::Deserialize<const char **>() {
- const size_t size = Deserialize<size_t>();
- if (size == 0)
- return nullptr;
- const char **r =
- reinterpret_cast<const char **>(calloc(size + 1, sizeof(char *)));
- for (size_t i = 0; i < size; ++i)
- r[i] = Deserialize<const char *>();
- return r;
-}
-
-void Deserializer::CheckSequence(unsigned sequence) {
- if (m_expected_sequence && *m_expected_sequence != sequence)
- llvm::report_fatal_error(
- "The result does not match the preceding "
- "function. This is probably the result of concurrent "
- "use of the SB API during capture, which is currently not "
- "supported.");
- m_expected_sequence.reset();
-}
-
-bool Registry::Replay(const FileSpec &file) {
- auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
- if (auto err = error_or_file.getError())
- return false;
-
- return Replay((*error_or_file)->getBuffer());
-}
-
-bool Registry::Replay(llvm::StringRef buffer) {
- Deserializer deserializer(buffer);
- return Replay(deserializer);
-}
-
-bool Registry::Replay(Deserializer &deserializer) {
-#ifndef LLDB_REPRO_INSTR_TRACE
- Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_API);
-#endif
-
- // Disable buffering stdout so that we approximate the way things get flushed
- // during an interactive session.
- setvbuf(stdout, nullptr, _IONBF, 0);
-
- while (deserializer.HasData(1)) {
- unsigned sequence = deserializer.Deserialize<unsigned>();
- unsigned id = deserializer.Deserialize<unsigned>();
-
-#ifndef LLDB_REPRO_INSTR_TRACE
- LLDB_LOG(log, "Replaying {0}: {1}", id, GetSignature(id));
-#else
- llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n";
-#endif
-
- deserializer.SetExpectedSequence(sequence);
- GetReplayer(id)->operator()(deserializer);
- }
-
- // Add a small artificial delay to ensure that all asynchronous events have
- // completed before we exit.
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
- return true;
-}
-
-void Registry::DoRegister(uintptr_t RunID, std::unique_ptr<Replayer> replayer,
- SignatureStr signature) {
- const unsigned id = m_replayers.size() + 1;
- assert(m_replayers.find(RunID) == m_replayers.end());
- m_replayers[RunID] = std::make_pair(std::move(replayer), id);
- m_ids[id] =
- std::make_pair(m_replayers[RunID].first.get(), std::move(signature));
-}
-
-unsigned Registry::GetID(uintptr_t addr) {
- unsigned id = m_replayers[addr].second;
- assert(id != 0 && "Forgot to add function to registry?");
- return id;
-}
-
-std::string Registry::GetSignature(unsigned id) {
- assert(m_ids.count(id) != 0 && "ID not in registry");
- return m_ids[id].second.ToString();
-}
-
-void Registry::CheckID(unsigned expected, unsigned actual) {
- if (expected != actual) {
- llvm::errs() << "Reproducer expected signature " << expected << ": '"
- << GetSignature(expected) << "'\n";
- llvm::errs() << "Reproducer actual signature " << actual << ": '"
- << GetSignature(actual) << "'\n";
- llvm::report_fatal_error(
- "Detected reproducer replay divergence. Refusing to continue.");
- }
-
-#ifdef LLDB_REPRO_INSTR_TRACE
- llvm::errs() << "Replaying " << actual << ": " << GetSignature(actual)
- << "\n";
-#endif
-}
-
-Replayer *Registry::GetReplayer(unsigned id) {
- assert(m_ids.count(id) != 0 && "ID not in registry");
- return m_ids[id].first;
-}
-
-std::string Registry::SignatureStr::ToString() const {
- return (result + (result.empty() ? "" : " ") + scope + "::" + name + args)
- .str();
-}
-
-unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) {
- unsigned index = m_mapping.size() + 1;
- auto it = m_mapping.find(object);
- if (it == m_mapping.end())
- m_mapping[object] = index;
- return m_mapping[object];
-}
-
-Recorder::Recorder()
- : m_pretty_func(), m_pretty_args(),
-
- m_sequence(std::numeric_limits<unsigned>::max()) {
- if (!g_global_boundary) {
- g_global_boundary = true;
- m_local_boundary = true;
- m_sequence = GetNextSequenceNumber();
- }
-}
-
-Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args)
- : m_serializer(nullptr), m_pretty_func(pretty_func),
- m_pretty_args(pretty_args), m_local_boundary(false),
- m_result_recorded(true),
- m_sequence(std::numeric_limits<unsigned>::max()) {
- if (!g_global_boundary) {
- g_global_boundary = true;
- m_local_boundary = true;
- m_sequence = GetNextSequenceNumber();
- LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})",
- m_pretty_func, m_pretty_args);
- }
-}
-
-Recorder::~Recorder() {
- assert(m_result_recorded && "Did you forget LLDB_RECORD_RESULT?");
- UpdateBoundary();
-}
-
-unsigned Recorder::GetSequenceNumber() const {
- assert(m_sequence != std::numeric_limits<unsigned>::max());
- return m_sequence;
-}
-
-void InstrumentationData::Initialize(Serializer &serializer,
- Registry ®istry) {
- InstanceImpl().emplace(serializer, registry);
-}
-
-void InstrumentationData::Initialize(Deserializer &deserializer,
- Registry ®istry) {
- InstanceImpl().emplace(deserializer, registry);
-}
-
-InstrumentationData &InstrumentationData::Instance() {
- if (!InstanceImpl())
- InstanceImpl().emplace();
- return *InstanceImpl();
-}
-
-llvm::Optional<InstrumentationData> &InstrumentationData::InstanceImpl() {
- static llvm::Optional<InstrumentationData> g_instrumentation_data;
- return g_instrumentation_data;
-}
-
-thread_local bool lldb_private::repro::Recorder::g_global_boundary = false;
-std::atomic<unsigned> lldb_private::repro::Recorder::g_sequence;
-std::mutex lldb_private::repro::Recorder::g_mutex;
+++ /dev/null
-//===-- Reproducer.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/ReproducerProvider.h"
-#include "lldb/Utility/ProcessInfo.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace llvm;
-using namespace llvm::yaml;
-
-llvm::Expected<std::unique_ptr<DataRecorder>>
-DataRecorder::Create(const FileSpec &filename) {
- std::error_code ec;
- auto recorder = std::make_unique<DataRecorder>(std::move(filename), ec);
- if (ec)
- return llvm::errorCodeToError(ec);
- return std::move(recorder);
-}
-
-llvm::Expected<std::unique_ptr<YamlRecorder>>
-YamlRecorder::Create(const FileSpec &filename) {
- std::error_code ec;
- auto recorder = std::make_unique<YamlRecorder>(std::move(filename), ec);
- if (ec)
- return llvm::errorCodeToError(ec);
- return std::move(recorder);
-}
-
-void VersionProvider::Keep() {
- FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- os << m_version << "\n";
-}
-
-FlushingFileCollector::FlushingFileCollector(llvm::StringRef files_path,
- llvm::StringRef dirs_path,
- std::error_code &ec) {
- auto clear = llvm::make_scope_exit([this]() {
- m_files_os.reset();
- m_dirs_os.reset();
- });
- m_files_os.emplace(files_path, ec, llvm::sys::fs::OF_Append);
- if (ec)
- return;
- m_dirs_os.emplace(dirs_path, ec, llvm::sys::fs::OF_Append);
- if (ec)
- return;
- clear.release();
-}
-
-void FlushingFileCollector::addFileImpl(StringRef file) {
- if (m_files_os) {
- *m_files_os << file << '\0';
- m_files_os->flush();
- }
-}
-
-llvm::vfs::directory_iterator
-FlushingFileCollector::addDirectoryImpl(const Twine &dir,
- IntrusiveRefCntPtr<vfs::FileSystem> vfs,
- std::error_code &dir_ec) {
- if (m_dirs_os) {
- *m_dirs_os << dir << '\0';
- m_dirs_os->flush();
- }
- return vfs->dir_begin(dir, dir_ec);
-}
-
-void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) {
- if (m_collector)
- m_collector->addFile(dir);
-}
-
-void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) {
- if (m_collector)
- m_collector->addDirectory(dir);
-}
-
-llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
-ProcessInfoRecorder::Create(const FileSpec &filename) {
- std::error_code ec;
- auto recorder =
- std::make_unique<ProcessInfoRecorder>(std::move(filename), ec);
- if (ec)
- return llvm::errorCodeToError(ec);
- return std::move(recorder);
-}
-
-void ProcessInfoProvider::Keep() {
- std::vector<std::string> files;
- for (auto &recorder : m_process_info_recorders) {
- recorder->Stop();
- files.push_back(recorder->GetFilename().GetPath());
- }
-
- FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
- llvm::yaml::Output yout(os);
- yout << files;
-}
-
-void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); }
-
-ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() {
- std::size_t i = m_process_info_recorders.size() + 1;
- std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") +
- llvm::Twine(i) + llvm::Twine(".yaml"))
- .str();
- auto recorder_or_error = ProcessInfoRecorder::Create(
- GetRoot().CopyByAppendingPathComponent(filename));
- if (!recorder_or_error) {
- llvm::consumeError(recorder_or_error.takeError());
- return nullptr;
- }
-
- m_process_info_recorders.push_back(std::move(*recorder_or_error));
- return m_process_info_recorders.back().get();
-}
-
-void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) {
- if (!m_record)
- return;
- llvm::yaml::Output yout(m_os);
- yout << const_cast<ProcessInstanceInfoList &>(process_infos);
- m_os.flush();
-}
-
-void SymbolFileProvider::AddSymbolFile(const UUID *uuid,
- const FileSpec &module_file,
- const FileSpec &symbol_file) {
- if (!uuid || (!module_file && !symbol_file))
- return;
- m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(),
- symbol_file.GetPath());
-}
-
-void SymbolFileProvider::Keep() {
- FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file);
- std::error_code ec;
- llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF);
- if (ec)
- return;
-
- // Remove duplicates.
- llvm::sort(m_symbol_files.begin(), m_symbol_files.end());
- m_symbol_files.erase(
- std::unique(m_symbol_files.begin(), m_symbol_files.end()),
- m_symbol_files.end());
-
- llvm::yaml::Output yout(os);
- yout << m_symbol_files;
-}
-
-SymbolFileLoader::SymbolFileLoader(Loader *loader) {
- if (!loader)
- return;
-
- FileSpec file = loader->GetFile<SymbolFileProvider::Info>();
- if (!file)
- return;
-
- auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
- if (auto err = error_or_file.getError())
- return;
-
- llvm::yaml::Input yin((*error_or_file)->getBuffer());
- yin >> m_symbol_files;
-}
-
-std::pair<FileSpec, FileSpec>
-SymbolFileLoader::GetPaths(const UUID *uuid) const {
- if (!uuid)
- return {};
-
- auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(),
- SymbolFileProvider::Entry(uuid->GetAsString()));
- if (it == m_symbol_files.end())
- return {};
- return std::make_pair<FileSpec, FileSpec>(FileSpec(it->module_path),
- FileSpec(it->symbol_path));
-}
-
-void ProviderBase::anchor() {}
-char CommandProvider::ID = 0;
-char FileProvider::ID = 0;
-char ProviderBase::ID = 0;
-char VersionProvider::ID = 0;
-char WorkingDirectoryProvider::ID = 0;
-char HomeDirectoryProvider::ID = 0;
-char ProcessInfoProvider::ID = 0;
-char SymbolFileProvider::ID = 0;
-const char *CommandProvider::Info::file = "command-interpreter.yaml";
-const char *CommandProvider::Info::name = "command-interpreter";
-const char *FileProvider::Info::file = "files.yaml";
-const char *FileProvider::Info::name = "files";
-const char *VersionProvider::Info::file = "version.txt";
-const char *VersionProvider::Info::name = "version";
-const char *WorkingDirectoryProvider::Info::file = "cwd.txt";
-const char *WorkingDirectoryProvider::Info::name = "cwd";
-const char *HomeDirectoryProvider::Info::file = "home.txt";
-const char *HomeDirectoryProvider::Info::name = "home";
-const char *ProcessInfoProvider::Info::file = "process-info.yaml";
-const char *ProcessInfoProvider::Info::name = "process-info";
-const char *SymbolFileProvider::Info::file = "symbol-files.yaml";
-const char *SymbolFileProvider::Info::name = "symbol-files";
+++ /dev/null
-//===-- StreamCallback.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StreamCallback.h"
-
-#include <string>
-
-using namespace lldb_private;
-
-StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton)
- : llvm::raw_ostream(true), m_callback(callback), m_baton(baton) {}
-
-void StreamCallback::write_impl(const char *Ptr, size_t Size) {
- m_callback(std::string(Ptr, Size).c_str(), m_baton);
-}
-
-uint64_t StreamCallback::current_pos() const { return 0; }
+++ /dev/null
-//===-- lldb.cpp ----------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "VCSVersion.inc"
-#include "lldb/lldb-private.h"
-#include "clang/Basic/Version.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-// LLDB_VERSION_STRING is set through a define so unlike the other defines
-// expanded with CMake, it lacks the double quotes.
-#define QUOTE(str) #str
-#define EXPAND_AND_QUOTE(str) QUOTE(str)
-
-static const char *GetLLDBVersion() {
-#ifdef LLDB_VERSION_STRING
- return EXPAND_AND_QUOTE(LLDB_VERSION_STRING);
-#else
- return "lldb version " CLANG_VERSION_STRING;
-#endif
-}
-
-static const char *GetLLDBRevision() {
-#ifdef LLDB_REVISION
- return LLDB_REVISION;
-#else
- return NULL;
-#endif
-}
-
-static const char *GetLLDBRepository() {
-#ifdef LLDB_REPOSITORY
- return LLDB_REPOSITORY;
-#else
- return NULL;
-#endif
-}
-
-const char *lldb_private::GetVersion() {
- static std::string g_version_str;
- if (g_version_str.empty()) {
- const char *lldb_version = GetLLDBVersion();
- const char *lldb_repo = GetLLDBRepository();
- const char *lldb_rev = GetLLDBRevision();
- g_version_str += lldb_version;
- if (lldb_repo || lldb_rev) {
- g_version_str += " (";
- if (lldb_repo)
- g_version_str += lldb_repo;
- if (lldb_repo && lldb_rev)
- g_version_str += " ";
- if (lldb_rev) {
- g_version_str += "revision ";
- g_version_str += lldb_rev;
- }
- g_version_str += ")";
- }
-
- std::string clang_rev(clang::getClangRevision());
- if (clang_rev.length() > 0) {
- g_version_str += "\n clang revision ";
- g_version_str += clang_rev;
- }
- std::string llvm_rev(clang::getLLVMRevision());
- if (llvm_rev.length() > 0) {
- g_version_str += "\n llvm revision ";
- g_version_str += llvm_rev;
- }
- }
- return g_version_str.c_str();
-}
+++ /dev/null
-Copyright (c) 2010-2015 Benjamin Peterson
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+++ /dev/null
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-# Copyright (c) 2010-2015 Benjamin Peterson
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-from __future__ import absolute_import
-
-import functools
-import itertools
-import operator
-import sys
-import types
-
-__author__ = "Benjamin Peterson <benjamin@python.org>"
-__version__ = "1.10.0"
-
-
-# Useful for very coarse version differentiation.
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-PY34 = sys.version_info[0:2] >= (3, 4)
-
-if PY3:
- string_types = str,
- integer_types = int,
- class_types = type,
- text_type = str
- binary_type = bytes
-
- MAXSIZE = sys.maxsize
-else:
- string_types = basestring,
- integer_types = (int, long)
- class_types = (type, types.ClassType)
- text_type = unicode
- binary_type = str
-
- if sys.platform.startswith("java"):
- # Jython always uses 32 bits.
- MAXSIZE = int((1 << 31) - 1)
- else:
- # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
- class X(object):
-
- def __len__(self):
- return 1 << 31
- try:
- len(X())
- except OverflowError:
- # 32-bit
- MAXSIZE = int((1 << 31) - 1)
- else:
- # 64-bit
- MAXSIZE = int((1 << 63) - 1)
- del X
-
-
-def _add_doc(func, doc):
- """Add documentation to a function."""
- func.__doc__ = doc
-
-
-def _import_module(name):
- """Import module, returning the module after the last dot."""
- __import__(name)
- return sys.modules[name]
-
-
-class _LazyDescr(object):
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, obj, tp):
- result = self._resolve()
- setattr(obj, self.name, result) # Invokes __set__.
- try:
- # This is a bit ugly, but it avoids running this again by
- # removing this descriptor.
- delattr(obj.__class__, self.name)
- except AttributeError:
- pass
- return result
-
-
-class MovedModule(_LazyDescr):
-
- def __init__(self, name, old, new=None):
- super(MovedModule, self).__init__(name)
- if PY3:
- if new is None:
- new = name
- self.mod = new
- else:
- self.mod = old
-
- def _resolve(self):
- return _import_module(self.mod)
-
- def __getattr__(self, attr):
- _module = self._resolve()
- value = getattr(_module, attr)
- setattr(self, attr, value)
- return value
-
-
-class _LazyModule(types.ModuleType):
-
- def __init__(self, name):
- super(_LazyModule, self).__init__(name)
- self.__doc__ = self.__class__.__doc__
-
- def __dir__(self):
- attrs = ["__doc__", "__name__"]
- attrs += [attr.name for attr in self._moved_attributes]
- return attrs
-
- # Subclasses should override this
- _moved_attributes = []
-
-
-class MovedAttribute(_LazyDescr):
-
- def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
- super(MovedAttribute, self).__init__(name)
- if PY3:
- if new_mod is None:
- new_mod = name
- self.mod = new_mod
- if new_attr is None:
- if old_attr is None:
- new_attr = name
- else:
- new_attr = old_attr
- self.attr = new_attr
- else:
- self.mod = old_mod
- if old_attr is None:
- old_attr = name
- self.attr = old_attr
-
- def _resolve(self):
- module = _import_module(self.mod)
- return getattr(module, self.attr)
-
-
-class _SixMetaPathImporter(object):
-
- """
- A meta path importer to import six.moves and its submodules.
-
- This class implements a PEP302 finder and loader. It should be compatible
- with Python 2.5 and all existing versions of Python3
- """
-
- def __init__(self, six_module_name):
- self.name = six_module_name
- self.known_modules = {}
-
- def _add_module(self, mod, *fullnames):
- for fullname in fullnames:
- self.known_modules[self.name + "." + fullname] = mod
-
- def _get_module(self, fullname):
- return self.known_modules[self.name + "." + fullname]
-
- def find_module(self, fullname, path=None):
- if fullname in self.known_modules:
- return self
- return None
-
- def __get_module(self, fullname):
- try:
- return self.known_modules[fullname]
- except KeyError:
- raise ImportError("This loader does not know module " + fullname)
-
- def load_module(self, fullname):
- try:
- # in case of a reload
- return sys.modules[fullname]
- except KeyError:
- pass
- mod = self.__get_module(fullname)
- if isinstance(mod, MovedModule):
- mod = mod._resolve()
- else:
- mod.__loader__ = self
- sys.modules[fullname] = mod
- return mod
-
- def is_package(self, fullname):
- """
- Return true, if the named module is a package.
-
- We need this method to get correct spec objects with
- Python 3.4 (see PEP451)
- """
- return hasattr(self.__get_module(fullname), "__path__")
-
- def get_code(self, fullname):
- """Return None
-
- Required, if is_package is implemented"""
- self.__get_module(fullname) # eventually raises ImportError
- return None
- get_source = get_code # same as get_code
-
-_importer = _SixMetaPathImporter(__name__)
-
-
-class _MovedItems(_LazyModule):
-
- """Lazy loading of moved objects"""
- __path__ = [] # mark as package
-
-
-_moved_attributes = [
- MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
- MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
- MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
- MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
- MovedAttribute("intern", "__builtin__", "sys"),
- MovedAttribute("map", "itertools", "builtins", "imap", "map"),
- MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
- MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
- MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
- MovedAttribute("reduce", "__builtin__", "functools"),
- MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
- MovedAttribute("StringIO", "StringIO", "io"),
- MovedAttribute("UserDict", "UserDict", "collections"),
- MovedAttribute("UserList", "UserList", "collections"),
- MovedAttribute("UserString", "UserString", "collections"),
- MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
- MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
- MovedModule("builtins", "__builtin__"),
- MovedModule("configparser", "ConfigParser"),
- MovedModule("copyreg", "copy_reg"),
- MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
- MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
- MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
- MovedModule("http_cookies", "Cookie", "http.cookies"),
- MovedModule("html_entities", "htmlentitydefs", "html.entities"),
- MovedModule("html_parser", "HTMLParser", "html.parser"),
- MovedModule("http_client", "httplib", "http.client"),
- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
- MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
- MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
- MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
- MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
- MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
- MovedModule("cPickle", "cPickle", "pickle"),
- MovedModule("queue", "Queue"),
- MovedModule("reprlib", "repr"),
- MovedModule("socketserver", "SocketServer"),
- MovedModule("_thread", "thread", "_thread"),
- MovedModule("tkinter", "Tkinter"),
- MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
- MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
- MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
- MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
- MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
- MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
- MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
- MovedModule("tkinter_colorchooser", "tkColorChooser",
- "tkinter.colorchooser"),
- MovedModule("tkinter_commondialog", "tkCommonDialog",
- "tkinter.commondialog"),
- MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
- MovedModule("tkinter_font", "tkFont", "tkinter.font"),
- MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
- "tkinter.simpledialog"),
- MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
- MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
- MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
- MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
- MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
- MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
-]
-# Add windows specific modules.
-if sys.platform == "win32":
- _moved_attributes += [
- MovedModule("winreg", "_winreg"),
- ]
-
-for attr in _moved_attributes:
- setattr(_MovedItems, attr.name, attr)
- if isinstance(attr, MovedModule):
- _importer._add_module(attr, "moves." + attr.name)
-del attr
-
-_MovedItems._moved_attributes = _moved_attributes
-
-moves = _MovedItems(__name__ + ".moves")
-_importer._add_module(moves, "moves")
-
-
-class Module_six_moves_urllib_parse(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_parse"""
-
-
-_urllib_parse_moved_attributes = [
- MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
- MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
- MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
- MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
- MovedAttribute("urljoin", "urlparse", "urllib.parse"),
- MovedAttribute("urlparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
- MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
- MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
- MovedAttribute("quote", "urllib", "urllib.parse"),
- MovedAttribute("quote_plus", "urllib", "urllib.parse"),
- MovedAttribute("unquote", "urllib", "urllib.parse"),
- MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
- MovedAttribute("urlencode", "urllib", "urllib.parse"),
- MovedAttribute("splitquery", "urllib", "urllib.parse"),
- MovedAttribute("splittag", "urllib", "urllib.parse"),
- MovedAttribute("splituser", "urllib", "urllib.parse"),
- MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
- MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
- MovedAttribute("uses_params", "urlparse", "urllib.parse"),
- MovedAttribute("uses_query", "urlparse", "urllib.parse"),
- MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
-]
-for attr in _urllib_parse_moved_attributes:
- setattr(Module_six_moves_urllib_parse, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_parse(
- __name__ +
- ".moves.urllib_parse"),
- "moves.urllib_parse",
- "moves.urllib.parse")
-
-
-class Module_six_moves_urllib_error(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_error"""
-
-
-_urllib_error_moved_attributes = [
- MovedAttribute("URLError", "urllib2", "urllib.error"),
- MovedAttribute("HTTPError", "urllib2", "urllib.error"),
- MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
-]
-for attr in _urllib_error_moved_attributes:
- setattr(Module_six_moves_urllib_error, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_error(
- __name__ +
- ".moves.urllib.error"),
- "moves.urllib_error",
- "moves.urllib.error")
-
-
-class Module_six_moves_urllib_request(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_request"""
-
-
-_urllib_request_moved_attributes = [
- MovedAttribute("urlopen", "urllib2", "urllib.request"),
- MovedAttribute("install_opener", "urllib2", "urllib.request"),
- MovedAttribute("build_opener", "urllib2", "urllib.request"),
- MovedAttribute("pathname2url", "urllib", "urllib.request"),
- MovedAttribute("url2pathname", "urllib", "urllib.request"),
- MovedAttribute("getproxies", "urllib", "urllib.request"),
- MovedAttribute("Request", "urllib2", "urllib.request"),
- MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
- MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
- MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
- MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
- MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
- MovedAttribute("FileHandler", "urllib2", "urllib.request"),
- MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
- MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
- MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
- MovedAttribute("urlretrieve", "urllib", "urllib.request"),
- MovedAttribute("urlcleanup", "urllib", "urllib.request"),
- MovedAttribute("URLopener", "urllib", "urllib.request"),
- MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
- MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
-]
-for attr in _urllib_request_moved_attributes:
- setattr(Module_six_moves_urllib_request, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_request(
- __name__ +
- ".moves.urllib.request"),
- "moves.urllib_request",
- "moves.urllib.request")
-
-
-class Module_six_moves_urllib_response(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_response"""
-
-
-_urllib_response_moved_attributes = [
- MovedAttribute("addbase", "urllib", "urllib.response"),
- MovedAttribute("addclosehook", "urllib", "urllib.response"),
- MovedAttribute("addinfo", "urllib", "urllib.response"),
- MovedAttribute("addinfourl", "urllib", "urllib.response"),
-]
-for attr in _urllib_response_moved_attributes:
- setattr(Module_six_moves_urllib_response, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_response(
- __name__ +
- ".moves.urllib.response"),
- "moves.urllib_response",
- "moves.urllib.response")
-
-
-class Module_six_moves_urllib_robotparser(_LazyModule):
-
- """Lazy loading of moved objects in six.moves.urllib_robotparser"""
-
-
-_urllib_robotparser_moved_attributes = [
- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
-]
-for attr in _urllib_robotparser_moved_attributes:
- setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
-del attr
-
-Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
-
-_importer._add_module(
- Module_six_moves_urllib_robotparser(
- __name__ + ".moves.urllib.robotparser"),
- "moves.urllib_robotparser",
- "moves.urllib.robotparser")
-
-
-class Module_six_moves_urllib(types.ModuleType):
-
- """Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
- __path__ = [] # mark as package
- parse = _importer._get_module("moves.urllib_parse")
- error = _importer._get_module("moves.urllib_error")
- request = _importer._get_module("moves.urllib_request")
- response = _importer._get_module("moves.urllib_response")
- robotparser = _importer._get_module("moves.urllib_robotparser")
-
- def __dir__(self):
- return ['parse', 'error', 'request', 'response', 'robotparser']
-
-_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
- "moves.urllib")
-
-
-def add_move(move):
- """Add an item to six.moves."""
- setattr(_MovedItems, move.name, move)
-
-
-def remove_move(name):
- """Remove item from six.moves."""
- try:
- delattr(_MovedItems, name)
- except AttributeError:
- try:
- del moves.__dict__[name]
- except KeyError:
- raise AttributeError("no such move, %r" % (name,))
-
-
-if PY3:
- _meth_func = "__func__"
- _meth_self = "__self__"
-
- _func_closure = "__closure__"
- _func_code = "__code__"
- _func_defaults = "__defaults__"
- _func_globals = "__globals__"
-else:
- _meth_func = "im_func"
- _meth_self = "im_self"
-
- _func_closure = "func_closure"
- _func_code = "func_code"
- _func_defaults = "func_defaults"
- _func_globals = "func_globals"
-
-
-try:
- advance_iterator = next
-except NameError:
- def advance_iterator(it):
- return it.next()
-next = advance_iterator
-
-
-try:
- callable = callable
-except NameError:
- def callable(obj):
- return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
-
-
-if PY3:
- def get_unbound_function(unbound):
- return unbound
-
- create_bound_method = types.MethodType
-
- def create_unbound_method(func, cls):
- return func
-
- Iterator = object
-else:
- def get_unbound_function(unbound):
- return unbound.im_func
-
- def create_bound_method(func, obj):
- return types.MethodType(func, obj, obj.__class__)
-
- def create_unbound_method(func, cls):
- return types.MethodType(func, None, cls)
-
- class Iterator(object):
-
- def next(self):
- return type(self).__next__(self)
-
- callable = callable
-_add_doc(get_unbound_function,
- """Get the function out of a possibly unbound function""")
-
-
-get_method_function = operator.attrgetter(_meth_func)
-get_method_self = operator.attrgetter(_meth_self)
-get_function_closure = operator.attrgetter(_func_closure)
-get_function_code = operator.attrgetter(_func_code)
-get_function_defaults = operator.attrgetter(_func_defaults)
-get_function_globals = operator.attrgetter(_func_globals)
-
-
-if PY3:
- def iterkeys(d, **kw):
- return iter(d.keys(**kw))
-
- def itervalues(d, **kw):
- return iter(d.values(**kw))
-
- def iteritems(d, **kw):
- return iter(d.items(**kw))
-
- def iterlists(d, **kw):
- return iter(d.lists(**kw))
-
- viewkeys = operator.methodcaller("keys")
-
- viewvalues = operator.methodcaller("values")
-
- viewitems = operator.methodcaller("items")
-else:
- def iterkeys(d, **kw):
- return d.iterkeys(**kw)
-
- def itervalues(d, **kw):
- return d.itervalues(**kw)
-
- def iteritems(d, **kw):
- return d.iteritems(**kw)
-
- def iterlists(d, **kw):
- return d.iterlists(**kw)
-
- viewkeys = operator.methodcaller("viewkeys")
-
- viewvalues = operator.methodcaller("viewvalues")
-
- viewitems = operator.methodcaller("viewitems")
-
-_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
-_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
-_add_doc(iteritems,
- "Return an iterator over the (key, value) pairs of a dictionary.")
-_add_doc(iterlists,
- "Return an iterator over the (key, [values]) pairs of a dictionary.")
-
-
-if PY3:
- def b(s):
- return s.encode("latin-1")
-
- def u(s):
- return s
- unichr = chr
- import struct
- int2byte = struct.Struct(">B").pack
- del struct
- byte2int = operator.itemgetter(0)
- indexbytes = operator.getitem
- iterbytes = iter
- import io
- StringIO = io.StringIO
- BytesIO = io.BytesIO
- _assertCountEqual = "assertCountEqual"
- if sys.version_info[1] <= 1:
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
- else:
- _assertRaisesRegex = "assertRaisesRegex"
- _assertRegex = "assertRegex"
-else:
- def b(s):
- return s
- # Workaround for standalone backslash
-
- def u(s):
- return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
- unichr = unichr
- int2byte = chr
-
- def byte2int(bs):
- return ord(bs[0])
-
- def indexbytes(buf, i):
- return ord(buf[i])
- iterbytes = functools.partial(itertools.imap, ord)
- import StringIO
- StringIO = BytesIO = StringIO.StringIO
- _assertCountEqual = "assertItemsEqual"
- _assertRaisesRegex = "assertRaisesRegexp"
- _assertRegex = "assertRegexpMatches"
-_add_doc(b, """Byte literal""")
-_add_doc(u, """Text literal""")
-
-
-def assertCountEqual(self, *args, **kwargs):
- return getattr(self, _assertCountEqual)(*args, **kwargs)
-
-
-def assertRaisesRegex(self, *args, **kwargs):
- return getattr(self, _assertRaisesRegex)(*args, **kwargs)
-
-
-def assertRegex(self, *args, **kwargs):
- return getattr(self, _assertRegex)(*args, **kwargs)
-
-
-if PY3:
- exec_ = getattr(moves.builtins, "exec")
-
- def reraise(tp, value, tb=None):
- if value is None:
- value = tp()
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-
-else:
- def exec_(_code_, _globs_=None, _locs_=None):
- """Execute code in a namespace."""
- if _globs_ is None:
- frame = sys._getframe(1)
- _globs_ = frame.f_globals
- if _locs_ is None:
- _locs_ = frame.f_locals
- del frame
- elif _locs_ is None:
- _locs_ = _globs_
- exec("""exec _code_ in _globs_, _locs_""")
-
- exec_("""def reraise(tp, value, tb=None):
- raise tp, value, tb
-""")
-
-
-if sys.version_info[:2] == (3, 2):
- exec_("""def raise_from(value, from_value):
- if from_value is None:
- raise value
- raise value from from_value
-""")
-elif sys.version_info[:2] > (3, 2):
- exec_("""def raise_from(value, from_value):
- raise value from from_value
-""")
-else:
- def raise_from(value, from_value):
- raise value
-
-
-print_ = getattr(moves.builtins, "print", None)
-if print_ is None:
- def print_(*args, **kwargs):
- """The new-style print function for Python 2.4 and 2.5."""
- fp = kwargs.pop("file", sys.stdout)
- if fp is None:
- return
-
- def write(data):
- if not isinstance(data, basestring):
- data = str(data)
- # If the file has an encoding, encode unicode with it.
- if (isinstance(fp, file) and
- isinstance(data, unicode) and
- fp.encoding is not None):
- errors = getattr(fp, "errors", None)
- if errors is None:
- errors = "strict"
- data = data.encode(fp.encoding, errors)
- fp.write(data)
- want_unicode = False
- sep = kwargs.pop("sep", None)
- if sep is not None:
- if isinstance(sep, unicode):
- want_unicode = True
- elif not isinstance(sep, str):
- raise TypeError("sep must be None or a string")
- end = kwargs.pop("end", None)
- if end is not None:
- if isinstance(end, unicode):
- want_unicode = True
- elif not isinstance(end, str):
- raise TypeError("end must be None or a string")
- if kwargs:
- raise TypeError("invalid keyword arguments to print()")
- if not want_unicode:
- for arg in args:
- if isinstance(arg, unicode):
- want_unicode = True
- break
- if want_unicode:
- newline = unicode("\n")
- space = unicode(" ")
- else:
- newline = "\n"
- space = " "
- if sep is None:
- sep = space
- if end is None:
- end = newline
- for i, arg in enumerate(args):
- if i:
- write(sep)
- write(arg)
- write(end)
-if sys.version_info[:2] < (3, 3):
- _print = print_
-
- def print_(*args, **kwargs):
- fp = kwargs.get("file", sys.stdout)
- flush = kwargs.pop("flush", False)
- _print(*args, **kwargs)
- if flush and fp is not None:
- fp.flush()
-
-_add_doc(reraise, """Reraise an exception.""")
-
-if sys.version_info[0:2] < (3, 4):
- def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES):
- def wrapper(f):
- f = functools.wraps(wrapped, assigned, updated)(f)
- f.__wrapped__ = wrapped
- return f
- return wrapper
-else:
- wraps = functools.wraps
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a dummy
- # metaclass for one level of class instantiation that replaces itself with
- # the actual metaclass.
- class metaclass(meta):
-
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
-
-
-def add_metaclass(metaclass):
- """Class decorator for creating a class with a metaclass."""
- def wrapper(cls):
- orig_vars = cls.__dict__.copy()
- slots = orig_vars.get('__slots__')
- if slots is not None:
- if isinstance(slots, str):
- slots = [slots]
- for slots_var in slots:
- orig_vars.pop(slots_var)
- orig_vars.pop('__dict__', None)
- orig_vars.pop('__weakref__', None)
- return metaclass(cls.__name__, cls.__bases__, orig_vars)
- return wrapper
-
-
-def python_2_unicode_compatible(klass):
- """
- A decorator that defines __unicode__ and __str__ methods under Python 2.
- Under Python 3 it does nothing.
-
- To support Python 2 and 3 with a single code base, define a __str__ method
- returning text and apply this decorator to the class.
- """
- if PY2:
- if '__str__' not in klass.__dict__:
- raise ValueError("@python_2_unicode_compatible cannot be applied "
- "to %s because it doesn't define __str__()." %
- klass.__name__)
- klass.__unicode__ = klass.__str__
- klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
- return klass
-
-
-# Complete the moves implementation.
-# This code is at the end of this module to speed up module loading.
-# Turn this module into a package.
-__path__ = [] # required for PEP 302 and PEP 451
-__package__ = __name__ # see PEP 366 @ReservedAssignment
-if globals().get("__spec__") is not None:
- __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
-# Remove other six meta path importers, since they cause problems. This can
-# happen if six is removed from sys.modules and then reloaded. (Setuptools does
-# this for some reason.)
-if sys.meta_path:
- for i, importer in enumerate(sys.meta_path):
- # Here's some real nastiness: Another "instance" of the six module might
- # be floating around. Therefore, we can't use isinstance() to check for
- # the six meta path importer, since the other six instance will have
- # inserted an importer with different class.
- if (type(importer).__name__ == "_SixMetaPathImporter" and
- importer.name == __name__):
- del sys.meta_path[i]
- break
- del i, importer
-# Finally, add the importer to the meta path import hook.
-sys.meta_path.append(_importer)
# i.e. if a target requires it as dependency. The typical
# example is `check-lldb`. So, we pass EXCLUDE_FROM_ALL here.
add_subdirectory(lldb-test EXCLUDE_FROM_ALL)
+add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL)
#add_lldb_tool_subdirectory(lldb-instr)
add_lldb_tool_subdirectory(lldb-vscode)
#include "lldb/API/SBFile.h"
#include "lldb/API/SBHostOS.h"
#include "lldb/API/SBLanguageRuntime.h"
-#include "lldb/API/SBReproducer.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBStructuredData.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <fcntl.h>
-// Includes for pipe()
-#if defined(_WIN32)
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
#if !defined(__APPLE__)
#include "llvm/Support/DataTypes.h"
#endif
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "Options.inc"
#undef PREFIX
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
#undef OPTION
};
-class LLDBOptTable : public opt::OptTable {
+class LLDBOptTable : public opt::GenericOptTable {
public:
- LLDBOptTable() : OptTable(InfoTable) {}
+ LLDBOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace
static bool g_old_stdin_termios_is_valid = false;
static struct termios g_old_stdin_termios;
+static bool disable_color(const raw_ostream &OS) { return false; }
+
static Driver *g_driver = nullptr;
// In the Driver::MainLoop, we change the terminal settings. This function is
m_debugger.SkipLLDBInitFiles(false);
m_debugger.SkipAppInitFiles(false);
+ if (args.hasArg(OPT_no_use_colors)) {
+ m_debugger.SetUseColor(false);
+ WithColor::setAutoDetectFunction(disable_color);
+ m_option_data.m_debug_mode = true;
+ }
+
if (args.hasArg(OPT_version)) {
m_option_data.m_print_version = true;
}
if (args.hasArg(OPT_python_path)) {
m_option_data.m_print_python_path = true;
}
+ if (args.hasArg(OPT_print_script_interpreter_info)) {
+ m_option_data.m_print_script_interpreter_info = true;
+ }
if (args.hasArg(OPT_batch)) {
m_option_data.m_batch = true;
m_debugger.GetInstanceName());
}
- if (args.hasArg(OPT_no_use_colors)) {
- m_debugger.SetUseColor(false);
- m_option_data.m_debug_mode = true;
- }
-
if (auto *arg = args.getLastArg(OPT_file)) {
auto arg_value = arg->getValue();
SBFileSpec file(arg_value);
arg_value);
return error;
}
+ m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
}
if (args.hasArg(OPT_repl)) {
return error;
}
- return error;
-}
-
-static inline int OpenPipe(int fds[2], std::size_t size) {
-#ifdef _WIN32
- return _pipe(fds, size, O_BINARY);
-#else
- (void)size;
- return pipe(fds);
-#endif
-}
-
-static ::FILE *PrepareCommandsForSourcing(const char *commands_data,
- size_t commands_size) {
- enum PIPES { READ, WRITE }; // Indexes for the read and write fds
- int fds[2] = {-1, -1};
-
- if (OpenPipe(fds, commands_size) != 0) {
- WithColor::error()
- << "can't create pipe file descriptors for LLDB commands\n";
- return nullptr;
- }
-
- ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
- if (size_t(nrwr) != commands_size) {
- WithColor::error()
- << format(
- "write(%i, %p, %" PRIu64
- ") failed (errno = %i) when trying to open LLDB commands pipe",
- fds[WRITE], static_cast<const void *>(commands_data),
- static_cast<uint64_t>(commands_size), errno)
- << '\n';
- llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
- llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
- return nullptr;
- }
-
- // Close the write end of the pipe, so that the command interpreter will exit
- // when it consumes all the data.
- llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
-
- // Open the read file descriptor as a FILE * that we can return as an input
- // handle.
- ::FILE *commands_file = fdopen(fds[READ], "rb");
- if (commands_file == nullptr) {
- WithColor::error() << format("fdopen(%i, \"rb\") failed (errno = %i) "
- "when trying to open LLDB commands pipe",
- fds[READ], errno)
- << '\n';
- llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
- return nullptr;
+ if (m_option_data.m_print_script_interpreter_info) {
+ SBStructuredData info =
+ m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
+ if (!info) {
+ error.SetErrorString("no script interpreter.");
+ } else {
+ SBStream stream;
+ error = info.GetAsJSON(stream);
+ if (error.Success()) {
+ llvm::outs() << stream.GetData() << '\n';
+ }
+ }
+ exiting = true;
+ return error;
}
- // 'commands_file' now owns the read descriptor.
- return commands_file;
+ return error;
}
std::string EscapeString(std::string arg) {
SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
- // Before we handle any options from the command line, we parse the
- // REPL init file or the default file in the user's home directory.
+ // Process lldbinit files before handling any options from the command line.
SBCommandReturnObject result;
+ sb_interpreter.SourceInitFileInGlobalDirectory(result);
+ if (m_option_data.m_debug_mode) {
+ result.PutError(m_debugger.GetErrorFile());
+ result.PutOutput(m_debugger.GetOutputFile());
+ }
+
sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
if (m_option_data.m_debug_mode) {
result.PutError(m_debugger.GetErrorFile());
// Check if we have any data in the commands stream, and if so, save it to a
// temp file
// so we can then run the command interpreter using the file contents.
- const char *commands_data = commands_stream.GetData();
- const size_t commands_size = commands_stream.GetSize();
-
bool go_interactive = true;
- if ((commands_data != nullptr) && (commands_size != 0u)) {
- FILE *commands_file =
- PrepareCommandsForSourcing(commands_data, commands_size);
-
- if (commands_file == nullptr) {
- // We should have already printed an error in PrepareCommandsForSourcing.
+ if ((commands_stream.GetData() != nullptr) &&
+ (commands_stream.GetSize() != 0u)) {
+ SBError error = m_debugger.SetInputString(commands_stream.GetData());
+ if (error.Fail()) {
+ WithColor::error() << error.GetCString() << '\n';
return 1;
}
- m_debugger.SetInputFileHandle(commands_file, true);
-
// Set the debugger into Sync mode when running the command file. Otherwise
// command files that run the target won't run in a sensible way.
bool old_async = m_debugger.GetAsync();
options.SetSpawnThread(false);
options.SetStopOnError(true);
options.SetStopOnCrash(m_option_data.m_batch);
+ options.SetEchoCommands(!m_option_data.m_source_quietly);
SBCommandInterpreterRunResult results =
m_debugger.RunCommandInterpreter(options);
SBStream crash_commands_stream;
WriteCommandsForSourcing(eCommandPlacementAfterCrash,
crash_commands_stream);
- const char *crash_commands_data = crash_commands_stream.GetData();
- const size_t crash_commands_size = crash_commands_stream.GetSize();
- commands_file =
- PrepareCommandsForSourcing(crash_commands_data, crash_commands_size);
- if (commands_file != nullptr) {
- m_debugger.SetInputFileHandle(commands_file, true);
+ SBError error =
+ m_debugger.SetInputString(crash_commands_stream.GetData());
+ if (error.Success()) {
SBCommandInterpreterRunResult local_results =
m_debugger.RunCommandInterpreter(options);
if (local_results.GetResult() ==
_exit(signo);
}
-void sigtstp_handler(int signo) {
+#ifndef _WIN32
+static void sigtstp_handler(int signo) {
if (g_driver != nullptr)
g_driver->GetDebugger().SaveInputTerminalState();
+ // Unblock the signal and remove our handler.
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signo);
+ pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
signal(signo, SIG_DFL);
- kill(getpid(), signo);
+
+ // Now re-raise the signal. We will immediately suspend...
+ raise(signo);
+ // ... and resume after a SIGCONT.
+
+ // Now undo the modifications.
+ pthread_sigmask(SIG_BLOCK, &set, nullptr);
signal(signo, sigtstp_handler);
-}
-void sigcont_handler(int signo) {
if (g_driver != nullptr)
g_driver->GetDebugger().RestoreInputTerminalState();
-
- signal(signo, SIG_DFL);
- kill(getpid(), signo);
- signal(signo, sigcont_handler);
-}
-
-void reproducer_handler(void *finalize_cmd) {
- if (SBReproducer::Generate()) {
- int result = std::system(static_cast<const char *>(finalize_cmd));
- (void)result;
- fflush(stdout);
- }
}
+#endif
static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
std::string usage_str = tool_name.str() + " [options]";
llvm::outs() << examples << '\n';
}
-static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
- opt::InputArgList &input_args) {
- if (auto *finalize_path = input_args.getLastArg(OPT_reproducer_finalize)) {
- if (const char *error = SBReproducer::Finalize(finalize_path->getValue())) {
- WithColor::error() << "reproducer finalization failed: " << error << '\n';
- return 1;
- }
-
- llvm::outs() << "********************\n";
- llvm::outs() << "Crash reproducer for ";
- llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
- llvm::outs() << '\n';
- llvm::outs() << "Reproducer written to '" << SBReproducer::GetPath()
- << "'\n";
- llvm::outs() << '\n';
- llvm::outs() << "Before attaching the reproducer to a bug report:\n";
- llvm::outs() << " - Look at the directory to ensure you're willing to "
- "share its content.\n";
- llvm::outs()
- << " - Make sure the reproducer works by replaying the reproducer.\n";
- llvm::outs() << '\n';
- llvm::outs() << "Replay the reproducer with the following command:\n";
- llvm::outs() << argv0 << " -replay " << finalize_path->getValue() << "\n";
- llvm::outs() << "********************\n";
- return 0;
- }
-
- if (auto *replay_path = input_args.getLastArg(OPT_replay)) {
- SBReplayOptions replay_options;
- replay_options.SetCheckVersion(!input_args.hasArg(OPT_no_version_check));
- replay_options.SetVerify(!input_args.hasArg(OPT_no_verification));
- if (const char *error =
- SBReproducer::Replay(replay_path->getValue(), replay_options)) {
- WithColor::error() << "reproducer replay failed: " << error << '\n';
- return 1;
- }
- return 0;
- }
-
- bool capture = input_args.hasArg(OPT_capture);
- bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
- auto *capture_path = input_args.getLastArg(OPT_capture_path);
-
- if (generate_on_exit && !capture) {
- WithColor::warning()
- << "-reproducer-generate-on-exit specified without -capture\n";
- }
-
- if (capture || capture_path) {
- if (capture_path) {
- if (!capture)
- WithColor::warning() << "-capture-path specified without -capture\n";
- if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
- WithColor::error() << "reproducer capture failed: " << error << '\n';
- return 1;
- }
- } else {
- const char *error = SBReproducer::Capture();
- if (error) {
- WithColor::error() << "reproducer capture failed: " << error << '\n';
- return 1;
- }
- }
- if (generate_on_exit)
- SBReproducer::SetAutoGenerate(true);
-
- // Register the reproducer signal handler.
- if (!input_args.hasArg(OPT_no_generate_on_signal)) {
- if (const char *reproducer_path = SBReproducer::GetPath()) {
- static std::string *finalize_cmd = new std::string(argv0);
- finalize_cmd->append(" --reproducer-finalize '");
- finalize_cmd->append(reproducer_path);
- finalize_cmd->append("'");
- llvm::sys::AddSignalHandler(reproducer_handler,
- const_cast<char *>(finalize_cmd->c_str()));
- }
- }
- }
-
- return llvm::None;
-}
-
int main(int argc, char const *argv[]) {
// Editline uses for example iswprint which is dependent on LC_CTYPE.
std::setlocale(LC_ALL, "");
LLDBOptTable T;
unsigned MissingArgIndex;
unsigned MissingArgCount;
- ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
+ ArrayRef<const char *> arg_arr = ArrayRef(argv + 1, argc - 1);
opt::InputArgList input_args =
T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
return 1;
}
- if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
- return *exit_code;
- }
-
SBError error = SBDebugger::InitializeWithErrorHandling();
if (error.Fail()) {
WithColor::error() << "initialization failed: " << error.GetCString()
<< '\n';
return 1;
}
+
+ // Setup LLDB signal handlers once the debugger has been initialized.
+ SBDebugger::PrintDiagnosticsOnError();
+
SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
signal(SIGINT, sigint_handler);
-#if !defined(_MSC_VER)
+#if !defined(_WIN32)
signal(SIGPIPE, SIG_IGN);
signal(SIGWINCH, sigwinch_handler);
signal(SIGTSTP, sigtstp_handler);
- signal(SIGCONT, sigcont_handler);
#endif
int exit_code = 0;
SystemInitializerLLGS.cpp
LINK_LIBS
- lldbBase
lldbHost
lldbInitialization
+ lldbVersion
${LLDB_PLUGINS}
lldbPluginInstructionARM
+ lldbPluginInstructionLoongArch
lldbPluginInstructionMIPS
lldbPluginInstructionMIPS64
+ lldbPluginInstructionRISCV
${LLDB_SYSTEM_LIBS}
LINK_COMPONENTS
#include <unistd.h>
#endif
-#include "Acceptor.h"
#include "LLDBServerUtilities.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Socket.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Target/Process.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Status.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/ArgList.h"
static void sighup_handler(MainLoopBase &mainloop) {
++g_sighup_received_count;
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Log *log = GetLog(LLDBLog::Process);
LLDB_LOGF(log, "lldb-server:%s swallowing SIGHUP (receive count=%d)",
__FUNCTION__, g_sighup_received_count);
}
}
-Status writeSocketIdToPipe(Pipe &port_pipe, const std::string &socket_id) {
+Status writeSocketIdToPipe(Pipe &port_pipe, llvm::StringRef socket_id) {
size_t bytes_written = 0;
// Write the port number as a C string with the NULL terminator.
- return port_pipe.Write(socket_id.c_str(), socket_id.size() + 1,
- bytes_written);
+ return port_pipe.Write(socket_id.data(), socket_id.size() + 1, bytes_written);
}
Status writeSocketIdToPipe(const char *const named_pipe_path,
- const std::string &socket_id) {
+ llvm::StringRef socket_id) {
Pipe port_name_pipe;
// Wait for 10 seconds for pipe to be opened.
auto error = port_name_pipe.OpenAsWriterWithTimeout(named_pipe_path, false,
}
Status writeSocketIdToPipe(lldb::pipe_t unnamed_pipe,
- const std::string &socket_id) {
+ llvm::StringRef socket_id) {
Pipe port_pipe{LLDB_INVALID_PIPE, unnamed_pipe};
return writeSocketIdToPipe(port_pipe, socket_id);
}
Status error;
std::unique_ptr<Connection> connection_up;
+ std::string url;
+
if (connection_fd != -1) {
- // Build the connection string.
- char connection_url[512];
- snprintf(connection_url, sizeof(connection_url), "fd://%d", connection_fd);
+ url = llvm::formatv("fd://{0}", connection_fd).str();
// Create the connection.
#if LLDB_ENABLE_POSIX && !defined _WIN32
::fcntl(connection_fd, F_SETFD, FD_CLOEXEC);
#endif
- connection_up.reset(new ConnectionFileDescriptor);
- auto connection_result = connection_up->Connect(connection_url, &error);
- if (connection_result != eConnectionStatusSuccess) {
- fprintf(stderr, "error: failed to connect to client at '%s' "
- "(connection status: %d)\n",
- connection_url, static_cast<int>(connection_result));
- exit(-1);
- }
- if (error.Fail()) {
- fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
- connection_url, error.AsCString());
- exit(-1);
- }
} else if (!host_and_port.empty()) {
- // Parse out host and port.
- std::string final_host_and_port;
- std::string connection_host;
- std::string connection_port;
- uint32_t connection_portno = 0;
-
- // If host_and_port starts with ':', default the host to be "localhost" and
- // expect the remainder to be the port.
- if (host_and_port[0] == ':')
- final_host_and_port.append("localhost");
- final_host_and_port.append(host_and_port.str());
-
- // Note: use rfind, because the host/port may look like "[::1]:12345".
- const std::string::size_type colon_pos = final_host_and_port.rfind(':');
- if (colon_pos != std::string::npos) {
- connection_host = final_host_and_port.substr(0, colon_pos);
- connection_port = final_host_and_port.substr(colon_pos + 1);
- connection_portno = StringConvert::ToUInt32(connection_port.c_str(), 0);
+ llvm::Expected<std::string> url_exp =
+ LLGSArgToURL(host_and_port, reverse_connect);
+ if (!url_exp) {
+ llvm::errs() << llvm::formatv("error: invalid host:port or URL '{0}': "
+ "{1}\n",
+ host_and_port,
+ llvm::toString(url_exp.takeError()));
+ exit(-1);
}
+ url = std::move(url_exp.get());
+ }
- if (reverse_connect) {
- // llgs will connect to the gdb-remote client.
-
- // Ensure we have a port number for the connection.
- if (connection_portno == 0) {
- fprintf(stderr, "error: port number must be specified on when using "
- "reverse connect\n");
- exit(1);
- }
-
- // Build the connection string.
- char connection_url[512];
- snprintf(connection_url, sizeof(connection_url), "connect://%s",
- final_host_and_port.c_str());
-
- // Create the connection.
- connection_up.reset(new ConnectionFileDescriptor);
- auto connection_result = connection_up->Connect(connection_url, &error);
- if (connection_result != eConnectionStatusSuccess) {
- fprintf(stderr, "error: failed to connect to client at '%s' "
- "(connection status: %d)\n",
- connection_url, static_cast<int>(connection_result));
- exit(-1);
- }
- if (error.Fail()) {
- fprintf(stderr, "error: failed to connect to client at '%s': %s\n",
- connection_url, error.AsCString());
- exit(-1);
- }
- } else {
- std::unique_ptr<Acceptor> acceptor_up(
- Acceptor::Create(final_host_and_port, false, error));
- if (error.Fail()) {
- fprintf(stderr, "failed to create acceptor: %s\n", error.AsCString());
- exit(1);
- }
- error = acceptor_up->Listen(1);
- if (error.Fail()) {
- fprintf(stderr, "failed to listen: %s\n", error.AsCString());
- exit(1);
- }
- const std::string socket_id = acceptor_up->GetLocalSocketId();
- if (!socket_id.empty()) {
- // If we have a named pipe to write the socket id back to, do that now.
- if (named_pipe_path && named_pipe_path[0]) {
- error = writeSocketIdToPipe(named_pipe_path, socket_id);
- if (error.Fail())
- fprintf(stderr, "failed to write to the named pipe \'%s\': %s\n",
- named_pipe_path, error.AsCString());
- }
- // If we have an unnamed pipe to write the socket id back to, do that
- // now.
- else if (unnamed_pipe != LLDB_INVALID_PIPE) {
- error = writeSocketIdToPipe(unnamed_pipe, socket_id);
- if (error.Fail())
- fprintf(stderr, "failed to write to the unnamed pipe: %s\n",
- error.AsCString());
- }
- } else {
- fprintf(stderr,
- "unable to get the socket id for the listening connection\n");
- }
+ if (!url.empty()) {
+ // Create the connection or server.
+ std::unique_ptr<ConnectionFileDescriptor> conn_fd_up{
+ new ConnectionFileDescriptor};
+ auto connection_result = conn_fd_up->Connect(
+ url,
+ [named_pipe_path, unnamed_pipe](llvm::StringRef socket_id) {
+ // If we have a named pipe to write the socket id back to, do that
+ // now.
+ if (named_pipe_path && named_pipe_path[0]) {
+ Status error = writeSocketIdToPipe(named_pipe_path, socket_id);
+ if (error.Fail())
+ llvm::errs() << llvm::formatv(
+ "failed to write to the named peipe '{0}': {1}\n",
+ named_pipe_path, error.AsCString());
+ }
+ // If we have an unnamed pipe to write the socket id back to, do
+ // that now.
+ else if (unnamed_pipe != LLDB_INVALID_PIPE) {
+ Status error = writeSocketIdToPipe(unnamed_pipe, socket_id);
+ if (error.Fail())
+ llvm::errs() << llvm::formatv(
+ "failed to write to the unnamed pipe: {0}\n", error);
+ }
+ },
+ &error);
- Connection *conn = nullptr;
- error = acceptor_up->Accept(false, conn);
- if (error.Fail()) {
- printf("failed to accept new connection: %s\n", error.AsCString());
- exit(1);
- }
- connection_up.reset(conn);
+ if (error.Fail()) {
+ llvm::errs() << llvm::formatv(
+ "error: failed to connect to client at '{0}': {1}\n", url, error);
+ exit(-1);
+ }
+ if (connection_result != eConnectionStatusSuccess) {
+ llvm::errs() << llvm::formatv(
+ "error: failed to connect to client at '{0}' "
+ "(connection status: {1})\n",
+ url, static_cast<int>(connection_result));
+ exit(-1);
}
+ connection_up = std::move(conn_fd_up);
}
error = gdb_server.InitializeConnection(std::move(connection_up));
if (error.Fail()) {
- fprintf(stderr, "Failed to initialize connection: %s\n",
- error.AsCString());
+ llvm::errs() << llvm::formatv("failed to initialize connection\n", error);
exit(-1);
}
- printf("Connection established.\n");
+ llvm::outs() << "Connection established.\n";
}
namespace {
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define PREFIX(NAME, VALUE) \
+ constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
#include "LLGSOptions.inc"
#undef PREFIX
-const opt::OptTable::Info InfoTable[] = {
+static constexpr opt::OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ \
#undef OPTION
};
-class LLGSOptTable : public opt::OptTable {
+class LLGSOptTable : public opt::GenericOptTable {
public:
- LLGSOptTable() : OptTable(InfoTable) {}
+ LLGSOptTable() : opt::GenericOptTable(InfoTable) {}
void PrintHelp(llvm::StringRef Name) {
std::string Usage =
+++ /dev/null
-add_lldb_unittest(APITests
- SBCommandInterpreterTest.cpp
- SBStructuredDataTest.cpp
-
- LINK_LIBS
- liblldb
- )
-
-if(Python3_RPATH)
- set_property(TARGET APITests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}")
-endif()
+++ /dev/null
-//===-- SBCommandInterpreterTest.cpp ------------------------===----------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===/
-
-#include "gtest/gtest.h"
-
-#include "lldb/API/SBCommandInterpreter.h"
-#include "lldb/API/SBCommandReturnObject.h"
-#include "lldb/API/SBDebugger.h"
-
-#include <cstring>
-#include <string>
-
-using namespace lldb;
-
-class SBCommandInterpreterTest : public testing::Test {
-protected:
- void SetUp() override {
- SBDebugger::Initialize();
- m_dbg = SBDebugger::Create(/*source_init_files=*/false);
- m_interp = m_dbg.GetCommandInterpreter();
- }
-
- SBDebugger m_dbg;
- SBCommandInterpreter m_interp;
-};
-
-class DummyCommand : public SBCommandPluginInterface {
-public:
- DummyCommand(const char *message) : m_message(message) {}
-
- bool DoExecute(SBDebugger dbg, char **command,
- SBCommandReturnObject &result) {
- result.PutCString(m_message.c_str());
- result.SetStatus(eReturnStatusSuccessFinishResult);
- return result.Succeeded();
- }
-
-private:
- std::string m_message;
-};
-
-TEST_F(SBCommandInterpreterTest, SingleWordCommand) {
- // We first test a command without autorepeat
- DummyCommand dummy("It worked");
- m_interp.AddCommand("dummy", &dummy, /*help=*/nullptr);
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("dummy", result, /*add_to_history=*/true);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked\n");
- }
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("", result);
- EXPECT_FALSE(result.Succeeded());
- EXPECT_STREQ(result.GetError(), "error: No auto repeat.\n");
- }
-
- // Now we test a command with autorepeat
- m_interp.AddCommand("dummy_with_autorepeat", &dummy, /*help=*/nullptr,
- /*syntax=*/nullptr, /*auto_repeat_command=*/nullptr);
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("dummy_with_autorepeat", result,
- /*add_to_history=*/true);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked\n");
- }
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("", result);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked\n");
- }
-}
-
-TEST_F(SBCommandInterpreterTest, MultiWordCommand) {
- auto command = m_interp.AddMultiwordCommand("multicommand", /*help=*/nullptr);
- // We first test a subcommand without autorepeat
- DummyCommand subcommand("It worked again");
- command.AddCommand("subcommand", &subcommand, /*help=*/nullptr);
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("multicommand subcommand", result,
- /*add_to_history=*/true);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked again\n");
- }
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("", result);
- EXPECT_FALSE(result.Succeeded());
- EXPECT_STREQ(result.GetError(), "error: No auto repeat.\n");
- }
-
- // We first test a subcommand with autorepeat
- command.AddCommand("subcommand_with_autorepeat", &subcommand,
- /*help=*/nullptr, /*syntax=*/nullptr,
- /*auto_repeat_command=*/nullptr);
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("multicommand subcommand_with_autorepeat", result,
- /*add_to_history=*/true);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked again\n");
- }
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("", result);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked again\n");
- }
-
- DummyCommand subcommand2("It worked again 2");
- // We now test a subcommand with autorepeat of the command name
- command.AddCommand(
- "subcommand_with_custom_autorepeat", &subcommand2, /*help=*/nullptr,
- /*syntax=*/nullptr,
- /*auto_repeat_command=*/"multicommand subcommand_with_autorepeat");
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("multicommand subcommand_with_custom_autorepeat",
- result, /*add_to_history=*/true);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked again 2\n");
- }
- {
- SBCommandReturnObject result;
- m_interp.HandleCommand("", result);
- EXPECT_TRUE(result.Succeeded());
- EXPECT_STREQ(result.GetOutput(), "It worked again\n");
- }
-}
+++ /dev/null
-//===-- SBStructuredDataTest.cpp ------------------------===----------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===/
-
-#include "gtest/gtest.h"
-
-#include "lldb/API/SBStringList.h"
-#include "lldb/API/SBStructuredData.h"
-
-#include <cstring>
-#include <string>
-
-using namespace lldb;
-
-class SBStructuredDataTest : public testing::Test {};
-
-TEST_F(SBStructuredDataTest, NullImpl) {
- SBStructuredData data(nullptr);
- EXPECT_EQ(data.GetType(), eStructuredDataTypeInvalid);
- EXPECT_EQ(data.GetSize(), 0ul);
- SBStringList keys;
- EXPECT_FALSE(data.GetKeys(keys));
- EXPECT_EQ(data.GetValueForKey("key").GetType(), eStructuredDataTypeInvalid);
- EXPECT_EQ(data.GetItemAtIndex(0).GetType(), eStructuredDataTypeInvalid);
- EXPECT_EQ(data.GetIntegerValue(UINT64_MAX), UINT64_MAX);
- EXPECT_EQ(data.GetFloatValue(DBL_MAX), DBL_MAX);
- EXPECT_TRUE(data.GetBooleanValue(true));
- EXPECT_FALSE(data.GetBooleanValue(false));
- char dst[1];
- EXPECT_EQ(data.GetStringValue(dst, sizeof(dst)), 0ul);
-}
+++ /dev/null
-//===-- BreakpointIDTest.cpp ----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Breakpoint/BreakpointID.h"
-#include "lldb/Utility/Status.h"
-
-#include "llvm/ADT/StringRef.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(BreakpointIDTest, StringIsBreakpointName) {
- Status E;
- EXPECT_FALSE(BreakpointID::StringIsBreakpointName("1breakpoint", E));
- EXPECT_FALSE(BreakpointID::StringIsBreakpointName("-", E));
- EXPECT_FALSE(BreakpointID::StringIsBreakpointName("", E));
- EXPECT_FALSE(BreakpointID::StringIsBreakpointName("3.4", E));
-
- EXPECT_TRUE(BreakpointID::StringIsBreakpointName("_", E));
- EXPECT_TRUE(BreakpointID::StringIsBreakpointName("a123", E));
- EXPECT_TRUE(BreakpointID::StringIsBreakpointName("test", E));
-}
+++ /dev/null
-add_lldb_unittest(LLDBBreakpointTests\r
- BreakpointIDTest.cpp\r
-\r
- LINK_LIBS\r
- lldbBreakpoint\r
- lldbCore\r
- LINK_COMPONENTS\r
- Support\r
- )\r
+++ /dev/null
-add_custom_target(LLDBUnitTests)
-set_target_properties(LLDBUnitTests PROPERTIES FOLDER "lldb tests")
-
-add_dependencies(lldb-unit-test-deps LLDBUnitTests)
-
-include_directories(${LLDB_SOURCE_ROOT})
-include_directories(${LLDB_PROJECT_ROOT}/unittests)
-
-if (CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG)
- add_compile_options("-Wno-suggest-override")
-endif()
-
-set(LLDB_GTEST_COMMON_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/gtest_common.h)
-if (MSVC)
- list(APPEND LLVM_COMPILE_FLAGS /FI ${LLDB_GTEST_COMMON_INCLUDE})
-else ()
- list(APPEND LLVM_COMPILE_FLAGS -include ${LLDB_GTEST_COMMON_INCLUDE})
-endif ()
-
-if (LLDB_BUILT_STANDALONE)
- # Build the gtest library needed for unittests, if we have LLVM sources
- # handy.
- if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/unittest AND NOT TARGET gtest)
- add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/unittest utils/unittest)
- endif()
- # LLVMTestingSupport library is needed for Process/gdb-remote.
- if (EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Testing/Support
- AND NOT TARGET LLVMTestingSupport)
- add_subdirectory(${LLVM_MAIN_SRC_DIR}/lib/Testing/Support
- lib/Testing/Support)
- endif()
-endif()
-
-function(add_lldb_unittest test_name)
- cmake_parse_arguments(ARG
- ""
- ""
- "LINK_LIBS;LINK_COMPONENTS"
- ${ARGN})
-
- if (NOT ${test_name} MATCHES "Tests$")
- message(FATAL_ERROR "Unit test name must end with 'Tests' for lit to find it.")
- endif()
-
- list(APPEND LLVM_LINK_COMPONENTS ${ARG_LINK_COMPONENTS})
-
- add_unittest(LLDBUnitTests
- ${test_name}
- ${ARG_UNPARSED_ARGUMENTS}
- )
-
- add_custom_command(
- TARGET ${test_name}
- POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Inputs)
-
- target_link_libraries(${test_name} PRIVATE ${ARG_LINK_LIBS})
-endfunction()
-
-function(add_unittest_inputs test_name inputs)
- foreach (INPUT ${inputs})
- add_custom_command(
- TARGET ${test_name}
- POST_BUILD
- COMMAND "${CMAKE_COMMAND}" -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Inputs/${INPUT} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/Inputs
- COMMENT "Copying ${INPUT} to binary directory.")
- endforeach()
-endfunction()
-
-add_subdirectory(TestingSupport)
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
- # FIXME: APITests.exe is not a valid googletest binary.
- add_subdirectory(API)
-endif()
-add_subdirectory(Breakpoint)
-add_subdirectory(Core)
-add_subdirectory(DataFormatter)
-add_subdirectory(Disassembler)
-add_subdirectory(Editline)
-add_subdirectory(Expression)
-add_subdirectory(Host)
-add_subdirectory(Interpreter)
-add_subdirectory(Instruction)
-add_subdirectory(Language)
-add_subdirectory(ObjectFile)
-add_subdirectory(Platform)
-add_subdirectory(Process)
-add_subdirectory(ScriptInterpreter)
-add_subdirectory(Signals)
-add_subdirectory(Symbol)
-add_subdirectory(SymbolFile)
-add_subdirectory(Target)
-add_subdirectory(tools)
-add_subdirectory(UnwindAssembly)
-add_subdirectory(Utility)
-add_subdirectory(Thread)
-
-if(LLDB_CAN_USE_DEBUGSERVER AND LLDB_TOOL_DEBUGSERVER_BUILD AND NOT LLDB_USE_SYSTEM_DEBUGSERVER)
- add_subdirectory(debugserver)
-endif()
+++ /dev/null
-add_lldb_unittest(LLDBCoreTests
- CommunicationTest.cpp
- DumpDataExtractorTest.cpp
- FormatEntityTest.cpp
- MangledTest.cpp
- ModuleSpecTest.cpp
- RichManglingContextTest.cpp
- SourceLocationSpecTest.cpp
- SourceManagerTest.cpp
- StreamCallbackTest.cpp
- UniqueCStringMapTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbPluginObjectFileELF
- lldbPluginObjectFileMachO
- lldbPluginObjectFilePECOFF
- lldbPluginSymbolFileSymtab
- lldbUtilityHelpers
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
+++ /dev/null
-//===-- CommunicationTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/Communication.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/Pipe.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-#ifndef _WIN32
-TEST(CommunicationTest, SynchronizeWhileClosing) {
- // Set up a communication object reading from a pipe.
- Pipe pipe;
- ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).ToError(),
- llvm::Succeeded());
-
- Communication comm("test");
- comm.SetConnection(std::make_unique<ConnectionFileDescriptor>(
- pipe.ReleaseReadFileDescriptor(), /*owns_fd=*/true));
- comm.SetCloseOnEOF(true);
- ASSERT_TRUE(comm.StartReadThread());
-
- // Ensure that we can safely synchronize with the read thread while it is
- // closing the read end (in response to us closing the write end).
- pipe.CloseWriteFileDescriptor();
- comm.SynchronizeWithReadThread();
-
- ASSERT_TRUE(comm.StopReadThread());
-}
-#endif
+++ /dev/null
-//===-- DataDumpExtractorTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/DumpDataExtractor.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/Endian.h"
-#include "lldb/Utility/StreamString.h"
-#include "gtest/gtest.h"
-#include <complex>
-#include <limits>
-
-using namespace lldb;
-using namespace lldb_private;
-
-static void TestDumpWithAddress(uint64_t base_addr, size_t item_count,
- llvm::StringRef expected) {
- std::vector<uint8_t> data{0x11, 0x22};
- StreamString result;
- DataBufferHeap dumpbuffer(&data[0], data.size());
- DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
- endian::InlHostByteOrder(), /*addr_size=*/4);
-
- DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatHex,
- /*item_byte_size=*/1, item_count,
- /*num_per_line=*/1, base_addr, 0, 0);
- ASSERT_EQ(expected, result.GetString());
-}
-
-TEST(DumpDataExtractorTest, BaseAddress) {
- TestDumpWithAddress(0x12341234, 1, "0x12341234: 0x11");
- TestDumpWithAddress(LLDB_INVALID_ADDRESS, 1, "0x11");
- TestDumpWithAddress(0x12341234, 2, "0x12341234: 0x11\n0x12341235: 0x22");
- TestDumpWithAddress(LLDB_INVALID_ADDRESS, 2, "0x11\n0x22");
-}
-
-static void TestDumpWithOffset(offset_t start_offset,
- llvm::StringRef expected) {
- std::vector<uint8_t> data{0x11, 0x22, 0x33};
- StreamString result;
- DataBufferHeap dumpbuffer(&data[0], data.size());
- DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
- endian::InlHostByteOrder(), /*addr_size=*/4);
-
- DumpDataExtractor(extractor, &result, start_offset, lldb::Format::eFormatHex,
- /*item_byte_size=*/1, /*item_count=*/data.size(),
- /*num_per_line=*/data.size(), /*base_addr=*/0, 0, 0);
- ASSERT_EQ(expected, result.GetString());
-}
-
-TEST(DumpDataExtractorTest, StartOffset) {
- TestDumpWithOffset(0, "0x00000000: 0x11 0x22 0x33");
- // The offset applies to the DataExtractor, not the address used when
- // formatting.
- TestDumpWithOffset(1, "0x00000000: 0x22 0x33");
- // If the offset is outside the DataExtractor's range we do nothing.
- TestDumpWithOffset(3, "");
-}
-
-TEST(DumpDataExtractorTest, NullStream) {
- // We don't do any work if there is no output stream.
- uint8_t c = 0x11;
- StreamString result;
- DataBufferHeap dumpbuffer(&c, 0);
- DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
- endian::InlHostByteOrder(), /*addr_size=*/4);
-
- DumpDataExtractor(extractor, nullptr, 0, lldb::Format::eFormatHex,
- /*item_byte_size=*/1, /*item_count=*/1,
- /*num_per_line=*/1, /*base_addr=*/0, 0, 0);
- ASSERT_EQ("", result.GetString());
-}
-
-static void TestDumpImpl(const void *data, size_t data_size,
- size_t item_byte_size, size_t item_count,
- size_t num_per_line, uint64_t base_addr,
- lldb::Format format, llvm::StringRef expected) {
- StreamString result;
- DataBufferHeap dumpbuffer(data, data_size);
- DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
- endian::InlHostByteOrder(),
- /*addr_size=*/4);
- DumpDataExtractor(extractor, &result, 0, format, item_byte_size, item_count,
- num_per_line, base_addr, 0, 0);
- ASSERT_EQ(expected, result.GetString());
-}
-
-template <typename T>
-static void TestDump(T data, lldb::Format format, llvm::StringRef expected) {
- TestDumpImpl(&data, sizeof(T), sizeof(T), 1, 1, LLDB_INVALID_ADDRESS, format,
- expected);
-}
-
-static void TestDump(llvm::StringRef str, lldb::Format format,
- llvm::StringRef expected) {
- TestDumpImpl(str.bytes_begin(),
- // +1 to include the NULL char as the last byte
- str.size() + 1, str.size() + 1, 1, 1, LLDB_INVALID_ADDRESS,
- format, expected);
-}
-
-template <typename T>
-static void TestDump(const std::vector<T> data, lldb::Format format,
- llvm::StringRef expected) {
- size_t sz_bytes = data.size() * sizeof(T);
- TestDumpImpl(&data[0], sz_bytes, sz_bytes, data.size(), 1,
- LLDB_INVALID_ADDRESS, format, expected);
-}
-
-TEST(DumpDataExtractorTest, Formats) {
- TestDump<uint8_t>(1, lldb::eFormatDefault, "0x01");
- TestDump<uint8_t>(1, lldb::eFormatBoolean, "true");
- TestDump<uint8_t>(0xAA, lldb::eFormatBinary, "0b10101010");
- TestDump<uint8_t>(1, lldb::eFormatBytes, "01");
- TestDump<uint8_t>(1, lldb::eFormatBytesWithASCII, "01 .");
- TestDump('?', lldb::eFormatChar, "'?'");
- TestDump('\x1A', lldb::eFormatCharPrintable, ".");
- TestDump('#', lldb::eFormatCharPrintable, "#");
- TestDump(std::complex<float>(1.2, 3.4), lldb::eFormatComplex, "1.2 + 3.4i");
- TestDump(std::complex<double>(4.5, 6.7), lldb::eFormatComplex, "4.5 + 6.7i");
-
- // long double is not tested here because for some platforms we treat it as 10
- // bytes when the compiler allocates 16 bytes of space for it. (see
- // DataExtractor::GetLongDouble) Meaning that when we extract the second one,
- // it gets the wrong value (it's 6 bytes off). You could manually construct a
- // set of bytes to match the 10 byte format but then if the test runs on a
- // machine where we don't use 10 it'll break.
-
- TestDump(llvm::StringRef("aardvark"), lldb::Format::eFormatCString,
- "\"aardvark\"");
- TestDump<uint16_t>(99, lldb::Format::eFormatDecimal, "99");
- // Just prints as a signed integer.
- TestDump(-1, lldb::Format::eFormatEnum, "-1");
- TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d");
- TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D");
- TestDump(0.456, lldb::Format::eFormatFloat, "0.456");
- TestDump(9, lldb::Format::eFormatOctal, "011");
- // Chars packed into an integer.
- TestDump<uint32_t>(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'");
- // Unicode8 doesn't have a specific formatter.
- TestDump<uint8_t>(0x34, lldb::Format::eFormatUnicode8, "0x34");
- TestDump<uint16_t>(0x1122, lldb::Format::eFormatUnicode16, "U+1122");
- TestDump<uint32_t>(0x12345678, lldb::Format::eFormatUnicode32,
- "U+0x12345678");
- TestDump<unsigned int>(654321, lldb::Format::eFormatUnsigned, "654321");
- // This pointer is printed based on the size of uint64_t, so the test is the
- // same for 32/64 bit host.
- TestDump<uint64_t>(0x4444555566667777, lldb::Format::eFormatPointer,
- "0x4444555566667777");
-
- TestDump(std::vector<char>{'A', '\x01', 'C'},
- lldb::Format::eFormatVectorOfChar, "{A\\x01C}");
- TestDump(std::vector<int8_t>{0, -1, std::numeric_limits<int8_t>::max()},
- lldb::Format::eFormatVectorOfSInt8, "{0 -1 127}");
- TestDump(std::vector<uint8_t>{12, 0xFF, 34},
- lldb::Format::eFormatVectorOfUInt8, "{0x0c 0xff 0x22}");
- TestDump(std::vector<int16_t>{-1, 1234, std::numeric_limits<int16_t>::max()},
- lldb::Format::eFormatVectorOfSInt16, "{-1 1234 32767}");
- TestDump(std::vector<uint16_t>{0xffff, 0xabcd, 0x1234},
- lldb::Format::eFormatVectorOfUInt16, "{0xffff 0xabcd 0x1234}");
- TestDump(std::vector<int32_t>{0, -1, std::numeric_limits<int32_t>::max()},
- lldb::Format::eFormatVectorOfSInt32, "{0 -1 2147483647}");
- TestDump(std::vector<uint32_t>{0, 0xffffffff, 0x1234abcd},
- lldb::Format::eFormatVectorOfUInt32,
- "{0x00000000 0xffffffff 0x1234abcd}");
- TestDump(std::vector<int64_t>{0, -1, std::numeric_limits<int64_t>::max()},
- lldb::Format::eFormatVectorOfSInt64, "{0 -1 9223372036854775807}");
- TestDump(std::vector<uint64_t>{0, 0xaaaabbbbccccdddd},
- lldb::Format::eFormatVectorOfUInt64,
- "{0x0000000000000000 0xaaaabbbbccccdddd}");
-
- // See half2float for format details.
- // Test zeroes.
- TestDump(std::vector<uint16_t>{0x0000, 0x8000},
- lldb::Format::eFormatVectorOfFloat16, "{0 -0}");
- // Some subnormal numbers.
- TestDump(std::vector<uint16_t>{0x0001, 0x8001},
- lldb::Format::eFormatVectorOfFloat16, "{5.96046e-08 -5.96046e-08}");
- // A full mantisse and empty expontent.
- TestDump(std::vector<uint16_t>{0x83ff, 0x03ff},
- lldb::Format::eFormatVectorOfFloat16, "{-6.09756e-05 6.09756e-05}");
- // Some normal numbers.
- TestDump(std::vector<uint16_t>{0b0100001001001000},
- lldb::Format::eFormatVectorOfFloat16,
-#ifdef _WIN32
- // FIXME: This should print the same on all platforms.
- "{3.14063}");
-#else
- "{3.14062}");
-#endif
- // Largest and smallest normal number.
- TestDump(std::vector<uint16_t>{0x0400, 0x7bff},
- lldb::Format::eFormatVectorOfFloat16, "{6.10352e-05 65504}");
- TestDump(std::vector<uint16_t>{0xabcd, 0x1234},
- lldb::Format::eFormatVectorOfFloat16, "{-0.0609436 0.000757217}");
-
- // quiet/signaling NaNs.
- TestDump(std::vector<uint16_t>{0xffff, 0xffc0, 0x7fff, 0x7fc0},
- lldb::Format::eFormatVectorOfFloat16, "{-nan -nan nan nan}");
- // +/-Inf.
- TestDump(std::vector<uint16_t>{0xfc00, 0x7c00},
- lldb::Format::eFormatVectorOfFloat16, "{-inf inf}");
-
- TestDump(std::vector<float>{std::numeric_limits<float>::min(),
- std::numeric_limits<float>::max()},
- lldb::Format::eFormatVectorOfFloat32, "{1.17549e-38 3.40282e+38}");
- TestDump(std::vector<float>{std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::signaling_NaN(),
- -std::numeric_limits<float>::quiet_NaN(),
- -std::numeric_limits<float>::signaling_NaN()},
- lldb::Format::eFormatVectorOfFloat32, "{nan nan -nan -nan}");
- TestDump(std::vector<double>{std::numeric_limits<double>::min(),
- std::numeric_limits<double>::max()},
- lldb::Format::eFormatVectorOfFloat64,
- "{2.2250738585072e-308 1.79769313486232e+308}");
- TestDump(
- std::vector<double>{
- std::numeric_limits<double>::quiet_NaN(),
- std::numeric_limits<double>::signaling_NaN(),
- -std::numeric_limits<double>::quiet_NaN(),
- -std::numeric_limits<double>::signaling_NaN(),
- },
- lldb::Format::eFormatVectorOfFloat64, "{nan nan -nan -nan}");
-
- // Not sure we can rely on having uint128_t everywhere so emulate with
- // uint64_t.
- TestDump(
- std::vector<uint64_t>{0x1, 0x1111222233334444, 0xaaaabbbbccccdddd, 0x0},
- lldb::Format::eFormatVectorOfUInt128,
- "{0x11112222333344440000000000000001 "
- "0x0000000000000000aaaabbbbccccdddd}");
-
- TestDump(std::vector<int>{2, 4}, lldb::Format::eFormatComplexInteger,
- "2 + 4i");
-
- // Without an execution context this just prints the pointer on its own.
- TestDump<uint32_t>(0x11223344, lldb::Format::eFormatAddressInfo,
- "0x11223344");
-
- // Input not written in hex form because that requires C++17.
- TestDump<float>(10, lldb::Format::eFormatHexFloat, "0x1.4p3");
- TestDump<double>(10, lldb::Format::eFormatHexFloat, "0x1.4p3");
- // long double not supported, see ItemByteSizeErrors.
-
- // Can't disassemble without an execution context.
- TestDump<uint32_t>(0xcafef00d, lldb::Format::eFormatInstruction,
- "invalid target");
-
- // Has no special handling, intended for use elsewhere.
- TestDump<int>(99, lldb::Format::eFormatVoid, "0x00000063");
-}
-
-TEST(DumpDataExtractorTest, FormatCharArray) {
- // Unlike the other formats, charArray isn't 1 array of N chars.
- // It must be passed as N chars of 1 byte each.
- // (eFormatVectorOfChar does this swap for you)
- std::vector<char> data{'A', '\x01', '#'};
- StreamString result;
- DataBufferHeap dumpbuffer(&data[0], data.size());
- DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
- endian::InlHostByteOrder(), /*addr_size=*/4);
-
- DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray,
- /*item_byte_size=*/1,
- /*item_count=*/data.size(),
- /*num_per_line=*/data.size(), 0, 0, 0);
- ASSERT_EQ("0x00000000: A\\x01#", result.GetString());
-
- result.Clear();
- DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, 1,
- data.size(), 1, 0, 0, 0);
- // ASSERT macro thinks the split strings are multiple arguments so make a var.
- const char *expected = "0x00000000: A\n"
- "0x00000001: \\x01\n"
- "0x00000002: #";
- ASSERT_EQ(expected, result.GetString());
-}
-
-template <typename T>
-void TestDumpMultiLine(std::vector<T> data, lldb::Format format,
- size_t num_per_line, llvm::StringRef expected) {
- size_t sz_bytes = data.size() * sizeof(T);
- TestDumpImpl(&data[0], sz_bytes, data.size(), sz_bytes, num_per_line,
- 0x80000000, format, expected);
-}
-
-template <typename T>
-void TestDumpMultiLine(const T *data, size_t num_items, lldb::Format format,
- size_t num_per_line, llvm::StringRef expected) {
- TestDumpImpl(data, sizeof(T) * num_items, sizeof(T), num_items, num_per_line,
- 0x80000000, format, expected);
-}
-
-TEST(DumpDataExtractorTest, MultiLine) {
- // A vector counts as 1 item regardless of size.
- TestDumpMultiLine(std::vector<uint8_t>{0x11},
- lldb::Format::eFormatVectorOfUInt8, 1,
- "0x80000000: {0x11}");
- TestDumpMultiLine(std::vector<uint8_t>{0x11, 0x22},
- lldb::Format::eFormatVectorOfUInt8, 1,
- "0x80000000: {0x11 0x22}");
-
- // If you have multiple vectors then that's multiple items.
- // Here we say that these 2 bytes are actually 2 1 byte vectors.
- const std::vector<uint8_t> vector_data{0x11, 0x22};
- TestDumpMultiLine(vector_data.data(), 2, lldb::Format::eFormatVectorOfUInt8,
- 1, "0x80000000: {0x11}\n0x80000001: {0x22}");
-
- // Single value formats can span multiple lines.
- const std::vector<uint8_t> bytes{0x11, 0x22, 0x33};
- const char *expected_bytes_3_line = "0x80000000: 0x11\n"
- "0x80000001: 0x22\n"
- "0x80000002: 0x33";
- TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 1,
- expected_bytes_3_line);
-
- // Lines may not have the full number of items.
- TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 4,
- "0x80000000: 0x11 0x22 0x33");
- const char *expected_bytes_2_line = "0x80000000: 0x11 0x22\n"
- "0x80000002: 0x33";
- TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 2,
- expected_bytes_2_line);
-
- // The line address accounts for item sizes other than 1 byte.
- const std::vector<uint16_t> shorts{0x1111, 0x2222, 0x3333};
- const char *expected_shorts_2_line = "0x80000000: 0x1111 0x2222\n"
- "0x80000004: 0x3333";
- TestDumpMultiLine(shorts.data(), shorts.size(), lldb::Format::eFormatHex, 2,
- expected_shorts_2_line);
-
- // The ascii column is positioned using the maximum line length.
- const std::vector<char> chars{'L', 'L', 'D', 'B'};
- const char *expected_chars_2_lines = "0x80000000: 4c 4c 44 LLD\n"
- "0x80000003: 42 B";
- TestDumpMultiLine(chars.data(), chars.size(),
- lldb::Format::eFormatBytesWithASCII, 3,
- expected_chars_2_lines);
-}
-
-void TestDumpWithItemByteSize(size_t item_byte_size, lldb::Format format,
- llvm::StringRef expected) {
- // We won't be reading this data so anything will do.
- uint8_t dummy = 0;
- TestDumpImpl(&dummy, 1, item_byte_size, 1, 1, LLDB_INVALID_ADDRESS, format,
- expected);
-}
-
-TEST(DumpDataExtractorTest, ItemByteSizeErrors) {
- TestDumpWithItemByteSize(
- 16, lldb::Format::eFormatBoolean,
- "error: unsupported byte size (16) for boolean format");
- TestDumpWithItemByteSize(21, lldb::Format::eFormatChar,
- "error: unsupported byte size (21) for char format");
- TestDumpWithItemByteSize(
- 18, lldb::Format::eFormatComplexInteger,
- "error: unsupported byte size (18) for complex integer format");
-
- // The code uses sizeof(long double) for these checks. This changes by host
- // but we know it won't be >16.
- TestDumpWithItemByteSize(
- 34, lldb::Format::eFormatComplex,
- "error: unsupported byte size (34) for complex float format");
- TestDumpWithItemByteSize(
- 18, lldb::Format::eFormatFloat,
- "error: unsupported byte size (18) for float format");
-
- // We want sizes to exactly match one of float/double.
- TestDumpWithItemByteSize(
- 14, lldb::Format::eFormatComplex,
- "error: unsupported byte size (14) for complex float format");
- TestDumpWithItemByteSize(3, lldb::Format::eFormatFloat,
- "error: unsupported byte size (3) for float format");
-
- // We only allow float and double size.
- TestDumpWithItemByteSize(
- 1, lldb::Format::eFormatHexFloat,
- "error: unsupported byte size (1) for hex float format");
- TestDumpWithItemByteSize(
- 17, lldb::Format::eFormatHexFloat,
- "error: unsupported byte size (17) for hex float format");
-}
+++ /dev/null
-//===-- FormatEntityTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/FormatEntity.h"
-#include "lldb/Utility/Status.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-using Definition = FormatEntity::Entry::Definition;
-using Entry = FormatEntity::Entry;
-
-TEST(FormatEntityTest, DefinitionConstructionNameAndType) {
- Definition d("foo", FormatEntity::Entry::Type::Invalid);
-
- EXPECT_EQ(d.name, "foo");
- EXPECT_EQ(d.string, nullptr);
- EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid);
- EXPECT_EQ(d.data, 0UL);
- EXPECT_EQ(d.num_children, 0UL);
- EXPECT_EQ(d.children, nullptr);
- EXPECT_FALSE(d.keep_separator);
-}
-
-TEST(FormatEntityTest, DefinitionConstructionNameAndString) {
- Definition d("foo", "string");
-
- EXPECT_EQ(d.name, "foo");
- EXPECT_EQ(d.string, "string");
- EXPECT_EQ(d.type, FormatEntity::Entry::Type::EscapeCode);
- EXPECT_EQ(d.data, 0UL);
- EXPECT_EQ(d.num_children, 0UL);
- EXPECT_EQ(d.children, nullptr);
- EXPECT_FALSE(d.keep_separator);
-}
-
-TEST(FormatEntityTest, DefinitionConstructionNameTypeData) {
- Definition d("foo", FormatEntity::Entry::Type::Invalid, 33);
-
- EXPECT_EQ(d.name, "foo");
- EXPECT_EQ(d.string, nullptr);
- EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid);
- EXPECT_EQ(d.data, 33UL);
- EXPECT_EQ(d.num_children, 0UL);
- EXPECT_EQ(d.children, nullptr);
- EXPECT_FALSE(d.keep_separator);
-}
-
-TEST(FormatEntityTest, DefinitionConstructionNameTypeChildren) {
- Definition d("foo", FormatEntity::Entry::Type::Invalid, 33);
- Definition parent("parent", FormatEntity::Entry::Type::Invalid, 1, &d);
- EXPECT_EQ(parent.name, "parent");
- EXPECT_EQ(parent.string, nullptr);
- EXPECT_EQ(parent.type, FormatEntity::Entry::Type::Invalid);
- EXPECT_EQ(parent.num_children, 1UL);
- EXPECT_EQ(parent.children, &d);
- EXPECT_FALSE(parent.keep_separator);
-
- EXPECT_EQ(parent.children[0].name, "foo");
- EXPECT_EQ(parent.children[0].string, nullptr);
- EXPECT_EQ(parent.children[0].type, FormatEntity::Entry::Type::Invalid);
- EXPECT_EQ(parent.children[0].data, 33UL);
- EXPECT_EQ(parent.children[0].num_children, 0UL);
- EXPECT_EQ(parent.children[0].children, nullptr);
- EXPECT_FALSE(d.keep_separator);
-}
-
-constexpr llvm::StringRef lookupStrings[] = {
- "${addr.load}",
- "${addr.file}",
- "${ansi.fg.black}",
- "${ansi.fg.red}",
- "${ansi.fg.green}",
- "${ansi.fg.yellow}",
- "${ansi.fg.blue}",
- "${ansi.fg.purple}",
- "${ansi.fg.cyan}",
- "${ansi.fg.white}",
- "${ansi.bg.black}",
- "${ansi.bg.red}",
- "${ansi.bg.green}",
- "${ansi.bg.yellow}",
- "${ansi.bg.blue}",
- "${ansi.bg.purple}",
- "${ansi.bg.cyan}",
- "${ansi.bg.white}",
- "${file.basename}",
- "${file.dirname}",
- "${file.fullpath}",
- "${frame.index}",
- "${frame.pc}",
- "${frame.fp}",
- "${frame.sp}",
- "${frame.flags}",
- "${frame.no-debug}",
- "${frame.reg.*}",
- "${frame.is-artificial}",
- "${function.id}",
- "${function.name}",
- "${function.name-without-args}",
- "${function.name-with-args}",
- "${function.mangled-name}",
- "${function.addr-offset}",
- "${function.concrete-only-addr-offset-no-padding}",
- "${function.line-offset}",
- "${function.pc-offset}",
- "${function.initial-function}",
- "${function.changed}",
- "${function.is-optimized}",
- "${line.file.basename}",
- "${line.file.dirname}",
- "${line.file.fullpath}",
- "${line.number}",
- "${line.column}",
- "${line.start-addr}",
- "${line.end-addr}",
- "${module.file.basename}",
- "${module.file.dirname}",
- "${module.file.fullpath}",
- "${process.id}",
- "${process.name}",
- "${process.file.basename}",
- "${process.file.dirname}",
- "${process.file.fullpath}",
- "${script.frame}",
- "${script.process}",
- "${script.target}",
- "${script.thread}",
- "${script.var}",
- "${script.svar}",
- "${script.thread}",
- "${svar.dummy-svar-to-test-wildcard}",
- "${thread.id}",
- "${thread.protocol_id}",
- "${thread.index}",
- "${thread.info.*}",
- "${thread.queue}",
- "${thread.name}",
- "${thread.stop-reason}",
- "${thread.stop-reason-raw}",
- "${thread.return-value}",
- "${thread.completed-expression}",
- "${target.arch}",
- "${var.dummy-var-to-test-wildcard}"};
-
-TEST(FormatEntity, LookupAllEntriesInTree) {
- for (const llvm::StringRef testString : lookupStrings) {
- Entry e;
- EXPECT_TRUE(FormatEntity::Parse(testString, e).Success())
- << "Formatting " << testString << " did not succeed";
- }
-}
+++ /dev/null
-//===-- MangledTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/Mangled.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/SymbolContext.h"
-
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(MangledTest, ResultForValidName) {
- ConstString MangledName("_ZN1a1b1cIiiiEEvm");
- Mangled TheMangled(MangledName);
- ConstString TheDemangled = TheMangled.GetDemangledName();
-
- ConstString ExpectedResult("void a::b::c<int, int, int>(unsigned long)");
- EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
-}
-
-TEST(MangledTest, ResultForBlockInvocation) {
- ConstString MangledName("___Z1fU13block_pointerFviE_block_invoke");
- Mangled TheMangled(MangledName);
- ConstString TheDemangled = TheMangled.GetDemangledName();
-
- ConstString ExpectedResult(
- "invocation function for block in f(void (int) block_pointer)");
- EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
-}
-
-TEST(MangledTest, EmptyForInvalidName) {
- ConstString MangledName("_ZN1a1b1cmxktpEEvm");
- Mangled TheMangled(MangledName);
- ConstString TheDemangled = TheMangled.GetDemangledName();
-
- EXPECT_STREQ("", TheDemangled.GetCString());
-}
-
-TEST(MangledTest, ResultForValidRustV0Name) {
- ConstString mangled_name("_RNvC1a4main");
- Mangled the_mangled(mangled_name);
- ConstString the_demangled = the_mangled.GetDemangledName();
-
- ConstString expected_result("a::main");
- EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
-}
-
-TEST(MangledTest, EmptyForInvalidRustV0Name) {
- ConstString mangled_name("_RRR");
- Mangled the_mangled(mangled_name);
- ConstString the_demangled = the_mangled.GetDemangledName();
-
- EXPECT_STREQ("", the_demangled.GetCString());
-}
-
-TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
- subsystems;
-
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_X86_64
-Sections:
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- AddressAlign: 0x0000000000000010
- Size: 0x20
- - Name: .anothertext
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x0000000000000010
- AddressAlign: 0x0000000000000010
- Size: 0x40
- - Name: .data
- Type: SHT_PROGBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x00000000000000A8
- AddressAlign: 0x0000000000000004
- Content: '01000000'
-Symbols:
- - Name: somedata
- Type: STT_OBJECT
- Section: .anothertext
- Value: 0x0000000000000045
- Binding: STB_GLOBAL
- - Name: main
- Type: STT_FUNC
- Section: .anothertext
- Value: 0x0000000000000010
- Size: 0x000000000000003F
- Binding: STB_GLOBAL
- - Name: _Z3foov
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: puts@GLIBC_2.5
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: puts@GLIBC_2.6
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _Z5annotv@VERSION3
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZN1AC2Ev
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZN1AD2Ev
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZN1A3barEv
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZGVZN4llvm4dbgsEvE7thestrm
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZZN4llvm4dbgsEvE7thestrm
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _ZTVN5clang4DeclE
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: -[ObjCfoo]
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: +[B ObjCbar(WithCategory)]
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
- - Name: _Z12undemangableEvx42
- Type: STT_FUNC
- Section: .text
- Size: 0x000000000000000D
- Binding: STB_GLOBAL
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
-
- auto Count = [M](const char *Name, FunctionNameType Type) -> int {
- SymbolContextList SymList;
- M->FindFunctionSymbols(ConstString(Name), Type, SymList);
- return SymList.GetSize();
- };
-
- // Unmangled
- EXPECT_EQ(1, Count("main", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("main", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("main", eFunctionNameTypeMethod));
-
- // Itanium mangled
- EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("foo", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("foo", eFunctionNameTypeMethod));
-
- // Unmangled with linker annotation
- EXPECT_EQ(1, Count("puts@GLIBC_2.5", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("puts@GLIBC_2.6", eFunctionNameTypeFull));
- EXPECT_EQ(2, Count("puts", eFunctionNameTypeFull));
- EXPECT_EQ(2, Count("puts", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("puts", eFunctionNameTypeMethod));
-
- // Itanium mangled with linker annotation
- EXPECT_EQ(1, Count("_Z5annotv@VERSION3", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("annot", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("annot", eFunctionNameTypeMethod));
-
- // Itanium mangled ctor A::A()
- EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("A", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("A", eFunctionNameTypeBase));
-
- // Itanium mangled dtor A::~A()
- EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("~A", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("~A", eFunctionNameTypeBase));
-
- // Itanium mangled method A::bar()
- EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("bar", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("bar", eFunctionNameTypeBase));
-
- // Itanium mangled names that are explicitly excluded from parsing
- EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
- EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("Decl", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("Decl", eFunctionNameTypeBase));
-
- // ObjC mangled static
- EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("ObjCfoo", eFunctionNameTypeMethod));
-
- // ObjC mangled method with category
- EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("ObjCbar", eFunctionNameTypeMethod));
-
- // Invalid things: unable to decode but still possible to find by full name
- EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeFull));
- EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("_Z12undemangableEvx42", eFunctionNameTypeMethod));
- EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
- EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
-}
+++ /dev/null
-//===-- ModuleSpecTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Utility/DataBuffer.h"
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
-#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-extern const char *TestMainArgv0;
-
-// This test file intentionally doesn't initialize the FileSystem.
-// Everything in this file should be able to run without requiring
-// any interaction with the FileSystem class; by keeping it
-// uninitialized, it will assert if anything tries to interact with
-// it.
-
-TEST(ModuleSpecTest, InvalidInMemoryBuffer) {
- uint8_t Invalid[] = "This is not a binary file.";
- DataBufferSP InvalidBufferSP =
- std::make_shared<DataBufferUnowned>(Invalid, sizeof(Invalid));
- ModuleSpec Spec(FileSpec(), UUID(), InvalidBufferSP);
-
- auto InvalidModuleSP = std::make_shared<Module>(Spec);
- ASSERT_EQ(InvalidModuleSP->GetObjectFile(), nullptr);
-}
-
-TEST(ModuleSpecTest, InvalidInMemoryBufferValidFile) {
- uint8_t Invalid[] = "This is not a binary file.";
- DataBufferSP InvalidBufferSP =
- std::make_shared<DataBufferUnowned>(Invalid, sizeof(Invalid));
- ModuleSpec Spec(FileSpec(TestMainArgv0), UUID(), InvalidBufferSP);
-
- auto InvalidModuleSP = std::make_shared<Module>(Spec);
- ASSERT_EQ(InvalidModuleSP->GetObjectFile(), nullptr);
-}
-
-TEST(ModuleSpecTest, TestELFFile) {
- SubsystemRAII<ObjectFileELF> subsystems;
-
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_REL
- Machine: EM_X86_64
-Sections:
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- AddressAlign: 0x0000000000000010
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
- ObjectFile *OF = M->GetObjectFile();
-
- ASSERT_EQ(llvm::isa<ObjectFileELF>(OF), true);
-}
-
-TEST(ModuleSpecTest, TestCOFFFile) {
- SubsystemRAII<ObjectFilePECOFF> subsystems;
-
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !COFF
-OptionalHeader:
- AddressOfEntryPoint: 0
- ImageBase: 16777216
- SectionAlignment: 4096
- FileAlignment: 512
- MajorOperatingSystemVersion: 6
- MinorOperatingSystemVersion: 0
- MajorImageVersion: 0
- MinorImageVersion: 0
- MajorSubsystemVersion: 6
- MinorSubsystemVersion: 0
- Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
- DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
- SizeOfStackReserve: 1048576
- SizeOfStackCommit: 4096
- SizeOfHeapReserve: 1048576
- SizeOfHeapCommit: 4096
-header:
- Machine: IMAGE_FILE_MACHINE_AMD64
- Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
-sections:
- - Name: .text
- Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
- VirtualAddress: 4096
- VirtualSize: 4096
-symbols: []
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
- ObjectFile *OF = M->GetObjectFile();
-
- ASSERT_EQ(llvm::isa<ObjectFilePECOFF>(OF), true);
-}
-
-TEST(ModuleSpecTest, TestMachOFile) {
- SubsystemRAII<ObjectFileMachO> subsystems;
-
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !mach-o
-FileHeader:
- magic: 0xFEEDFACF
- cputype: 0x0100000C
- cpusubtype: 0x00000000
- filetype: 0x00000001
- ncmds: 1
- sizeofcmds: 232
- flags: 0x00002000
- reserved: 0x00000000
-LoadCommands:
- - cmd: LC_SEGMENT_64
- cmdsize: 232
- segname: ''
- vmaddr: 0
- vmsize: 56
- fileoff: 392
- filesize: 56
- maxprot: 7
- initprot: 7
- nsects: 1
- flags: 0
- Sections:
- - sectname: __text
- segname: __TEXT
- addr: 0x0000000000000000
- size: 24
- offset: 0x00000188
- align: 2
- reloff: 0x00000000
- nreloc: 0
- flags: 0x80000400
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
- ObjectFile *OF = M->GetObjectFile();
-
- ASSERT_EQ(llvm::isa<ObjectFileMachO>(OF), true);
-}
+++ /dev/null
-//===-- RichManglingContextTest.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/RichManglingContext.h"
-
-#include "lldb/Utility/ConstString.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(RichManglingContextTest, Basic) {
- RichManglingContext RMC;
- ConstString mangled("_ZN3foo3barEv");
- EXPECT_TRUE(RMC.FromItaniumName(mangled));
-
- EXPECT_TRUE(RMC.IsFunction());
- EXPECT_FALSE(RMC.IsCtorOrDtor());
-
- RMC.ParseFunctionDeclContextName();
- EXPECT_EQ("foo", RMC.GetBufferRef());
-
- RMC.ParseFunctionBaseName();
- EXPECT_EQ("bar", RMC.GetBufferRef());
-
- RMC.ParseFullName();
- EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
-}
-
-TEST(RichManglingContextTest, FromCxxMethodName) {
- RichManglingContext ItaniumRMC;
- ConstString mangled("_ZN3foo3barEv");
- EXPECT_TRUE(ItaniumRMC.FromItaniumName(mangled));
-
- RichManglingContext CxxMethodRMC;
- ConstString demangled("foo::bar()");
- EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled));
-
- EXPECT_TRUE(ItaniumRMC.IsFunction() == CxxMethodRMC.IsFunction());
- EXPECT_TRUE(ItaniumRMC.IsCtorOrDtor() == CxxMethodRMC.IsCtorOrDtor());
-
- ItaniumRMC.ParseFunctionDeclContextName();
- CxxMethodRMC.ParseFunctionDeclContextName();
- EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
-
- ItaniumRMC.ParseFunctionBaseName();
- CxxMethodRMC.ParseFunctionBaseName();
- EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
-
- ItaniumRMC.ParseFullName();
- CxxMethodRMC.ParseFullName();
- EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
-
- // Construct with a random name.
- {
- RichManglingContext CxxMethodRMC;
- EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(ConstString("X")));
-
- // We expect it is not a function.
- EXPECT_FALSE(CxxMethodRMC.IsFunction());
- }
-
- // Construct with a function without a context.
- {
- RichManglingContext CxxMethodRMC;
- EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(
- ConstString("void * operator new(unsigned __int64)")));
-
- // We expect it is a function.
- EXPECT_TRUE(CxxMethodRMC.IsFunction());
-
- // We expect its context is empty.
- CxxMethodRMC.ParseFunctionDeclContextName();
- EXPECT_TRUE(CxxMethodRMC.GetBufferRef().empty());
- }
-}
-
-TEST(RichManglingContextTest, SwitchProvider) {
- RichManglingContext RMC;
- llvm::StringRef mangled = "_ZN3foo3barEv";
- llvm::StringRef demangled = "foo::bar()";
-
- EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
- RMC.ParseFullName();
- EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
-
- EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled)));
- RMC.ParseFullName();
- EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
-
- EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
- RMC.ParseFullName();
- EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
-}
-
-TEST(RichManglingContextTest, IPDRealloc) {
- // The demangled name should fit into the Itanium default buffer.
- const char *ShortMangled = "_ZN3foo3barEv";
-
- // The demangled name for this will certainly not fit into the default buffer.
- const char *LongMangled =
- "_ZNK3shk6detail17CallbackPublisherIZNS_5ThrowERKNSt15__exception_"
- "ptr13exception_ptrEEUlOT_E_E9SubscribeINS0_9ConcatMapINS0_"
- "18CallbackSubscriberIZNS_6GetAllIiNS1_IZZNS_9ConcatMapIZNS_6ConcatIJNS1_"
- "IZZNS_3MapIZZNS_7IfEmptyIS9_EEDaS7_ENKUlS6_E_clINS1_IZZNS_4TakeIiEESI_"
- "S7_ENKUlS6_E_clINS1_IZZNS_6FilterIZNS_9ElementAtEmEUlS7_E_EESI_S7_"
- "ENKUlS6_E_clINS1_IZZNSL_ImEESI_S7_ENKUlS6_E_clINS1_IZNS_4FromINS0_"
- "22InfiniteRangeContainerIiEEEESI_S7_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_"
- "EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_EUlS7_E_EESI_S7_ENKUlS6_E_clIS14_"
- "EESI_S6_EUlS7_E_EERNS1_IZZNSH_IS9_EESI_S7_ENKSK_IS14_EESI_S6_EUlS7_E0_"
- "EEEEESI_DpOT_EUlS7_E_EESI_S7_ENKUlS6_E_clINS1_IZNS_5StartIJZNS_"
- "4JustIJS19_S1C_EEESI_S1F_EUlvE_ZNS1K_IJS19_S1C_EEESI_S1F_EUlvE0_EEESI_"
- "S1F_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESt6vectorIS6_SaIS6_EERKT0_NS_"
- "12ElementCountEbEUlS7_E_ZNSD_IiS1Q_EES1T_S1W_S1X_bEUlOS3_E_ZNSD_IiS1Q_"
- "EES1T_S1W_S1X_bEUlvE_EES1G_S1O_E25ConcatMapValuesSubscriberEEEDaS7_";
-
- RichManglingContext RMC;
-
- // Demangle the short one.
- EXPECT_TRUE(RMC.FromItaniumName(ConstString(ShortMangled)));
- RMC.ParseFullName();
- const char *ShortDemangled = RMC.GetBufferRef().data();
-
- // Demangle the long one.
- EXPECT_TRUE(RMC.FromItaniumName(ConstString(LongMangled)));
- RMC.ParseFullName();
- const char *LongDemangled = RMC.GetBufferRef().data();
-
- // Make sure a new buffer was allocated or the default buffer was extended.
- bool AllocatedNewBuffer = (ShortDemangled != LongDemangled);
- bool ExtendedExistingBuffer = (strlen(LongDemangled) > 2048);
- EXPECT_TRUE(AllocatedNewBuffer || ExtendedExistingBuffer);
-}
+++ /dev/null
-//===-- SourceLocationSpecTest.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Core/SourceLocationSpec.h"
-#include "lldb/Utility/LLDBAssert.h"
-
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private;
-
-TEST(SourceLocationSpecTest, OperatorBool) {
- SourceLocationSpec invalid(FileSpec(), 0);
- EXPECT_FALSE(invalid);
-
- SourceLocationSpec invalid_filespec(FileSpec(), 4);
- EXPECT_FALSE(invalid_filespec);
-
- SourceLocationSpec invalid_line(FileSpec("/foo/bar"), 0);
- EXPECT_FALSE(invalid_line);
-
- SourceLocationSpec valid_fs_line_no_column(FileSpec("/foo/bar"), 4);
- EXPECT_TRUE(valid_fs_line_no_column);
-
- SourceLocationSpec invalid_fs_column(FileSpec(), 4, 0);
- EXPECT_FALSE(invalid_fs_column);
-
- SourceLocationSpec invalid_line_column(FileSpec("/foo/bar"), 0, 19);
- EXPECT_FALSE(invalid_line_column);
-
- SourceLocationSpec valid_fs_line_zero_column(FileSpec("/foo/bar"), 4, 0);
- EXPECT_TRUE(valid_fs_line_zero_column);
-
- SourceLocationSpec valid_fs_line_column(FileSpec("/foo/bar"), 4, 19);
- EXPECT_TRUE(valid_fs_line_column);
-}
-
-TEST(SourceLocationSpecTest, FileLineColumnComponents) {
- FileSpec fs("/foo/bar", FileSpec::Style::posix);
- const uint32_t line = 19;
- const uint16_t column = 4;
-
- SourceLocationSpec without_column(fs, line, LLDB_INVALID_COLUMN_NUMBER, false,
- true);
- EXPECT_TRUE(without_column);
- EXPECT_EQ(fs, without_column.GetFileSpec());
- EXPECT_EQ(line, without_column.GetLine().getValueOr(0));
- EXPECT_EQ(llvm::None, without_column.GetColumn());
- EXPECT_FALSE(without_column.GetCheckInlines());
- EXPECT_TRUE(without_column.GetExactMatch());
- EXPECT_STREQ("check inlines = false, exact match = true, decl = /foo/bar:19",
- without_column.GetString().c_str());
-
- SourceLocationSpec with_column(fs, line, column, true, false);
- EXPECT_TRUE(with_column);
- EXPECT_EQ(column, *with_column.GetColumn());
- EXPECT_TRUE(with_column.GetCheckInlines());
- EXPECT_FALSE(with_column.GetExactMatch());
- EXPECT_STREQ(
- "check inlines = true, exact match = false, decl = /foo/bar:19:4",
- with_column.GetString().c_str());
-}
-
-static SourceLocationSpec Create(bool check_inlines, bool exact_match,
- FileSpec fs, uint32_t line,
- uint16_t column = LLDB_INVALID_COLUMN_NUMBER) {
- return SourceLocationSpec(fs, line, column, check_inlines, exact_match);
-}
-
-TEST(SourceLocationSpecTest, Equal) {
- auto Equal = [](SourceLocationSpec lhs, SourceLocationSpec rhs, bool full) {
- return SourceLocationSpec::Equal(lhs, rhs, full);
- };
-
- const FileSpec fs("/foo/bar", FileSpec::Style::posix);
- const FileSpec other_fs("/foo/baz", FileSpec::Style::posix);
-
- // mutating FileSpec + const Inlined, ExactMatch, Line
- EXPECT_TRUE(
- Equal(Create(false, false, fs, 4), Create(false, false, fs, 4), true));
- EXPECT_TRUE(
- Equal(Create(true, true, fs, 4), Create(true, true, fs, 4), false));
- EXPECT_FALSE(Equal(Create(false, false, fs, 4),
- Create(false, false, other_fs, 4), true));
- EXPECT_FALSE(
- Equal(Create(true, true, fs, 4), Create(true, true, other_fs, 4), false));
-
- // Mutating FileSpec + const Inlined, ExactMatch, Line, Column
- EXPECT_TRUE(Equal(Create(false, false, fs, 4, 19),
- Create(false, false, fs, 4, 19), true));
- EXPECT_TRUE(Equal(Create(true, true, fs, 4, 19),
- Create(true, true, fs, 4, 19), false));
- EXPECT_FALSE(Equal(Create(false, false, fs, 4, 19),
- Create(false, false, other_fs, 4, 19), true));
- EXPECT_FALSE(Equal(Create(true, true, fs, 4, 19),
- Create(true, true, other_fs, 4, 19), false));
-
- // Asymetric match
- EXPECT_FALSE(
- Equal(Create(true, true, fs, 4), Create(true, true, fs, 4, 19), true));
- EXPECT_TRUE(Equal(Create(false, false, fs, 4),
- Create(false, false, fs, 4, 19), false));
-
- // Mutating Inlined, ExactMatch
- EXPECT_FALSE(
- Equal(Create(true, false, fs, 4), Create(false, true, fs, 4), true));
- EXPECT_TRUE(
- Equal(Create(false, true, fs, 4), Create(true, false, fs, 4), false));
-
- // Mutating Column
- EXPECT_FALSE(Equal(Create(true, true, fs, 4, 96),
- Create(true, true, fs, 4, 19), true));
- EXPECT_TRUE(Equal(Create(false, false, fs, 4, 96),
- Create(false, false, fs, 4, 19), false));
-}
-
-TEST(SourceLocationSpecTest, Compare) {
- auto Cmp = [](SourceLocationSpec a, SourceLocationSpec b) {
- return SourceLocationSpec::Compare(a, b);
- };
-
- FileSpec fs("/foo/bar", FileSpec::Style::posix);
- FileSpec other_fs("/foo/baz", FileSpec::Style::posix);
-
- // Asymetric comparaison
- EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 4, 19)));
- EXPECT_EQ(-1,
- Cmp(Create(false, false, fs, 4), Create(false, false, fs, 4, 19)));
- EXPECT_EQ(1, Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4)));
-
- // Mutating FS, const Line
- EXPECT_EQ(
- -1, Cmp(Create(false, false, fs, 4), Create(false, false, other_fs, 4)));
- EXPECT_EQ(-1,
- Cmp(Create(true, true, fs, 4), Create(true, true, other_fs, 4)));
- EXPECT_EQ(1,
- Cmp(Create(false, true, other_fs, 4), Create(false, true, fs, 4)));
- EXPECT_EQ(1,
- Cmp(Create(true, false, other_fs, 4), Create(true, false, fs, 4)));
-
- // Const FS, mutating Line
- EXPECT_EQ(-1, Cmp(Create(false, false, fs, 1), Create(false, false, fs, 4)));
- EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4)));
- EXPECT_EQ(0, Cmp(Create(false, true, fs, 4), Create(false, true, fs, 4)));
- EXPECT_EQ(0, Cmp(Create(true, false, fs, 4), Create(true, false, fs, 4)));
- EXPECT_EQ(1, Cmp(Create(false, false, fs, 4), Create(false, false, fs, 1)));
- EXPECT_EQ(1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 1)));
-
- // Const FS, mutating Line, const Column
- EXPECT_EQ(-1,
- Cmp(Create(false, true, fs, 1), Create(false, true, fs, 4, 19)));
- EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4, 19)));
- EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1)));
- EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1)));
-
- // Mutating FS, const Line, const Column
- EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19),
- Create(false, false, other_fs, 4, 19)));
- EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4, 19),
- Create(true, true, other_fs, 4, 19)));
- EXPECT_EQ(
- 0, Cmp(Create(false, false, fs, 4, 19), Create(false, false, fs, 4, 19)));
- EXPECT_EQ(0,
- Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4, 19)));
- EXPECT_EQ(1, Cmp(Create(false, true, other_fs, 4, 19),
- Create(false, true, fs, 4, 19)));
- EXPECT_EQ(1, Cmp(Create(true, false, other_fs, 4, 19),
- Create(true, false, fs, 4, 19)));
-
- // Const FS, const Line, mutating Column
- EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19),
- Create(false, false, fs, 4, 96)));
- EXPECT_EQ(1,
- Cmp(Create(true, true, fs, 4, 96), Create(true, true, fs, 4, 19)));
- EXPECT_EQ(
- 1, Cmp(Create(false, true, fs, 4, 96), Create(false, true, fs, 4, 19)));
-}
+++ /dev/null
-//===-- SourceManagerTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/SourceManager.h"
-#include "lldb/Host/FileSystem.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class SourceFileCache : public ::testing::Test {
-public:
- void SetUp() override { FileSystem::Initialize(); }
- void TearDown() override { FileSystem::Terminate(); }
-};
-
-TEST_F(SourceFileCache, FindSourceFileFound) {
- SourceManager::SourceFileCache cache;
-
- // Insert: foo
- FileSpec foo_file_spec("foo");
- auto foo_file_sp =
- std::make_shared<SourceManager::File>(foo_file_spec, nullptr);
- cache.AddSourceFile(foo_file_sp);
-
- // Query: foo, expect found.
- FileSpec another_foo_file_spec("foo");
- ASSERT_EQ(cache.FindSourceFile(another_foo_file_spec), foo_file_sp);
-}
-
-TEST_F(SourceFileCache, FindSourceFileNotFound) {
- SourceManager::SourceFileCache cache;
-
- // Insert: foo
- FileSpec foo_file_spec("foo");
- auto foo_file_sp =
- std::make_shared<SourceManager::File>(foo_file_spec, nullptr);
- cache.AddSourceFile(foo_file_sp);
-
- // Query: bar, expect not found.
- FileSpec bar_file_spec("bar");
- ASSERT_EQ(cache.FindSourceFile(bar_file_spec), nullptr);
-}
+++ /dev/null
-//===-- StreamCallbackTest.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StreamCallback.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-static char test_baton;
-static size_t callback_count = 0;
-static void TestCallback(const char *data, void *baton) {
- EXPECT_STREQ("Foobar", data);
- EXPECT_EQ(&test_baton, baton);
- ++callback_count;
-}
-
-TEST(StreamCallbackTest, Callback) {
- StreamCallback stream(TestCallback, &test_baton);
- stream << "Foobar";
- EXPECT_EQ(1u, callback_count);
-}
+++ /dev/null
-//===-- UniqueCStringMapTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Core/UniqueCStringMap.h"
-#include "gmock/gmock.h"
-
-using namespace lldb_private;
-
-namespace {
-struct NoDefault {
- int x;
-
- NoDefault(int x) : x(x) {}
- NoDefault() = delete;
-
- friend bool operator==(NoDefault lhs, NoDefault rhs) {
- return lhs.x == rhs.x;
- }
-
- friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
- NoDefault x) {
- return OS << "NoDefault{" << x.x << "}";
- }
-};
-} // namespace
-
-TEST(UniqueCStringMap, NoDefaultConstructor) {
- using MapT = UniqueCStringMap<NoDefault>;
- using EntryT = MapT::Entry;
-
- MapT Map;
- ConstString Foo("foo"), Bar("bar");
-
- Map.Append(Foo, NoDefault(42));
- EXPECT_THAT(Map.Find(Foo, NoDefault(47)), NoDefault(42));
- EXPECT_THAT(Map.Find(Bar, NoDefault(47)), NoDefault(47));
- EXPECT_THAT(Map.FindFirstValueForName(Foo),
- testing::Pointee(testing::Field(&EntryT::value, NoDefault(42))));
- EXPECT_THAT(Map.FindFirstValueForName(Bar), nullptr);
-
- std::vector<NoDefault> Values;
- EXPECT_THAT(Map.GetValues(Foo, Values), 1);
- EXPECT_THAT(Values, testing::ElementsAre(NoDefault(42)));
-
- Values.clear();
- EXPECT_THAT(Map.GetValues(Bar, Values), 0);
- EXPECT_THAT(Values, testing::IsEmpty());
-}
+++ /dev/null
-add_lldb_unittest(LLDBFormatterTests
- FormatManagerTests.cpp
- FormattersContainerTest.cpp
- StringPrinterTests.cpp
-
- LINK_LIBS
- lldbCore
- lldbInterpreter
- lldbSymbol
- lldbTarget
- lldbUtility
-
- LINK_COMPONENTS
- Support
- )
+++ /dev/null
-//===-- FormatManagerTests.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/DataFormatters/FormatManager.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(FormatManagerTests, CompatibleLangs) {
- std::vector<LanguageType> candidates = {eLanguageTypeC_plus_plus,
- eLanguageTypeObjC};
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC), candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC89), candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC99), candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC11), candidates);
-
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC_plus_plus),
- candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC_plus_plus_03),
- candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC_plus_plus_11),
- candidates);
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeC_plus_plus_14),
- candidates);
-
- candidates = {eLanguageTypeObjC};
- EXPECT_EQ(FormatManager::GetCandidateLanguages(eLanguageTypeObjC),
- candidates);
-}
+++ /dev/null
-//===-- FormattersContainerTests.cpp --------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/DataFormatters/FormattersContainer.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-// All the prefixes that the exact name matching will strip from the type.
-static const std::vector<std::string> exact_name_prefixes = {
- "", // no prefix.
- "class ", "struct ", "union ", "enum ",
-};
-
-// TypeMatcher that uses a exact type name string that needs to be matched.
-TEST(TypeMatcherTests, ExactName) {
- for (const std::string &prefix : exact_name_prefixes) {
- SCOPED_TRACE("Prefix: " + prefix);
-
- TypeMatcher matcher(ConstString(prefix + "Name"));
- EXPECT_TRUE(matcher.Matches(ConstString("class Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("struct Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("union Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("enum Name")));
- EXPECT_TRUE(matcher.Matches(ConstString("Name")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("Name ")));
- EXPECT_FALSE(matcher.Matches(ConstString("ame")));
- EXPECT_FALSE(matcher.Matches(ConstString("Nam")));
- EXPECT_FALSE(matcher.Matches(ConstString("am")));
- EXPECT_FALSE(matcher.Matches(ConstString("a")));
- EXPECT_FALSE(matcher.Matches(ConstString(" ")));
- EXPECT_FALSE(matcher.Matches(ConstString("class N")));
- EXPECT_FALSE(matcher.Matches(ConstString("class ")));
- EXPECT_FALSE(matcher.Matches(ConstString("class")));
- }
-}
-
-// TypeMatcher that uses a regex to match a type name.
-TEST(TypeMatcherTests, RegexName) {
- TypeMatcher matcher(RegularExpression("^a[a-z]c$"));
- EXPECT_TRUE(matcher.Matches(ConstString("abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("azc")));
-
- // FIXME: This isn't consistent with the 'exact' type name matches above.
- EXPECT_FALSE(matcher.Matches(ConstString("class abc")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("abbc")));
- EXPECT_FALSE(matcher.Matches(ConstString(" abc")));
- EXPECT_FALSE(matcher.Matches(ConstString("abc ")));
- EXPECT_FALSE(matcher.Matches(ConstString(" abc ")));
- EXPECT_FALSE(matcher.Matches(ConstString("XabcX")));
- EXPECT_FALSE(matcher.Matches(ConstString("ac")));
- EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));
- EXPECT_FALSE(matcher.Matches(ConstString("aAc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ABC")));
- EXPECT_FALSE(matcher.Matches(ConstString("")));
-}
-
-// TypeMatcher that only searches the type name.
-TEST(TypeMatcherTests, RegexMatchPart) {
- TypeMatcher matcher(RegularExpression("a[a-z]c"));
- EXPECT_TRUE(matcher.Matches(ConstString("class abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("abc")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString("azc")));
- EXPECT_TRUE(matcher.Matches(ConstString("abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc ")));
- EXPECT_TRUE(matcher.Matches(ConstString(" abc")));
- EXPECT_TRUE(matcher.Matches(ConstString("XabcX")));
-
- EXPECT_FALSE(matcher.Matches(ConstString("abbc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ac")));
- EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c")));
- EXPECT_FALSE(matcher.Matches(ConstString("aAc")));
- EXPECT_FALSE(matcher.Matches(ConstString("ABC")));
- EXPECT_FALSE(matcher.Matches(ConstString("")));
-}
-
-// GetMatchString for exact type name matchers.
-TEST(TypeMatcherTests, GetMatchStringExactName) {
- EXPECT_EQ(TypeMatcher(ConstString("aa")).GetMatchString(), "aa");
- EXPECT_EQ(TypeMatcher(ConstString("")).GetMatchString(), "");
- EXPECT_EQ(TypeMatcher(ConstString("[a]")).GetMatchString(), "[a]");
-}
-
-// GetMatchString for regex matchers.
-TEST(TypeMatcherTests, GetMatchStringRegex) {
- EXPECT_EQ(TypeMatcher(RegularExpression("aa")).GetMatchString(), "aa");
- EXPECT_EQ(TypeMatcher(RegularExpression("")).GetMatchString(), "");
- EXPECT_EQ(TypeMatcher(RegularExpression("[a]")).GetMatchString(), "[a]");
-}
-
-// GetMatchString for regex matchers.
-TEST(TypeMatcherTests, CreatedBySameMatchString) {
- TypeMatcher empty_str(ConstString(""));
- TypeMatcher empty_regex(RegularExpression(""));
- EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_str));
- EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_regex));
-
- TypeMatcher a_str(ConstString("a"));
- TypeMatcher a_regex(RegularExpression("a"));
- EXPECT_TRUE(a_str.CreatedBySameMatchString(a_str));
- EXPECT_TRUE(a_str.CreatedBySameMatchString(a_regex));
-
- TypeMatcher digit_str(ConstString("[0-9]"));
- TypeMatcher digit_regex(RegularExpression("[0-9]"));
- EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_str));
- EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_regex));
-
- EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_str));
- EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_regex));
- EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_str));
- EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_regex));
-
- EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_str));
- EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_regex));
- EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_str));
- EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_regex));
-
- EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_str));
- EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_regex));
- EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_str));
- EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_regex));
-
- EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_str));
- EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_regex));
- EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_str));
- EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_regex));
-
- EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_str));
- EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_regex));
- EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_str));
- EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_regex));
-
- EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_str));
- EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_regex));
- EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_str));
- EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_regex));
-}
-
-// Test CreatedBySameMatchString with stripped exact name prefixes.
-TEST(TypeMatcherTests, CreatedBySameMatchStringExactNamePrefixes) {
- for (const std::string &prefix : exact_name_prefixes) {
- SCOPED_TRACE("Prefix: " + prefix);
- TypeMatcher with_prefix(ConstString(prefix + "Name"));
- TypeMatcher without_prefix(RegularExpression(""));
-
- EXPECT_TRUE(with_prefix.CreatedBySameMatchString(with_prefix));
- EXPECT_TRUE(without_prefix.CreatedBySameMatchString(without_prefix));
- }
-}
+++ /dev/null
-//===-- StringPrinterTests.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/DataFormatters/StringPrinter.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/Endian.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-#include "gtest/gtest.h"
-#include <string>
-
-using namespace lldb;
-using namespace lldb_private;
-using lldb_private::formatters::StringPrinter;
-using llvm::Optional;
-using llvm::StringRef;
-
-#define QUOTE(x) std::string("\"" x "\"")
-
-/// Format \p input according to the specified string encoding and special char
-/// escape style.
-template <StringPrinter::StringElementType elem_ty>
-static Optional<std::string> format(StringRef input,
- StringPrinter::EscapeStyle escape_style) {
- StreamString out;
- StringPrinter::ReadBufferAndDumpToStreamOptions opts;
- opts.SetStream(&out);
- opts.SetSourceSize(input.size());
- opts.SetNeedsZeroTermination(true);
- opts.SetEscapeNonPrintables(true);
- opts.SetIgnoreMaxLength(false);
- opts.SetEscapeStyle(escape_style);
- DataExtractor extractor(input.data(), input.size(),
- endian::InlHostByteOrder(), sizeof(void *));
- opts.SetData(extractor);
- const bool success = StringPrinter::ReadBufferAndDumpToStream<elem_ty>(opts);
- if (!success)
- return llvm::None;
- return out.GetString().str();
-}
-
-// Test ASCII formatting for C++. This behaves exactly like UTF8 formatting for
-// C++, although that's questionable (see FIXME in StringPrinter.cpp).
-TEST(StringPrinterTests, CxxASCII) {
- auto fmt = [](StringRef str) {
- return format<StringPrinter::StringElementType::ASCII>(
- str, StringPrinter::EscapeStyle::CXX);
- };
-
- // Special escapes.
- EXPECT_EQ(fmt({"\0", 1}), QUOTE(""));
- EXPECT_EQ(fmt("\a"), QUOTE(R"(\a)"));
- EXPECT_EQ(fmt("\b"), QUOTE(R"(\b)"));
- EXPECT_EQ(fmt("\f"), QUOTE(R"(\f)"));
- EXPECT_EQ(fmt("\n"), QUOTE(R"(\n)"));
- EXPECT_EQ(fmt("\r"), QUOTE(R"(\r)"));
- EXPECT_EQ(fmt("\t"), QUOTE(R"(\t)"));
- EXPECT_EQ(fmt("\v"), QUOTE(R"(\v)"));
- EXPECT_EQ(fmt("\""), QUOTE(R"(\")"));
- EXPECT_EQ(fmt("\'"), QUOTE(R"(')"));
- EXPECT_EQ(fmt("\\"), QUOTE(R"(\\)"));
-
- // Printable characters.
- EXPECT_EQ(fmt("'"), QUOTE("'"));
- EXPECT_EQ(fmt("a"), QUOTE("a"));
- EXPECT_EQ(fmt("Z"), QUOTE("Z"));
- EXPECT_EQ(fmt("🥑"), QUOTE("🥑"));
-
- // Octal (\nnn), hex (\xnn), extended octal (\unnnn or \Unnnnnnnn).
- EXPECT_EQ(fmt("\uD55C"), QUOTE("\uD55C"));
- EXPECT_EQ(fmt("\U00010348"), QUOTE("\U00010348"));
-
- EXPECT_EQ(fmt("\376"), QUOTE(R"(\xfe)")); // \376 is 254 in decimal.
- EXPECT_EQ(fmt("\xfe"), QUOTE(R"(\xfe)")); // \xfe is 254 in decimal.
-}
-
-// Test UTF8 formatting for C++.
-TEST(StringPrinterTests, CxxUTF8) {
- auto fmt = [](StringRef str) {
- return format<StringPrinter::StringElementType::UTF8>(
- str, StringPrinter::EscapeStyle::CXX);
- };
-
- // Special escapes.
- EXPECT_EQ(fmt({"\0", 1}), QUOTE(""));
- EXPECT_EQ(fmt("\a"), QUOTE(R"(\a)"));
- EXPECT_EQ(fmt("\b"), QUOTE(R"(\b)"));
- EXPECT_EQ(fmt("\f"), QUOTE(R"(\f)"));
- EXPECT_EQ(fmt("\n"), QUOTE(R"(\n)"));
- EXPECT_EQ(fmt("\r"), QUOTE(R"(\r)"));
- EXPECT_EQ(fmt("\t"), QUOTE(R"(\t)"));
- EXPECT_EQ(fmt("\v"), QUOTE(R"(\v)"));
- EXPECT_EQ(fmt("\""), QUOTE(R"(\")"));
- EXPECT_EQ(fmt("\'"), QUOTE(R"(')"));
- EXPECT_EQ(fmt("\\"), QUOTE(R"(\\)"));
-
- // Printable characters.
- EXPECT_EQ(fmt("'"), QUOTE("'"));
- EXPECT_EQ(fmt("a"), QUOTE("a"));
- EXPECT_EQ(fmt("Z"), QUOTE("Z"));
- EXPECT_EQ(fmt("🥑"), QUOTE("🥑"));
-
- // Octal (\nnn), hex (\xnn), extended octal (\unnnn or \Unnnnnnnn).
- EXPECT_EQ(fmt("\uD55C"), QUOTE("\uD55C"));
- EXPECT_EQ(fmt("\U00010348"), QUOTE("\U00010348"));
-
- EXPECT_EQ(fmt("\376"), QUOTE(R"(\xfe)")); // \376 is 254 in decimal.
- EXPECT_EQ(fmt("\xfe"), QUOTE(R"(\xfe)")); // \xfe is 254 in decimal.
-}
-
-// Test UTF8 formatting for Swift.
-TEST(StringPrinterTests, SwiftUTF8) {
- auto fmt = [](StringRef str) {
- return format<StringPrinter::StringElementType::UTF8>(
- str, StringPrinter::EscapeStyle::Swift);
- };
-
- // Special escapes.
- EXPECT_EQ(fmt({"\0", 1}), QUOTE(""));
- EXPECT_EQ(fmt("\a"), QUOTE(R"(\a)"));
- EXPECT_EQ(fmt("\b"), QUOTE(R"(\u{8})"));
- EXPECT_EQ(fmt("\f"), QUOTE(R"(\u{c})"));
- EXPECT_EQ(fmt("\n"), QUOTE(R"(\n)"));
- EXPECT_EQ(fmt("\r"), QUOTE(R"(\r)"));
- EXPECT_EQ(fmt("\t"), QUOTE(R"(\t)"));
- EXPECT_EQ(fmt("\v"), QUOTE(R"(\u{b})"));
- EXPECT_EQ(fmt("\""), QUOTE(R"(\")"));
- EXPECT_EQ(fmt("\'"), QUOTE(R"(\')"));
- EXPECT_EQ(fmt("\\"), QUOTE(R"(\\)"));
-
- // Printable characters.
- EXPECT_EQ(fmt("'"), QUOTE(R"(\')"));
- EXPECT_EQ(fmt("a"), QUOTE("a"));
- EXPECT_EQ(fmt("Z"), QUOTE("Z"));
- EXPECT_EQ(fmt("🥑"), QUOTE("🥑"));
-
- // Octal (\nnn), hex (\xnn), extended octal (\unnnn or \Unnnnnnnn).
- EXPECT_EQ(fmt("\uD55C"), QUOTE("\uD55C"));
- EXPECT_EQ(fmt("\U00010348"), QUOTE("\U00010348"));
-
- EXPECT_EQ(fmt("\376"), QUOTE(R"(\u{fe})")); // \376 is 254 in decimal.
- EXPECT_EQ(fmt("\xfe"), QUOTE(R"(\u{fe})")); // \xfe is 254 in decimal.
-}
+++ /dev/null
-if("ARM" IN_LIST LLVM_TARGETS_TO_BUILD)
- add_lldb_unittest(DisassemblerTests
- TestArm64Disassembly.cpp
- TestArmv7Disassembly.cpp
- LINK_LIBS
- lldbCore
- lldbSymbol
- lldbTarget
- lldbPluginDisassemblerLLVMC
- lldbPluginProcessUtility
- LINK_COMPONENTS
- Support
- ${LLVM_TARGETS_TO_BUILD})
-endif()
+++ /dev/null
-//===-- TestArm64Disassembly.cpp ------------------------------------------===//
-
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Disassembler.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Target/ExecutionContext.h"
-
-#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestArm64Disassembly : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
- // virtual void SetUp() override { }
- // virtual void TearDown() override { }
-
-protected:
-};
-
-void TestArm64Disassembly::SetUpTestCase() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
- DisassemblerLLVMC::Initialize();
-}
-
-void TestArm64Disassembly::TearDownTestCase() {
- DisassemblerLLVMC::Terminate();
-}
-
-TEST_F(TestArm64Disassembly, TestArmv81Instruction) {
- ArchSpec arch("arm64-apple-ios");
-
- const unsigned num_of_instructions = 2;
- uint8_t data[] = {
- 0xff, 0x43, 0x00, 0xd1, // 0xd10043ff : sub sp, sp, #0x10
- 0x62, 0x7c, 0xa1, 0xc8, // 0xc8a17c62 : cas x1, x2, [x3] (cas defined in ARM v8.1 & newer)
- };
-
- DisassemblerSP disass_sp;
- Address start_addr(0x100);
- disass_sp = Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr,
- &data, sizeof (data), num_of_instructions, false);
-
- // If we failed to get a disassembler, we can assume it is because
- // the llvm we linked against was not built with the ARM target,
- // and we should skip these tests without marking anything as failing.
-
- if (disass_sp) {
- const InstructionList inst_list (disass_sp->GetInstructionList());
- EXPECT_EQ (num_of_instructions, inst_list.GetSize());
-
- InstructionSP inst_sp;
- const char *mnemonic;
- ExecutionContext exe_ctx (nullptr, nullptr, nullptr);
- inst_sp = inst_list.GetInstructionAtIndex (0);
- mnemonic = inst_sp->GetMnemonic(&exe_ctx);
- ASSERT_STREQ ("sub", mnemonic);
-
- inst_sp = inst_list.GetInstructionAtIndex (1);
- mnemonic = inst_sp->GetMnemonic(&exe_ctx);
- ASSERT_STREQ ("cas", mnemonic);
- }
-}
+++ /dev/null
-//===-- TestArmv7Disassembly.cpp ------------------------------------------===//
-
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Disassembler.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Target/ExecutionContext.h"
-
-#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestArmv7Disassembly : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
- // virtual void SetUp() override { }
- // virtual void TearDown() override { }
-
-protected:
-};
-
-void TestArmv7Disassembly::SetUpTestCase() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
- DisassemblerLLVMC::Initialize();
-}
-
-void TestArmv7Disassembly::TearDownTestCase() {
- DisassemblerLLVMC::Terminate();
-}
-
-TEST_F(TestArmv7Disassembly, TestCortexFPDisass) {
- ArchSpec arch("armv7em--");
-
- const unsigned num_of_instructions = 3;
- uint8_t data[] = {
- 0x00, 0xee, 0x10, 0x2a, // 0xee002a10 : vmov s0, r2
- 0xb8, 0xee, 0xc0, 0x0b, // 0xeeb80bc0 : vcvt.f64.s32 d0, s0
- 0xb6, 0xee, 0x00, 0x0a, // 0xeeb60a00 : vmov.f32 s0, #5.000000e-01
- };
-
- // these can be disassembled by hand with llvm-mc, e.g.
- //
- // 0x00, 0xee, 0x10, 0x2a, // 0xee002a10 : vmov s0, r2
- //
- // echo 0x00 0xee 0x10 0x2a | llvm-mc -arch thumb -disassemble -mattr=+fp-armv8
- // vmov s0, r2
-
- DisassemblerSP disass_sp;
- Address start_addr(0x100);
- disass_sp = Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr,
- &data, sizeof (data), num_of_instructions, false);
-
- // If we failed to get a disassembler, we can assume it is because
- // the llvm we linked against was not built with the ARM target,
- // and we should skip these tests without marking anything as failing.
-
- if (disass_sp) {
- const InstructionList inst_list (disass_sp->GetInstructionList());
- EXPECT_EQ (num_of_instructions, inst_list.GetSize());
-
- InstructionSP inst_sp;
- const char *mnemonic;
- ExecutionContext exe_ctx (nullptr, nullptr, nullptr);
- inst_sp = inst_list.GetInstructionAtIndex (0);
- mnemonic = inst_sp->GetMnemonic(&exe_ctx);
- ASSERT_STREQ ("vmov", mnemonic);
-
- inst_sp = inst_list.GetInstructionAtIndex (1);
- mnemonic = inst_sp->GetMnemonic(&exe_ctx);
- ASSERT_STREQ ("vcvt.f64.s32", mnemonic);
-
- inst_sp = inst_list.GetInstructionAtIndex (2);
- mnemonic = inst_sp->GetMnemonic(&exe_ctx);
- ASSERT_STREQ ("vmov.f32", mnemonic);
- }
-}
+++ /dev/null
-add_lldb_unittest(EditlineTests
- EditlineTest.cpp
-
- LINK_LIBS
- lldbHost
- lldbUtility
- LLVMTestingSupport
- )
+++ /dev/null
-//===-- EditlineTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Config.h"
-
-#if LLDB_ENABLE_LIBEDIT
-
-#define EDITLINE_TEST_DUMP_OUTPUT 0
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <memory>
-#include <thread>
-
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/Editline.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Pipe.h"
-#include "lldb/Host/PseudoTerminal.h"
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/StringList.h"
-
-using namespace lldb_private;
-
-namespace {
-const size_t TIMEOUT_MILLIS = 5000;
-}
-
-class FilePointer {
-public:
- FilePointer() = delete;
-
- FilePointer(const FilePointer &) = delete;
-
- FilePointer(FILE *file_p) : _file_p(file_p) {}
-
- ~FilePointer() {
- if (_file_p != nullptr) {
- const int close_result = fclose(_file_p);
- EXPECT_EQ(0, close_result);
- }
- }
-
- operator FILE *() { return _file_p; }
-
-private:
- FILE *_file_p;
-};
-
-/**
- Wraps an Editline class, providing a simple way to feed
- input (as if from the keyboard) and receive output from Editline.
- */
-class EditlineAdapter {
-public:
- EditlineAdapter();
-
- void CloseInput();
-
- bool IsValid() const { return _editline_sp != nullptr; }
-
- lldb_private::Editline &GetEditline() { return *_editline_sp; }
-
- bool SendLine(const std::string &line);
-
- bool SendLines(const std::vector<std::string> &lines);
-
- bool GetLine(std::string &line, bool &interrupted, size_t timeout_millis);
-
- bool GetLines(lldb_private::StringList &lines, bool &interrupted,
- size_t timeout_millis);
-
- void ConsumeAllOutput();
-
-private:
- bool IsInputComplete(lldb_private::Editline *editline,
- lldb_private::StringList &lines);
-
- std::unique_ptr<lldb_private::Editline> _editline_sp;
-
- PseudoTerminal _pty;
- int _pty_master_fd;
- int _pty_secondary_fd;
-
- std::unique_ptr<FilePointer> _el_secondary_file;
-};
-
-EditlineAdapter::EditlineAdapter()
- : _editline_sp(), _pty(), _pty_master_fd(-1), _pty_secondary_fd(-1),
- _el_secondary_file() {
- lldb_private::Status error;
-
- // Open the first master pty available.
- EXPECT_THAT_ERROR(_pty.OpenFirstAvailablePrimary(O_RDWR), llvm::Succeeded());
-
- // Grab the master fd. This is a file descriptor we will:
- // (1) write to when we want to send input to editline.
- // (2) read from when we want to see what editline sends back.
- _pty_master_fd = _pty.GetPrimaryFileDescriptor();
-
- // Open the corresponding secondary pty.
- EXPECT_THAT_ERROR(_pty.OpenSecondary(O_RDWR), llvm::Succeeded());
- _pty_secondary_fd = _pty.GetSecondaryFileDescriptor();
-
- _el_secondary_file.reset(new FilePointer(fdopen(_pty_secondary_fd, "rw")));
- EXPECT_FALSE(nullptr == *_el_secondary_file);
- if (*_el_secondary_file == nullptr)
- return;
-
- // Create an Editline instance.
- _editline_sp.reset(new lldb_private::Editline(
- "gtest editor", *_el_secondary_file, *_el_secondary_file,
- *_el_secondary_file, false));
- _editline_sp->SetPrompt("> ");
-
- // Hookup our input complete callback.
- auto input_complete_cb = [this](Editline *editline, StringList &lines) {
- return this->IsInputComplete(editline, lines);
- };
- _editline_sp->SetIsInputCompleteCallback(input_complete_cb);
-}
-
-void EditlineAdapter::CloseInput() {
- if (_el_secondary_file != nullptr)
- _el_secondary_file.reset(nullptr);
-}
-
-bool EditlineAdapter::SendLine(const std::string &line) {
- // Ensure we're valid before proceeding.
- if (!IsValid())
- return false;
-
- // Write the line out to the pipe connected to editline's input.
- ssize_t input_bytes_written =
- ::write(_pty_master_fd, line.c_str(),
- line.length() * sizeof(std::string::value_type));
-
- const char *eoln = "\n";
- const size_t eoln_length = strlen(eoln);
- input_bytes_written =
- ::write(_pty_master_fd, eoln, eoln_length * sizeof(char));
-
- EXPECT_NE(-1, input_bytes_written) << strerror(errno);
- EXPECT_EQ(eoln_length * sizeof(char), size_t(input_bytes_written));
- return eoln_length * sizeof(char) == size_t(input_bytes_written);
-}
-
-bool EditlineAdapter::SendLines(const std::vector<std::string> &lines) {
- for (auto &line : lines) {
-#if EDITLINE_TEST_DUMP_OUTPUT
- printf("<stdin> sending line \"%s\"\n", line.c_str());
-#endif
- if (!SendLine(line))
- return false;
- }
- return true;
-}
-
-// We ignore the timeout for now.
-bool EditlineAdapter::GetLine(std::string &line, bool &interrupted,
- size_t /* timeout_millis */) {
- // Ensure we're valid before proceeding.
- if (!IsValid())
- return false;
-
- _editline_sp->GetLine(line, interrupted);
- return true;
-}
-
-bool EditlineAdapter::GetLines(lldb_private::StringList &lines,
- bool &interrupted, size_t /* timeout_millis */) {
- // Ensure we're valid before proceeding.
- if (!IsValid())
- return false;
-
- _editline_sp->GetLines(1, lines, interrupted);
- return true;
-}
-
-bool EditlineAdapter::IsInputComplete(lldb_private::Editline *editline,
- lldb_private::StringList &lines) {
- // We'll call ourselves complete if we've received a balanced set of braces.
- int start_block_count = 0;
- int brace_balance = 0;
-
- for (const std::string &line : lines) {
- for (auto ch : line) {
- if (ch == '{') {
- ++start_block_count;
- ++brace_balance;
- } else if (ch == '}')
- --brace_balance;
- }
- }
-
- return (start_block_count > 0) && (brace_balance == 0);
-}
-
-void EditlineAdapter::ConsumeAllOutput() {
- FilePointer output_file(fdopen(_pty_master_fd, "r"));
-
- int ch;
- while ((ch = fgetc(output_file)) != EOF) {
-#if EDITLINE_TEST_DUMP_OUTPUT
- char display_str[] = {0, 0, 0};
- switch (ch) {
- case '\t':
- display_str[0] = '\\';
- display_str[1] = 't';
- break;
- case '\n':
- display_str[0] = '\\';
- display_str[1] = 'n';
- break;
- case '\r':
- display_str[0] = '\\';
- display_str[1] = 'r';
- break;
- default:
- display_str[0] = ch;
- break;
- }
- printf("<stdout> 0x%02x (%03d) (%s)\n", ch, ch, display_str);
-// putc(ch, stdout);
-#endif
- }
-}
-
-class EditlineTestFixture : public ::testing::Test {
- SubsystemRAII<FileSystem> subsystems;
- EditlineAdapter _el_adapter;
- std::shared_ptr<std::thread> _sp_output_thread;
-
-public:
- static void SetUpTestCase() {
- // We need a TERM set properly for editline to work as expected.
- setenv("TERM", "vt100", 1);
- }
-
- void SetUp() override {
- // Validate the editline adapter.
- EXPECT_TRUE(_el_adapter.IsValid());
- if (!_el_adapter.IsValid())
- return;
-
- // Dump output.
- _sp_output_thread =
- std::make_shared<std::thread>([&] { _el_adapter.ConsumeAllOutput(); });
- }
-
- void TearDown() override {
- _el_adapter.CloseInput();
- if (_sp_output_thread)
- _sp_output_thread->join();
- }
-
- EditlineAdapter &GetEditlineAdapter() { return _el_adapter; }
-};
-
-TEST_F(EditlineTestFixture, EditlineReceivesSingleLineText) {
- // Send it some text via our virtual keyboard.
- const std::string input_text("Hello, world");
- EXPECT_TRUE(GetEditlineAdapter().SendLine(input_text));
-
- // Verify editline sees what we put in.
- std::string el_reported_line;
- bool input_interrupted = false;
- const bool received_line = GetEditlineAdapter().GetLine(
- el_reported_line, input_interrupted, TIMEOUT_MILLIS);
-
- EXPECT_TRUE(received_line);
- EXPECT_FALSE(input_interrupted);
- EXPECT_EQ(input_text, el_reported_line);
-}
-
-TEST_F(EditlineTestFixture, EditlineReceivesMultiLineText) {
- // Send it some text via our virtual keyboard.
- std::vector<std::string> input_lines;
- input_lines.push_back("int foo()");
- input_lines.push_back("{");
- input_lines.push_back("printf(\"Hello, world\");");
- input_lines.push_back("}");
- input_lines.push_back("");
-
- EXPECT_TRUE(GetEditlineAdapter().SendLines(input_lines));
-
- // Verify editline sees what we put in.
- lldb_private::StringList el_reported_lines;
- bool input_interrupted = false;
-
- EXPECT_TRUE(GetEditlineAdapter().GetLines(el_reported_lines,
- input_interrupted, TIMEOUT_MILLIS));
- EXPECT_FALSE(input_interrupted);
-
- // Without any auto indentation support, our output should directly match our
- // input.
- std::vector<std::string> reported_lines;
- for (const std::string &line : el_reported_lines)
- reported_lines.push_back(line);
-
- EXPECT_THAT(reported_lines, testing::ContainerEq(input_lines));
-}
-
-#endif
+++ /dev/null
-add_lldb_unittest(ExpressionTests
- ClangParserTest.cpp
- ClangExpressionDeclMapTest.cpp
- DiagnosticManagerTest.cpp
- DWARFExpressionTest.cpp
- CppModuleConfigurationTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbPluginObjectFileELF
- lldbPluginPlatformLinux
- lldbPluginExpressionParserClang
- lldbPluginTypeSystemClang
- lldbUtility
- lldbUtilityHelpers
- lldbSymbolHelpers
- LLVMTestingSupport
- )
+++ /dev/null
-//===-- ClangExpressionDeclMapTest.cpp ------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
-#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/Symbol/ClangTestUtils.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/lldb-defines.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-namespace {
-struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap {
- FakeClangExpressionDeclMap(const std::shared_ptr<ClangASTImporter> &importer)
- : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer,
- nullptr) {
- m_scratch_context = clang_utils::createAST();
- }
- std::unique_ptr<TypeSystemClang> m_scratch_context;
- /// Adds a persistent decl that can be found by the ClangExpressionDeclMap
- /// via GetPersistentDecl.
- void AddPersistentDeclForTest(clang::NamedDecl *d) {
- // The declaration needs to have '$' prefix in its name like every
- // persistent declaration and must be inside the scratch AST context.
- assert(d);
- assert(d->getName().startswith("$"));
- assert(&d->getASTContext() == &m_scratch_context->getASTContext());
- m_persistent_decls[d->getName()] = d;
- }
-
-protected:
- // ClangExpressionDeclMap hooks.
-
- clang::NamedDecl *GetPersistentDecl(ConstString name) override {
- // ClangExpressionDeclMap wants to know if there is a persistent decl
- // with the given name. Check the
- return m_persistent_decls.lookup(name.GetStringRef());
- }
-
-private:
- /// The persistent decls in this test with their names as keys.
- llvm::DenseMap<llvm::StringRef, clang::NamedDecl *> m_persistent_decls;
-};
-} // namespace
-
-namespace {
-struct ClangExpressionDeclMapTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-
- /// The ClangASTImporter used during the test.
- std::shared_ptr<ClangASTImporter> importer;
- /// The ExpressionDeclMap for the current test case.
- std::unique_ptr<FakeClangExpressionDeclMap> decl_map;
-
- /// The target AST that lookup results should be imported to.
- std::unique_ptr<TypeSystemClang> target_ast;
-
- void SetUp() override {
- importer = std::make_shared<ClangASTImporter>();
- decl_map = std::make_unique<FakeClangExpressionDeclMap>(importer);
- target_ast = clang_utils::createAST();
- decl_map->InstallASTContext(*target_ast);
- }
-
- void TearDown() override {
- importer.reset();
- decl_map.reset();
- target_ast.reset();
- }
-};
-} // namespace
-
-TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
- // Tests looking up an identifier that can't be found anywhere.
-
- // Setup a NameSearchContext for 'foo'.
- llvm::SmallVector<clang::NamedDecl *, 16> decls;
- clang::DeclarationName name =
- clang_utils::getDeclarationName(*target_ast, "foo");
- const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
- NameSearchContext search(*target_ast, decls, name, dc);
-
- decl_map->FindExternalVisibleDecls(search);
-
- // This shouldn't exist so we should get no lookups.
- EXPECT_EQ(0U, decls.size());
-}
-
-TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
- // Tests looking up a persistent decl from the scratch AST context.
-
- // Create a '$persistent_class' record and add it as a persistent variable
- // to the scratch AST context.
- llvm::StringRef decl_name = "$persistent_class";
- CompilerType persistent_type =
- clang_utils::createRecord(*decl_map->m_scratch_context, decl_name);
- decl_map->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type));
-
- // Setup a NameSearchContext for $persistent_class;
- llvm::SmallVector<clang::NamedDecl *, 16> decls;
- clang::DeclarationName name =
- clang_utils::getDeclarationName(*target_ast, decl_name);
- const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
- NameSearchContext search(*target_ast, decls, name, dc);
-
- // Search and check that we found $persistent_class.
- decl_map->FindExternalVisibleDecls(search);
- EXPECT_EQ(1U, decls.size());
- EXPECT_EQ(decl_name, decls.front()->getQualifiedNameAsString());
- auto *record = llvm::cast<clang::RecordDecl>(decls.front());
- // The class was minimally imported from the scratch AST context.
- EXPECT_TRUE(record->hasExternalLexicalStorage());
-}
+++ /dev/null
-//===-- ClangParserTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/Version.h"
-
-#include "Plugins/ExpressionParser/Clang/ClangHost.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Host/Config.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/lldb-defines.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-struct ClangHostTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-};
-} // namespace
-
-static std::string ComputeClangResourceDir(std::string lldb_shlib_path,
- bool verify = false) {
- FileSpec clang_dir;
- FileSpec lldb_shlib_spec(lldb_shlib_path);
- ComputeClangResourceDirectory(lldb_shlib_spec, clang_dir, verify);
- return clang_dir.GetPath();
-}
-
-TEST_F(ClangHostTest, ComputeClangResourceDirectory) {
-#if !defined(_WIN32)
- std::string path_to_liblldb = "/foo/bar/lib/";
- std::string path_to_clang_dir = "/foo/bar/lib" LLDB_LIBDIR_SUFFIX "/clang/" CLANG_VERSION_STRING;
-#else
- std::string path_to_liblldb = "C:\\foo\\bar\\lib";
- std::string path_to_clang_dir = "C:\\foo\\bar\\lib\\clang\\" CLANG_VERSION_STRING;
-#endif
- EXPECT_EQ(ComputeClangResourceDir(path_to_liblldb), path_to_clang_dir);
-
- // The path doesn't really exist, so setting verify to true should make
- // ComputeClangResourceDir not give you path_to_clang_dir.
- EXPECT_NE(ComputeClangResourceDir(path_to_liblldb, true), path_to_clang_dir);
-}
-
-#if defined(__APPLE__)
-TEST_F(ClangHostTest, MacOSX) {
- // This returns whatever the POSIX fallback returns.
- std::string posix = "/usr/lib/liblldb.dylib";
- EXPECT_FALSE(ComputeClangResourceDir(posix).empty());
-
- std::string build =
- "/lldb-macosx-x86_64/Library/Frameworks/LLDB.framework/Versions/A";
- std::string build_clang =
- "/lldb-macosx-x86_64/Library/Frameworks/LLDB.framework/Resources/Clang";
- EXPECT_EQ(ComputeClangResourceDir(build), build_clang);
-
- std::string xcode = "/Applications/Xcode.app/Contents/SharedFrameworks/"
- "LLDB.framework/Versions/A";
- std::string xcode_clang =
- "/Applications/Xcode.app/Contents/Developer/Toolchains/"
- "XcodeDefault.xctoolchain/usr/lib/swift/clang";
- EXPECT_EQ(ComputeClangResourceDir(xcode), xcode_clang);
-
- std::string toolchain =
- "/Applications/Xcode.app/Contents/Developer/Toolchains/"
- "Swift-4.1-development-snapshot.xctoolchain/System/Library/"
- "PrivateFrameworks/LLDB.framework";
- std::string toolchain_clang =
- "/Applications/Xcode.app/Contents/Developer/Toolchains/"
- "Swift-4.1-development-snapshot.xctoolchain/usr/lib/swift/clang";
- EXPECT_EQ(ComputeClangResourceDir(toolchain), toolchain_clang);
-
- std::string cltools = "/Library/Developer/CommandLineTools/Library/"
- "PrivateFrameworks/LLDB.framework";
- std::string cltools_clang =
- "/Library/Developer/CommandLineTools/Library/PrivateFrameworks/"
- "LLDB.framework/Resources/Clang";
- EXPECT_EQ(ComputeClangResourceDir(cltools), cltools_clang);
-
- // Test that a bogus path is detected.
- EXPECT_NE(ComputeClangResourceDir(GetInputFilePath(xcode), true),
- ComputeClangResourceDir(GetInputFilePath(xcode)));
-}
-#endif // __APPLE__
+++ /dev/null
-//===-- CppModuleConfigurationTest.cpp ------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ExpressionParser/Clang/CppModuleConfiguration.h"
-#include "Plugins/ExpressionParser/Clang/ClangHost.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "llvm/Support/SmallVectorMemoryBuffer.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-struct CppModuleConfigurationTest : public testing::Test {
- llvm::MemoryBufferRef m_empty_buffer;
- llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> m_fs;
-
- CppModuleConfigurationTest()
- : m_empty_buffer("", "<empty buffer>"),
- m_fs(new llvm::vfs::InMemoryFileSystem()) {}
-
- void SetUp() override {
- FileSystem::Initialize(m_fs);
- HostInfo::Initialize();
- }
-
- void TearDown() override {
- HostInfo::Terminate();
- FileSystem::Terminate();
- }
-
- /// Utility function turning a list of paths into a FileSpecList.
- FileSpecList makeFiles(llvm::ArrayRef<std::string> paths) {
- FileSpecList result;
- for (const std::string &path : paths) {
- result.Append(FileSpec(path, FileSpec::Style::posix));
- if (!m_fs->addFileNoOwn(path, static_cast<time_t>(0), m_empty_buffer))
- llvm_unreachable("Invalid test configuration?");
- }
- return result;
- }
-};
-} // namespace
-
-/// Returns the Clang resource include directory.
-static std::string ResourceInc() {
- llvm::SmallString<256> resource_dir;
- llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(),
- "include");
- return std::string(resource_dir);
-}
-
-
-TEST_F(CppModuleConfigurationTest, Linux) {
- // Test the average Linux configuration.
-
- std::string usr = "/usr/include";
- std::string libcpp = "/usr/include/c++/v1";
- std::vector<std::string> files = {// C library
- usr + "/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre(libcpp, ResourceInc(), usr));
-}
-
-TEST_F(CppModuleConfigurationTest, Sysroot) {
- // Test that having a sysroot for the whole system works fine.
-
- std::string libcpp = "/home/user/sysroot/usr/include/c++/v1";
- std::string usr = "/home/user/sysroot/usr/include";
- std::vector<std::string> files = {// C library
- usr + "/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre(libcpp, ResourceInc(), usr));
-}
-
-TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) {
- // Test that a locally build libc++ is detected.
-
- std::string usr = "/usr/include";
- std::string libcpp = "/home/user/llvm-build/include/c++/v1";
- std::vector<std::string> files = {// C library
- usr + "/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre(libcpp, ResourceInc(), usr));
-}
-
-TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) {
- // Test that having an unrelated library in /usr/include doesn't break.
-
- std::string usr = "/usr/include";
- std::string libcpp = "/home/user/llvm-build/include/c++/v1";
- std::vector<std::string> files = {// C library
- usr + "/stdio.h",
- // unrelated library
- usr + "/boost/vector",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre(libcpp, ResourceInc(), usr));
-}
-
-TEST_F(CppModuleConfigurationTest, Xcode) {
- // Test detection of libc++ coming from Xcode with generic platform names.
-
- std::string p = "/Applications/Xcode.app/Contents/Developer/";
- std::string libcpp = p + "Toolchains/B.xctoolchain/usr/include/c++/v1";
- std::string usr =
- p + "Platforms/A.platform/Developer/SDKs/OSVers.sdk/usr/include";
- std::vector<std::string> files = {
- // C library
- usr + "/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap",
- };
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre(libcpp, ResourceInc(), usr));
-}
-
-TEST_F(CppModuleConfigurationTest, LibCppV2) {
- // Test that a "v2" of libc++ is still correctly detected.
-
- std::string libcpp = "/usr/include/c++/v2";
- std::vector<std::string> files = {// C library
- "/usr/include/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre("/usr/include/c++/v2", ResourceInc(),
- "/usr/include"));
-}
-
-TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) {
- // Test that having some unknown file in the libc++ path doesn't break
- // anything.
-
- std::string libcpp = "/usr/include/c++/v1";
- std::vector<std::string> files = {// C library
- "/usr/include/stdio.h",
- // C++ library
- libcpp + "/non_existing_file",
- libcpp + "/module.modulemap",
- libcpp + "/vector"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
- EXPECT_THAT(config.GetIncludeDirs(),
- testing::ElementsAre("/usr/include/c++/v1", ResourceInc(),
- "/usr/include"));
-}
-
-TEST_F(CppModuleConfigurationTest, MissingUsrInclude) {
- // Test that we don't load 'std' if we can't find the C standard library.
-
- std::string libcpp = "/usr/include/c++/v1";
- std::vector<std::string> files = {// C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap"};
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
- EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
-}
-
-TEST_F(CppModuleConfigurationTest, MissingLibCpp) {
- // Test that we don't load 'std' if we don't have a libc++.
-
- std::string usr = "/usr/include";
- std::vector<std::string> files = {
- // C library
- usr + "/stdio.h",
- };
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
- EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
-}
-
-TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) {
- // Test that we don't do anything bad when we encounter libstdc++ paths.
-
- std::string usr = "/usr/include";
- std::vector<std::string> files = {
- // C library
- usr + "/stdio.h",
- // C++ library
- usr + "/c++/8.0.1/vector",
- };
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
- EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
-}
-
-TEST_F(CppModuleConfigurationTest, AmbiguousCLib) {
- // Test that we don't do anything when we are not sure where the
- // right C standard library is.
-
- std::string usr1 = "/usr/include";
- std::string usr2 = "/usr/include/other/path";
- std::string libcpp = usr1 + "c++/v1";
- std::vector<std::string> files = {
- // First C library
- usr1 + "/stdio.h",
- // Second C library
- usr2 + "/stdio.h",
- // C++ library
- libcpp + "/vector",
- libcpp + "/module.modulemap",
- };
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
- EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
-}
-
-TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) {
- // Test that we don't do anything when we are not sure where the
- // right libc++ is.
-
- std::string usr = "/usr/include";
- std::string libcpp1 = usr + "c++/v1";
- std::string libcpp2 = usr + "c++/v2";
- std::vector<std::string> files = {
- // C library
- usr + "/stdio.h",
- // First C++ library
- libcpp1 + "/vector",
- libcpp1 + "/module.modulemap",
- // Second C++ library
- libcpp2 + "/vector",
- libcpp2 + "/module.modulemap",
- };
- CppModuleConfiguration config(makeFiles(files));
- EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
- EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
-}
+++ /dev/null
-//===-- DWARFExpressionTest.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Expression/DWARFExpression.h"
-#include "Plugins/Platform/Linux/PlatformLinux.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "lldb/Core/Value.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/dwarf.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr,
- lldb::ModuleSP module_sp = {},
- DWARFUnit *unit = nullptr,
- ExecutionContext *exe_ctx = nullptr) {
- DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
- /*addr_size*/ 4);
- Value result;
- Status status;
- if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp,
- extractor, unit, lldb::eRegisterKindLLDB,
- /*initial_value_ptr*/ nullptr,
- /*object_address_ptr*/ nullptr, result,
- &status))
- return status.ToError();
-
- switch (result.GetValueType()) {
- case Value::ValueType::Scalar:
- return result.GetScalar();
- case Value::ValueType::LoadAddress:
- return LLDB_INVALID_ADDRESS;
- case Value::ValueType::HostAddress: {
- // Convert small buffers to scalars to simplify the tests.
- DataBufferHeap &buf = result.GetBuffer();
- if (buf.GetByteSize() <= 8) {
- uint64_t val = 0;
- memcpy(&val, buf.GetBytes(), buf.GetByteSize());
- return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false));
- }
- }
- LLVM_FALLTHROUGH;
- default:
- return status.ToError();
- }
-}
-
-class DWARFExpressionTester : public YAMLModuleTester {
-public:
- using YAMLModuleTester::YAMLModuleTester;
- llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) {
- return ::Evaluate(expr, m_module_sp, m_dwarf_unit);
- }
-};
-
-/// Unfortunately Scalar's operator==() is really picky.
-static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) {
- Scalar scalar(value);
- scalar.TruncOrExtendTo(bits, sign);
- return scalar;
-}
-
-/// This is needed for the tests that use a mock process.
-class DWARFExpressionMockProcessTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(repro::Reproducer::Initialize(repro::ReproducerMode::Off, {}));
- FileSystem::Initialize();
- HostInfo::Initialize();
- platform_linux::PlatformLinux::Initialize();
- }
- void TearDown() override {
- platform_linux::PlatformLinux::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- repro::Reproducer::Terminate();
- }
-};
-
-TEST(DWARFExpression, DW_OP_pick) {
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}),
- llvm::HasValue(0));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}),
- llvm::HasValue(1));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}),
- llvm::Failed());
-}
-
-TEST(DWARFExpression, DW_OP_const) {
- // Extend to address size.
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}),
- llvm::HasValue(0xffffff88));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}),
- llvm::HasValue(0x8847));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}),
- llvm::HasValue(0xffff8847));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}),
- llvm::HasValue(0x88474244));
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}),
- llvm::HasValue(0x88474244));
-
- // Truncate to address size.
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
- llvm::HasValue(0x33221100));
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
- llvm::HasValue(0x33221100));
-
- // Don't truncate to address size for compatibility with clang (pr48087).
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
- llvm::HasValue(0x01010101010101));
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
- llvm::HasValue(0xffff010101010101));
-}
-
-TEST(DWARFExpression, DW_OP_convert) {
- /// Auxiliary debug info.
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- - Code: 0x00000002
- Tag: DW_TAG_base_type
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_encoding
- Form: DW_FORM_data1
- - Attribute: DW_AT_byte_size
- Form: DW_FORM_data1
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x000000000000000C
- # 0x0000000e:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000004
- # 0x00000011:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000008
- # 0x00000014:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000005 # DW_ATE_signed
- - Value: 0x0000000000000008
- # 0x00000017:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000008 # DW_ATE_unsigned_char
- - Value: 0x0000000000000001
- # 0x0000001a:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000006 # DW_ATE_signed_char
- - Value: 0x0000000000000001
- # 0x0000001d:
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x000000000000000b # DW_ATE_numeric_string
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000000
-)";
- uint8_t offs_uint32_t = 0x0000000e;
- uint8_t offs_uint64_t = 0x00000011;
- uint8_t offs_sint64_t = 0x00000014;
- uint8_t offs_uchar = 0x00000017;
- uint8_t offs_schar = 0x0000001a;
-
- DWARFExpressionTester t(yamldata);
- ASSERT_TRUE((bool)t.GetDwarfUnit());
-
- // Constant is given as little-endian.
- bool is_signed = true;
- bool not_signed = false;
-
- //
- // Positive tests.
- //
-
- // Leave as is.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
- DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
-
- // Zero-extend to 64 bits.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
- DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
-
- // Sign-extend to 64 bits.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
- DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed)));
-
- // Sign-extend, then truncate.
- EXPECT_THAT_EXPECTED(
- t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
- DW_OP_convert, offs_sint64_t, //
- DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
-
- // Truncate to default unspecified (pointer-sized) type.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
- DW_OP_convert, offs_sint64_t, //
- DW_OP_convert, 0x00, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
-
- // Truncate to 8 bits.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
- offs_uchar, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(8, 'A', not_signed)));
-
- // Also truncate to 8 bits.
- EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
- offs_schar, DW_OP_stack_value}),
- llvm::HasValue(GetScalar(8, 'A', is_signed)));
-
- //
- // Errors.
- //
-
- // No Module.
- EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr,
- t.GetDwarfUnit())
- .takeError(),
- llvm::Failed());
-
- // No DIE.
- EXPECT_THAT_ERROR(
- t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(),
- llvm::Failed());
-
- // Unsupported.
- EXPECT_THAT_ERROR(
- t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(),
- llvm::Failed());
-}
-
-TEST(DWARFExpression, DW_OP_stack_value) {
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
-}
-
-TEST(DWARFExpression, DW_OP_piece) {
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,
- DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),
- llvm::HasValue(GetScalar(32, 0x44332211, true)));
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}),
- // Note that the "00" should really be "undef", but we can't
- // represent that yet.
- llvm::HasValue(GetScalar(16, 0xff00, true)));
-}
-
-TEST(DWARFExpression, DW_OP_implicit_value) {
- unsigned char bytes = 4;
-
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),
- llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true)));
-}
-
-TEST(DWARFExpression, DW_OP_unknown) {
- EXPECT_THAT_EXPECTED(
- Evaluate({0xff}),
- llvm::FailedWithMessage(
- "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
-}
-
-TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
-
- struct MockProcess : Process {
- using Process::Process;
- ConstString GetPluginName() override { return ConstString("mock process"); }
- uint32_t GetPluginVersion() override { return 0; }
- bool CanDebug(lldb::TargetSP target,
- bool plugin_specified_by_name) override {
- return false;
- };
- Status DoDestroy() override { return {}; }
- void RefreshStateAfterStop() override {}
- bool DoUpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override {
- return false;
- };
- size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Status &error) override {
- for (size_t i = 0; i < size; ++i)
- ((char *)buf)[i] = (vm_addr + i) & 0xff;
- error.Clear();
- return size;
- }
- };
-
- // Set up a mock process.
- ArchSpec arch("i386-pc-linux");
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
- lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
- lldb::TargetSP target_sp;
- lldb::PlatformSP platform_sp;
- debugger_sp->GetTargetList().CreateTarget(
- *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
- ASSERT_TRUE(target_sp);
- ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
- ASSERT_TRUE(platform_sp);
- lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
- lldb::ProcessSP process_sp =
- std::make_shared<MockProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- ExecutionContext exe_ctx(process_sp);
- // Implicit location: *0x4.
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value},
- {}, {}, &exe_ctx),
- llvm::HasValue(GetScalar(32, 0x07060504, false)));
- // Memory location: *(*0x4).
- // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
- llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS)));
- // Memory location: *0x4.
- // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
- EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),
- llvm::HasValue(Scalar(4)));
- // Implicit location: *0x4.
- // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
- EXPECT_THAT_EXPECTED(
- Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),
- llvm::HasValue(GetScalar(32, 0x07060504, false)));
-}
+++ /dev/null
-//===-- DiagnosticManagerTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Expression/DiagnosticManager.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-static const uint32_t custom_diag_id = 42;
-
-namespace {
-class FixItDiag : public Diagnostic {
- bool m_has_fixits;
-
-public:
- FixItDiag(llvm::StringRef msg, bool has_fixits)
- : Diagnostic(msg, DiagnosticSeverity::eDiagnosticSeverityError,
- DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id),
- m_has_fixits(has_fixits) {}
- bool HasFixIts() const override { return m_has_fixits; }
-};
-} // namespace
-
-namespace {
-class TextDiag : public Diagnostic {
-public:
- TextDiag(llvm::StringRef msg, DiagnosticSeverity severity)
- : Diagnostic(msg, severity, DiagnosticOrigin::eDiagnosticOriginLLDB,
- custom_diag_id) {}
-};
-} // namespace
-
-TEST(DiagnosticManagerTest, AddDiagnostic) {
- DiagnosticManager mgr;
- EXPECT_EQ(0U, mgr.Diagnostics().size());
-
- std::string msg = "foo bar has happened";
- DiagnosticSeverity severity = DiagnosticSeverity::eDiagnosticSeverityError;
- DiagnosticOrigin origin = DiagnosticOrigin::eDiagnosticOriginLLDB;
- auto diag =
- std::make_unique<Diagnostic>(msg, severity, origin, custom_diag_id);
- mgr.AddDiagnostic(std::move(diag));
- EXPECT_EQ(1U, mgr.Diagnostics().size());
- const Diagnostic *got = mgr.Diagnostics().front().get();
- EXPECT_EQ(DiagnosticOrigin::eDiagnosticOriginLLDB, got->getKind());
- EXPECT_EQ(msg, got->GetMessage());
- EXPECT_EQ(severity, got->GetSeverity());
- EXPECT_EQ(custom_diag_id, got->GetCompilerID());
- EXPECT_EQ(false, got->HasFixIts());
-}
-
-TEST(DiagnosticManagerTest, HasFixits) {
- DiagnosticManager mgr;
- // By default we shouldn't have any fixits.
- EXPECT_FALSE(mgr.HasFixIts());
- // Adding a diag without fixits shouldn't make HasFixIts return true.
- mgr.AddDiagnostic(std::make_unique<FixItDiag>("no fixit", false));
- EXPECT_FALSE(mgr.HasFixIts());
- // Adding a diag with fixits will mark the manager as containing fixits.
- mgr.AddDiagnostic(std::make_unique<FixItDiag>("fixit", true));
- EXPECT_TRUE(mgr.HasFixIts());
- // Adding another diag without fixit shouldn't make it return false.
- mgr.AddDiagnostic(std::make_unique<FixItDiag>("no fixit", false));
- EXPECT_TRUE(mgr.HasFixIts());
- // Adding a diag with fixits. The manager should still return true.
- mgr.AddDiagnostic(std::make_unique<FixItDiag>("fixit", true));
- EXPECT_TRUE(mgr.HasFixIts());
-}
-
-TEST(DiagnosticManagerTest, GetStringNoDiags) {
- DiagnosticManager mgr;
- EXPECT_EQ("", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, GetStringBasic) {
- DiagnosticManager mgr;
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("abc", eDiagnosticSeverityError));
- EXPECT_EQ("error: abc\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, GetStringMultiline) {
- DiagnosticManager mgr;
-
- // Multiline diagnostics should only get one severity label.
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("b\nc", eDiagnosticSeverityError));
- EXPECT_EQ("error: b\nc\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, GetStringMultipleDiags) {
- DiagnosticManager mgr;
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("abc", eDiagnosticSeverityError));
- EXPECT_EQ("error: abc\n", mgr.GetString());
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("def", eDiagnosticSeverityError));
- EXPECT_EQ("error: abc\nerror: def\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, GetStringSeverityLabels) {
- DiagnosticManager mgr;
-
- // Different severities should cause different labels.
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("foo", eDiagnosticSeverityError));
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("bar", eDiagnosticSeverityWarning));
- // Remarks have no labels.
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("baz", eDiagnosticSeverityRemark));
- EXPECT_EQ("error: foo\nwarning: bar\nbaz\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, GetStringPreserveOrder) {
- DiagnosticManager mgr;
-
- // Make sure we preserve the diagnostic order and do not sort them in any way.
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("baz", eDiagnosticSeverityRemark));
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("bar", eDiagnosticSeverityWarning));
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("foo", eDiagnosticSeverityError));
- EXPECT_EQ("baz\nwarning: bar\nerror: foo\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, AppendMessageNoDiag) {
- DiagnosticManager mgr;
-
- // FIXME: This *really* should not just fail silently.
- mgr.AppendMessageToDiagnostic("no diag has been pushed yet");
- EXPECT_EQ(0U, mgr.Diagnostics().size());
-}
-
-TEST(DiagnosticManagerTest, AppendMessageAttachToLastDiag) {
- DiagnosticManager mgr;
-
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("foo", eDiagnosticSeverityError));
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("bar", eDiagnosticSeverityError));
- // This should append to 'bar' and not to 'foo'.
- mgr.AppendMessageToDiagnostic("message text");
-
- EXPECT_EQ("error: foo\nerror: bar\nmessage text\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, AppendMessageSubsequentDiags) {
- DiagnosticManager mgr;
-
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("bar", eDiagnosticSeverityError));
- mgr.AppendMessageToDiagnostic("message text");
- // Pushing another diag after the message should work fine.
- mgr.AddDiagnostic(
- std::make_unique<TextDiag>("foo", eDiagnosticSeverityError));
-
- EXPECT_EQ("error: bar\nmessage text\nerror: foo\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, PutString) {
- DiagnosticManager mgr;
-
- mgr.PutString(eDiagnosticSeverityError, "foo");
- EXPECT_EQ(1U, mgr.Diagnostics().size());
- EXPECT_EQ(eDiagnosticOriginLLDB, mgr.Diagnostics().front()->getKind());
- EXPECT_EQ("error: foo\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, PutStringMultiple) {
- DiagnosticManager mgr;
-
- // Multiple PutString should behave like multiple diagnostics.
- mgr.PutString(eDiagnosticSeverityError, "foo");
- mgr.PutString(eDiagnosticSeverityError, "bar");
- EXPECT_EQ(2U, mgr.Diagnostics().size());
- EXPECT_EQ("error: foo\nerror: bar\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, PutStringSeverities) {
- DiagnosticManager mgr;
-
- // Multiple PutString with different severities should behave like we
- // created multiple diagnostics.
- mgr.PutString(eDiagnosticSeverityError, "foo");
- mgr.PutString(eDiagnosticSeverityWarning, "bar");
- EXPECT_EQ(2U, mgr.Diagnostics().size());
- EXPECT_EQ("error: foo\nwarning: bar\n", mgr.GetString());
-}
-
-TEST(DiagnosticManagerTest, FixedExpression) {
- DiagnosticManager mgr;
-
- // By default there should be no fixed expression.
- EXPECT_EQ("", mgr.GetFixedExpression());
-
- // Setting the fixed expression should change it.
- mgr.SetFixedExpression("foo");
- EXPECT_EQ("foo", mgr.GetFixedExpression());
-
- // Setting the fixed expression again should also change it.
- mgr.SetFixedExpression("bar");
- EXPECT_EQ("bar", mgr.GetFixedExpression());
-}
+++ /dev/null
-set (FILES
- ConnectionFileDescriptorTest.cpp
- FileActionTest.cpp
- FileSystemTest.cpp
- FileTest.cpp
- HostInfoTest.cpp
- HostTest.cpp
- MainLoopTest.cpp
- NativeProcessProtocolTest.cpp
- PipeTest.cpp
- ProcessLaunchInfoTest.cpp
- SocketAddressTest.cpp
- SocketTest.cpp
- SocketTestUtilities.cpp
-)
-
-if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
- list(APPEND FILES
- linux/HostTest.cpp
- linux/SupportTest.cpp
- )
-endif()
-
-add_lldb_unittest(HostTests
- ${FILES}
- LINK_LIBS
- lldbHost
- lldbUtilityHelpers
- LLVMTestingSupport
- )
+++ /dev/null
-//===-- ConnectionFileDescriptorTest.cpp ----------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "SocketTestUtilities.h"
-#include "gtest/gtest.h"
-
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
-#include "lldb/Utility/UriParser.h"
-
-using namespace lldb_private;
-
-class ConnectionFileDescriptorTest : public testing::Test {
-public:
- SubsystemRAII<Socket> subsystems;
-
- void TestGetURI(std::string ip) {
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- CreateTCPConnectedSockets(ip, &socket_a_up, &socket_b_up);
- auto socket = socket_a_up.release();
- ConnectionFileDescriptor connection_file_descriptor(socket);
-
- llvm::StringRef scheme;
- llvm::StringRef hostname;
- int port;
- llvm::StringRef path;
- std::string uri(connection_file_descriptor.GetURI());
- EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path));
- EXPECT_EQ(ip, hostname);
- EXPECT_EQ(socket->GetRemotePortNumber(), port);
- }
-};
-
-TEST_F(ConnectionFileDescriptorTest, TCPGetURIv4) {
- if (!HostSupportsIPv4())
- return;
- TestGetURI("127.0.0.1");
-}
-
-TEST_F(ConnectionFileDescriptorTest, TCPGetURIv6) {
- if (!HostSupportsIPv6())
- return;
- TestGetURI("::1");
-}
+++ /dev/null
-//===-- FileActionTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/FileAction.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(FileActionTest, Open) {
- FileAction Action;
- Action.Open(47, FileSpec("/tmp"), /*read*/ true, /*write*/ false);
- EXPECT_EQ(Action.GetAction(), FileAction::eFileActionOpen);
- EXPECT_EQ(Action.GetFileSpec(), FileSpec("/tmp"));
-}
+++ /dev/null
-//===-- FileSystemTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "lldb/Host/FileSystem.h"
-#include "llvm/Support/Errc.h"
-
-extern const char *TestMainArgv0;
-
-using namespace lldb_private;
-using namespace llvm;
-using llvm::sys::fs::UniqueID;
-
-// Modified from llvm/unittests/Support/VirtualFileSystemTest.cpp
-namespace {
-struct DummyFile : public vfs::File {
- vfs::Status S;
- explicit DummyFile(vfs::Status S) : S(S) {}
- llvm::ErrorOr<vfs::Status> status() override { return S; }
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
- getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
- bool IsVolatile) override {
- llvm_unreachable("unimplemented");
- }
- std::error_code close() override { return std::error_code(); }
-};
-
-class DummyFileSystem : public vfs::FileSystem {
- int FSID; // used to produce UniqueIDs
- int FileID; // used to produce UniqueIDs
- std::string cwd;
- std::map<std::string, vfs::Status> FilesAndDirs;
-
- static int getNextFSID() {
- static int Count = 0;
- return Count++;
- }
-
-public:
- DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
-
- ErrorOr<vfs::Status> status(const Twine &Path) override {
- std::map<std::string, vfs::Status>::iterator I =
- FilesAndDirs.find(Path.str());
- if (I == FilesAndDirs.end())
- return make_error_code(llvm::errc::no_such_file_or_directory);
- return I->second;
- }
- ErrorOr<std::unique_ptr<vfs::File>>
- openFileForRead(const Twine &Path) override {
- auto S = status(Path);
- if (S)
- return std::unique_ptr<vfs::File>(new DummyFile{*S});
- return S.getError();
- }
- llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
- return cwd;
- }
- std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
- cwd = Path.str();
- return std::error_code();
- }
- // Map any symlink to "/symlink".
- std::error_code getRealPath(const Twine &Path,
- SmallVectorImpl<char> &Output) const override {
- auto I = FilesAndDirs.find(Path.str());
- if (I == FilesAndDirs.end())
- return make_error_code(llvm::errc::no_such_file_or_directory);
- if (I->second.isSymlink()) {
- Output.clear();
- Twine("/symlink").toVector(Output);
- return std::error_code();
- }
- Output.clear();
- Path.toVector(Output);
- return std::error_code();
- }
-
- struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
- std::map<std::string, vfs::Status> &FilesAndDirs;
- std::map<std::string, vfs::Status>::iterator I;
- std::string Path;
- bool isInPath(StringRef S) {
- if (Path.size() < S.size() && S.find(Path) == 0) {
- auto LastSep = S.find_last_of('/');
- if (LastSep == Path.size() || LastSep == Path.size() - 1)
- return true;
- }
- return false;
- }
- DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
- const Twine &_Path)
- : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
- Path(_Path.str()) {
- for (; I != FilesAndDirs.end(); ++I) {
- if (isInPath(I->first)) {
- CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
- I->second.getType());
- break;
- }
- }
- }
- std::error_code increment() override {
- ++I;
- for (; I != FilesAndDirs.end(); ++I) {
- if (isInPath(I->first)) {
- CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
- I->second.getType());
- break;
- }
- }
- if (I == FilesAndDirs.end())
- CurrentEntry = vfs::directory_entry();
- return std::error_code();
- }
- };
-
- vfs::directory_iterator dir_begin(const Twine &Dir,
- std::error_code &EC) override {
- return vfs::directory_iterator(
- std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
- }
-
- void addEntry(StringRef Path, const vfs::Status &Status) {
- FilesAndDirs[std::string(Path)] = Status;
- }
-
- void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
- vfs::Status S(Path, UniqueID(FSID, FileID++),
- std::chrono::system_clock::now(), 0, 0, 1024,
- sys::fs::file_type::regular_file, Perms);
- addEntry(Path, S);
- }
-
- void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
- vfs::Status S(Path, UniqueID(FSID, FileID++),
- std::chrono::system_clock::now(), 0, 0, 0,
- sys::fs::file_type::directory_file, Perms);
- addEntry(Path, S);
- }
-
- void addSymlink(StringRef Path) {
- vfs::Status S(Path, UniqueID(FSID, FileID++),
- std::chrono::system_clock::now(), 0, 0, 0,
- sys::fs::file_type::symlink_file, sys::fs::all_all);
- addEntry(Path, S);
- }
-};
-} // namespace
-
-TEST(FileSystemTest, FileAndDirectoryComponents) {
- using namespace std::chrono;
- FileSystem fs;
-
-#ifdef _WIN32
- FileSpec fs1("C:\\FILE\\THAT\\DOES\\NOT\\EXIST.TXT");
-#else
- FileSpec fs1("/file/that/does/not/exist.txt");
-#endif
- FileSpec fs2(TestMainArgv0);
-
- fs.Resolve(fs2);
-
- EXPECT_EQ(system_clock::time_point(), fs.GetModificationTime(fs1));
- EXPECT_LT(system_clock::time_point() + hours(24 * 365 * 20),
- fs.GetModificationTime(fs2));
-}
-
-static IntrusiveRefCntPtr<DummyFileSystem> GetSimpleDummyFS() {
- IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
- D->addRegularFile("/foo");
- D->addDirectory("/bar");
- D->addSymlink("/baz");
- D->addRegularFile("/qux", ~sys::fs::perms::all_read);
- D->setCurrentWorkingDirectory("/");
- return D;
-}
-
-TEST(FileSystemTest, Exists) {
- FileSystem fs(GetSimpleDummyFS());
-
- EXPECT_TRUE(fs.Exists("/foo"));
- EXPECT_TRUE(fs.Exists(FileSpec("/foo", FileSpec::Style::posix)));
-}
-
-TEST(FileSystemTest, Readable) {
- FileSystem fs(GetSimpleDummyFS());
-
- EXPECT_TRUE(fs.Readable("/foo"));
- EXPECT_TRUE(fs.Readable(FileSpec("/foo", FileSpec::Style::posix)));
-
- EXPECT_FALSE(fs.Readable("/qux"));
- EXPECT_FALSE(fs.Readable(FileSpec("/qux", FileSpec::Style::posix)));
-}
-
-TEST(FileSystemTest, GetByteSize) {
- FileSystem fs(GetSimpleDummyFS());
-
- EXPECT_EQ((uint64_t)1024, fs.GetByteSize("/foo"));
- EXPECT_EQ((uint64_t)1024,
- fs.GetByteSize(FileSpec("/foo", FileSpec::Style::posix)));
-}
-
-TEST(FileSystemTest, GetPermissions) {
- FileSystem fs(GetSimpleDummyFS());
-
- EXPECT_EQ(sys::fs::all_all, fs.GetPermissions("/foo"));
- EXPECT_EQ(sys::fs::all_all,
- fs.GetPermissions(FileSpec("/foo", FileSpec::Style::posix)));
-}
-
-TEST(FileSystemTest, MakeAbsolute) {
- FileSystem fs(GetSimpleDummyFS());
-
- {
- StringRef foo_relative = "foo";
- SmallString<16> foo(foo_relative);
- auto EC = fs.MakeAbsolute(foo);
- EXPECT_FALSE(EC);
- EXPECT_TRUE(foo.equals("/foo"));
- }
-
- {
- FileSpec file_spec("foo");
- auto EC = fs.MakeAbsolute(file_spec);
- EXPECT_FALSE(EC);
- EXPECT_EQ(FileSpec("/foo"), file_spec);
- }
-}
-
-TEST(FileSystemTest, Resolve) {
- FileSystem fs(GetSimpleDummyFS());
-
- {
- StringRef foo_relative = "foo";
- SmallString<16> foo(foo_relative);
- fs.Resolve(foo);
- EXPECT_TRUE(foo.equals("/foo"));
- }
-
- {
- FileSpec file_spec("foo");
- fs.Resolve(file_spec);
- EXPECT_EQ(FileSpec("/foo"), file_spec);
- }
-
- {
- StringRef foo_relative = "bogus";
- SmallString<16> foo(foo_relative);
- fs.Resolve(foo);
- EXPECT_TRUE(foo.equals("bogus"));
- }
-
- {
- FileSpec file_spec("bogus");
- fs.Resolve(file_spec);
- EXPECT_EQ(FileSpec("bogus"), file_spec);
- }
-}
-
-FileSystem::EnumerateDirectoryResult
-VFSCallback(void *baton, llvm::sys::fs::file_type file_type,
- llvm::StringRef path) {
- auto visited = static_cast<std::vector<std::string> *>(baton);
- visited->push_back(path.str());
- return FileSystem::eEnumerateDirectoryResultNext;
-}
-
-TEST(FileSystemTest, EnumerateDirectory) {
- FileSystem fs(GetSimpleDummyFS());
-
- std::vector<std::string> visited;
-
- constexpr bool find_directories = true;
- constexpr bool find_files = true;
- constexpr bool find_other = true;
-
- fs.EnumerateDirectory("/", find_directories, find_files, find_other,
- VFSCallback, &visited);
-
- EXPECT_THAT(visited,
- testing::UnorderedElementsAre("/foo", "/bar", "/baz", "/qux"));
-}
-
-TEST(FileSystemTest, OpenErrno) {
-#ifdef _WIN32
- FileSpec spec("C:\\FILE\\THAT\\DOES\\NOT\\EXIST.TXT");
-#else
- FileSpec spec("/file/that/does/not/exist.txt");
-#endif
- FileSystem fs;
- auto file = fs.Open(spec, File::eOpenOptionRead, 0, true);
- ASSERT_FALSE(file);
- std::error_code code = errorToErrorCode(file.takeError());
- EXPECT_EQ(code.category(), std::system_category());
- EXPECT_EQ(code.value(), ENOENT);
-}
-
-TEST(FileSystemTest, EmptyTest) {
- FileSpec spec;
- FileSystem fs;
-
- {
- std::error_code ec;
- fs.DirBegin(spec, ec);
- EXPECT_EQ(ec.category(), std::system_category());
- EXPECT_EQ(ec.value(), ENOENT);
- }
-
- {
- llvm::ErrorOr<vfs::Status> status = fs.GetStatus(spec);
- ASSERT_FALSE(status);
- EXPECT_EQ(status.getError().category(), std::system_category());
- EXPECT_EQ(status.getError().value(), ENOENT);
- }
-
- EXPECT_EQ(sys::TimePoint<>(), fs.GetModificationTime(spec));
- EXPECT_EQ(static_cast<uint64_t>(0), fs.GetByteSize(spec));
- EXPECT_EQ(llvm::sys::fs::perms::perms_not_known, fs.GetPermissions(spec));
- EXPECT_FALSE(fs.Exists(spec));
- EXPECT_FALSE(fs.Readable(spec));
- EXPECT_FALSE(fs.IsDirectory(spec));
- EXPECT_FALSE(fs.IsLocal(spec));
-}
+++ /dev/null
-//===-- FileTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/File.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(File, GetWaitableHandleFileno) {
- const auto *Info = testing::UnitTest::GetInstance()->current_test_info();
-
- llvm::SmallString<128> name;
- int fd;
- llvm::sys::fs::createTemporaryFile(llvm::Twine(Info->test_case_name()) + "-" +
- Info->name(),
- "test", fd, name);
- llvm::FileRemover remover(name);
- ASSERT_GE(fd, 0);
-
- FILE *stream = fdopen(fd, "r");
- ASSERT_TRUE(stream);
-
- NativeFile file(stream, true);
- EXPECT_EQ(file.GetWaitableHandle(), fd);
-}
-
-TEST(File, GetStreamFromDescriptor) {
- const auto *Info = testing::UnitTest::GetInstance()->current_test_info();
- llvm::SmallString<128> name;
- int fd;
- llvm::sys::fs::createTemporaryFile(llvm::Twine(Info->test_case_name()) + "-" +
- Info->name(),
- "test", fd, name);
-
- llvm::FileRemover remover(name);
- ASSERT_GE(fd, 0);
-
- NativeFile file(fd, File::eOpenOptionWrite, true);
- ASSERT_TRUE(file.IsValid());
-
- FILE *stream = file.GetStream();
- ASSERT_TRUE(stream != NULL);
-
- EXPECT_EQ(file.GetDescriptor(), fd);
- EXPECT_EQ(file.GetWaitableHandle(), fd);
-}
+++ /dev/null
-//===-- HostInfoTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/HostInfo.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/lldb-defines.h"
-#include "llvm/Support/Host.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace llvm;
-
-namespace {
-class HostInfoTest : public ::testing::Test {
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-};
-} // namespace
-
-TEST_F(HostInfoTest, GetAugmentedArchSpec) {
- // Fully specified triple should not be changed.
- ArchSpec spec = HostInfo::GetAugmentedArchSpec("x86_64-pc-linux-gnu");
- EXPECT_EQ(spec.GetTriple().getTriple(), "x86_64-pc-linux-gnu");
-
- // Same goes if we specify at least one of (os, vendor, env).
- spec = HostInfo::GetAugmentedArchSpec("x86_64-pc");
- EXPECT_EQ(spec.GetTriple().getTriple(), "x86_64-pc");
-
- // But if we specify only an arch, we should fill in the rest from the host.
- spec = HostInfo::GetAugmentedArchSpec("x86_64");
- Triple triple(sys::getDefaultTargetTriple());
- EXPECT_EQ(spec.GetTriple().getArch(), Triple::x86_64);
- EXPECT_EQ(spec.GetTriple().getOS(), triple.getOS());
- EXPECT_EQ(spec.GetTriple().getVendor(), triple.getVendor());
- EXPECT_EQ(spec.GetTriple().getEnvironment(), triple.getEnvironment());
-
- // Test LLDB_ARCH_DEFAULT
- EXPECT_EQ(HostInfo::GetAugmentedArchSpec(LLDB_ARCH_DEFAULT).GetTriple(),
- HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple());
-}
-
-TEST_F(HostInfoTest, GetHostname) {
- // Check non-empty string input works correctly.
- std::string s("abc");
- EXPECT_TRUE(HostInfo::GetHostname(s));
-}
-
-#if defined(__APPLE__)
-TEST_F(HostInfoTest, GetXcodeSDK) {
- EXPECT_FALSE(HostInfo::GetXcodeSDKPath(XcodeSDK("MacOSX.sdk")).empty());
- // These are expected to fall back to an available version.
- EXPECT_FALSE(HostInfo::GetXcodeSDKPath(XcodeSDK("MacOSX9999.sdk")).empty());
- // This is expected to fail.
- EXPECT_TRUE(HostInfo::GetXcodeSDKPath(XcodeSDK("CeciNestPasUnOS.sdk")).empty());
-}
-#endif
-
-TEST(HostInfoTestInitialization, InitTwice) {
- llvm::VersionTuple Version;
- {
- SubsystemRAII<FileSystem, HostInfo> subsystems;
- Version = HostInfo::GetOSVersion();
- }
-
- {
- SubsystemRAII<FileSystem, HostInfo> subsystems;
- EXPECT_EQ(Version, HostInfo::GetOSVersion());
- }
-}
+++ /dev/null
-//===-- HostTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Host.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace llvm;
-
-TEST(Host, WaitStatusFormat) {
- EXPECT_EQ("W01", formatv("{0:g}", WaitStatus{WaitStatus::Exit, 1}).str());
- EXPECT_EQ("X02", formatv("{0:g}", WaitStatus{WaitStatus::Signal, 2}).str());
- EXPECT_EQ("S03", formatv("{0:g}", WaitStatus{WaitStatus::Stop, 3}).str());
- EXPECT_EQ("Exited with status 4",
- formatv("{0}", WaitStatus{WaitStatus::Exit, 4}).str());
-}
-
-TEST(Host, GetEnvironment) {
- putenv(const_cast<char *>("LLDB_TEST_ENVIRONMENT_VAR=Host::GetEnvironment"));
- ASSERT_EQ("Host::GetEnvironment",
- Host::GetEnvironment().lookup("LLDB_TEST_ENVIRONMENT_VAR"));
-}
+++ /dev/null
-//===-- MainLoopTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/MainLoop.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
-#include "lldb/Host/PseudoTerminal.h"
-#include "lldb/Host/common/TCPSocket.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-#include <future>
-
-using namespace lldb_private;
-
-namespace {
-class MainLoopTest : public testing::Test {
-public:
- SubsystemRAII<Socket> subsystems;
-
- void SetUp() override {
- bool child_processes_inherit = false;
- Status error;
- std::unique_ptr<TCPSocket> listen_socket_up(
- new TCPSocket(true, child_processes_inherit));
- ASSERT_TRUE(error.Success());
- error = listen_socket_up->Listen("localhost:0", 5);
- ASSERT_TRUE(error.Success());
-
- Socket *accept_socket;
- std::future<Status> accept_error = std::async(std::launch::async, [&] {
- return listen_socket_up->Accept(accept_socket);
- });
-
- std::unique_ptr<TCPSocket> connect_socket_up(
- new TCPSocket(true, child_processes_inherit));
- error = connect_socket_up->Connect(
- llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber())
- .str());
- ASSERT_TRUE(error.Success());
- ASSERT_TRUE(accept_error.get().Success());
-
- callback_count = 0;
- socketpair[0] = std::move(connect_socket_up);
- socketpair[1].reset(accept_socket);
- }
-
- void TearDown() override {
- socketpair[0].reset();
- socketpair[1].reset();
- }
-
-protected:
- MainLoop::Callback make_callback() {
- return [&](MainLoopBase &loop) {
- ++callback_count;
- loop.RequestTermination();
- };
- }
- std::shared_ptr<Socket> socketpair[2];
- unsigned callback_count;
-};
-} // namespace
-
-TEST_F(MainLoopTest, ReadObject) {
- char X = 'X';
- size_t len = sizeof(X);
- ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
-
- MainLoop loop;
-
- Status error;
- auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error);
- ASSERT_TRUE(error.Success());
- ASSERT_TRUE(handle);
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(1u, callback_count);
-}
-
-TEST_F(MainLoopTest, TerminatesImmediately) {
- char X = 'X';
- size_t len = sizeof(X);
- ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
- ASSERT_TRUE(socketpair[1]->Write(&X, len).Success());
-
- MainLoop loop;
- Status error;
- auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error);
- ASSERT_TRUE(error.Success());
- auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error);
- ASSERT_TRUE(error.Success());
-
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(1u, callback_count);
-}
-
-#ifdef LLVM_ON_UNIX
-TEST_F(MainLoopTest, DetectsEOF) {
-
- PseudoTerminal term;
- ASSERT_THAT_ERROR(term.OpenFirstAvailablePrimary(O_RDWR), llvm::Succeeded());
- ASSERT_THAT_ERROR(term.OpenSecondary(O_RDWR | O_NOCTTY), llvm::Succeeded());
- auto conn = std::make_unique<ConnectionFileDescriptor>(
- term.ReleasePrimaryFileDescriptor(), true);
-
- Status error;
- MainLoop loop;
- auto handle =
- loop.RegisterReadObject(conn->GetReadObject(), make_callback(), error);
- ASSERT_TRUE(error.Success());
- term.CloseSecondaryFileDescriptor();
-
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(1u, callback_count);
-}
-
-TEST_F(MainLoopTest, Signal) {
- MainLoop loop;
- Status error;
-
- auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
- ASSERT_TRUE(error.Success());
- kill(getpid(), SIGUSR1);
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(1u, callback_count);
-}
-
-// Test that a signal which is not monitored by the MainLoop does not
-// cause a premature exit.
-TEST_F(MainLoopTest, UnmonitoredSignal) {
- MainLoop loop;
- Status error;
- struct sigaction sa;
- sa.sa_sigaction = [](int, siginfo_t *, void *) { };
- sa.sa_flags = SA_SIGINFO; // important: no SA_RESTART
- sigemptyset(&sa.sa_mask);
- ASSERT_EQ(0, sigaction(SIGUSR2, &sa, nullptr));
-
- auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
- ASSERT_TRUE(error.Success());
- std::thread killer([]() {
- sleep(1);
- kill(getpid(), SIGUSR2);
- sleep(1);
- kill(getpid(), SIGUSR1);
- });
- ASSERT_TRUE(loop.Run().Success());
- killer.join();
- ASSERT_EQ(1u, callback_count);
-}
-
-// Test that two callbacks can be registered for the same signal
-// and unregistered independently.
-TEST_F(MainLoopTest, TwoSignalCallbacks) {
- MainLoop loop;
- Status error;
- unsigned callback2_count = 0;
- unsigned callback3_count = 0;
-
- auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
- ASSERT_TRUE(error.Success());
-
- {
- // Run a single iteration with two callbacks enabled.
- auto handle2 = loop.RegisterSignal(
- SIGUSR1, [&](MainLoopBase &loop) { ++callback2_count; }, error);
- ASSERT_TRUE(error.Success());
-
- kill(getpid(), SIGUSR1);
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(1u, callback_count);
- ASSERT_EQ(1u, callback2_count);
- ASSERT_EQ(0u, callback3_count);
- }
-
- {
- // Make sure that remove + add new works.
- auto handle3 = loop.RegisterSignal(
- SIGUSR1, [&](MainLoopBase &loop) { ++callback3_count; }, error);
- ASSERT_TRUE(error.Success());
-
- kill(getpid(), SIGUSR1);
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(2u, callback_count);
- ASSERT_EQ(1u, callback2_count);
- ASSERT_EQ(1u, callback3_count);
- }
-
- // Both extra callbacks should be unregistered now.
- kill(getpid(), SIGUSR1);
- ASSERT_TRUE(loop.Run().Success());
- ASSERT_EQ(3u, callback_count);
- ASSERT_EQ(1u, callback2_count);
- ASSERT_EQ(1u, callback3_count);
-}
-#endif
+++ /dev/null
-//===-- NativeProcessProtocolTest.cpp -------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestingSupport/Host/NativeProcessTestUtils.h"
-
-#include "lldb/Host/common/NativeProcessProtocol.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-
-using namespace lldb_private;
-using namespace lldb;
-using namespace testing;
-
-TEST(NativeProcessProtocolTest, SetBreakpoint) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("x86_64-pc-linux"));
- auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
- InSequence S;
- EXPECT_CALL(Process, ReadMemory(0x47, 1))
- .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
- EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
- EXPECT_CALL(Process, ReadMemory(0x47, 1)).WillOnce(Return(ByMove(Trap)));
- EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
- llvm::Succeeded());
-}
-
-TEST(NativeProcessProtocolTest, SetBreakpointFailRead) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("x86_64-pc-linux"));
- EXPECT_CALL(Process, ReadMemory(0x47, 1))
- .WillOnce(Return(ByMove(
- llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
- EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
- llvm::Failed());
-}
-
-TEST(NativeProcessProtocolTest, SetBreakpointFailWrite) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("x86_64-pc-linux"));
- auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
- InSequence S;
- EXPECT_CALL(Process, ReadMemory(0x47, 1))
- .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
- EXPECT_CALL(Process, WriteMemory(0x47, Trap))
- .WillOnce(Return(ByMove(
- llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
- EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
- llvm::Failed());
-}
-
-TEST(NativeProcessProtocolTest, SetBreakpointFailVerify) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("x86_64-pc-linux"));
- auto Trap = cantFail(Process.GetSoftwareBreakpointTrapOpcode(1));
- InSequence S;
- EXPECT_CALL(Process, ReadMemory(0x47, 1))
- .WillOnce(Return(ByMove(std::vector<uint8_t>{0xbb})));
- EXPECT_CALL(Process, WriteMemory(0x47, Trap)).WillOnce(Return(ByMove(1)));
- EXPECT_CALL(Process, ReadMemory(0x47, 1))
- .WillOnce(Return(ByMove(
- llvm::createStringError(llvm::inconvertibleErrorCode(), "Foo"))));
- EXPECT_THAT_ERROR(Process.SetBreakpoint(0x47, 0, false).ToError(),
- llvm::Failed());
-}
-
-TEST(NativeProcessProtocolTest, ReadMemoryWithoutTrap) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("aarch64-pc-linux"));
- FakeMemory M{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
- EXPECT_CALL(Process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
- EXPECT_CALL(Process, WriteMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Write));
-
- EXPECT_THAT_ERROR(Process.SetBreakpoint(0x4, 0, false).ToError(),
- llvm::Succeeded());
- EXPECT_THAT_EXPECTED(
- Process.ReadMemoryWithoutTrap(0, 10),
- llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
- EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(0, 6),
- llvm::HasValue(std::vector<uint8_t>{0, 1, 2, 3, 4, 5}));
- EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 4),
- llvm::HasValue(std::vector<uint8_t>{6, 7, 8, 9}));
- EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(6, 2),
- llvm::HasValue(std::vector<uint8_t>{6, 7}));
- EXPECT_THAT_EXPECTED(Process.ReadMemoryWithoutTrap(4, 2),
- llvm::HasValue(std::vector<uint8_t>{4, 5}));
-}
-
-TEST(NativeProcessProtocolTest, ReadCStringFromMemory) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("aarch64-pc-linux"));
- FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'});
- EXPECT_CALL(Process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
-
- char string[1024];
- size_t bytes_read;
- EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(
- 0x0, &string[0], sizeof(string), bytes_read),
- llvm::HasValue(llvm::StringRef("hello")));
- EXPECT_EQ(bytes_read, 6UL);
-}
-
-TEST(NativeProcessProtocolTest, ReadCStringFromMemory_MaxSize) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("aarch64-pc-linux"));
- FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'});
- EXPECT_CALL(Process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
-
- char string[4];
- size_t bytes_read;
- EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(
- 0x0, &string[0], sizeof(string), bytes_read),
- llvm::HasValue(llvm::StringRef("hel")));
- EXPECT_EQ(bytes_read, 3UL);
-}
-
-TEST(NativeProcessProtocolTest, ReadCStringFromMemory_CrossPageBoundary) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcess<NativeProcessProtocol> Process(DummyDelegate,
- ArchSpec("aarch64-pc-linux"));
- unsigned string_start = llvm::sys::Process::getPageSizeEstimate() - 3;
- FakeMemory M({'h', 'e', 'l', 'l', 'o', 0, 'w', 'o'}, string_start);
- EXPECT_CALL(Process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
-
- char string[1024];
- size_t bytes_read;
- EXPECT_THAT_EXPECTED(Process.ReadCStringFromMemory(string_start, &string[0],
- sizeof(string),
- bytes_read),
- llvm::HasValue(llvm::StringRef("hello")));
- EXPECT_EQ(bytes_read, 6UL);
-}
\ No newline at end of file
+++ /dev/null
-//===-- PipeTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Pipe.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-class PipeTest : public testing::Test {
-public:
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-};
-
-TEST_F(PipeTest, CreateWithUniqueName) {
- Pipe pipe;
- llvm::SmallString<0> name;
- ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-CreateWithUniqueName",
- /*child_process_inherit=*/false,
- name)
- .ToError(),
- llvm::Succeeded());
-}
-
-// Test broken
-#ifndef _WIN32
-TEST_F(PipeTest, OpenAsReader) {
- Pipe pipe;
- llvm::SmallString<0> name;
- ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-OpenAsReader",
- /*child_process_inherit=*/false,
- name)
- .ToError(),
- llvm::Succeeded());
-
- // Ensure name is not null-terminated
- size_t name_len = name.size();
- name += "foobar";
- llvm::StringRef name_ref(name.data(), name_len);
- ASSERT_THAT_ERROR(
- pipe.OpenAsReader(name_ref, /*child_process_inherit=*/false).ToError(),
- llvm::Succeeded());
-}
-#endif
+++ /dev/null
-//===-- ProcessLaunchInfoTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/ProcessLaunchInfo.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-TEST(ProcessLaunchInfoTest, Constructor) {
- ProcessLaunchInfo Info(FileSpec("/stdin"), FileSpec("/stdout"),
- FileSpec("/stderr"), FileSpec("/wd"),
- eLaunchFlagStopAtEntry);
- EXPECT_EQ(FileSpec("/stdin"),
- Info.GetFileActionForFD(STDIN_FILENO)->GetFileSpec());
- EXPECT_EQ(FileSpec("/stdout"),
- Info.GetFileActionForFD(STDOUT_FILENO)->GetFileSpec());
- EXPECT_EQ(FileSpec("/stderr"),
- Info.GetFileActionForFD(STDERR_FILENO)->GetFileSpec());
- EXPECT_EQ(FileSpec("/wd"), Info.GetWorkingDirectory());
- EXPECT_EQ(eLaunchFlagStopAtEntry, Info.GetFlags().Get());
-}
+++ /dev/null
-//===-- SocketAddressTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/SocketAddress.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/Socket.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-class SocketAddressTest : public testing::Test {
-public:
- SubsystemRAII<Socket> subsystems;
-};
-} // namespace
-
-TEST_F(SocketAddressTest, Set) {
- SocketAddress sa;
- ASSERT_TRUE(sa.SetToLocalhost(AF_INET, 1138));
- ASSERT_STREQ("127.0.0.1", sa.GetIPAddress().c_str());
- ASSERT_EQ(1138, sa.GetPort());
-
- ASSERT_TRUE(sa.SetToAnyAddress(AF_INET, 0));
- ASSERT_STREQ("0.0.0.0", sa.GetIPAddress().c_str());
- ASSERT_EQ(0, sa.GetPort());
-
- ASSERT_TRUE(sa.SetToLocalhost(AF_INET6, 1139));
- ASSERT_TRUE(sa.GetIPAddress() == "::1" ||
- sa.GetIPAddress() == "0:0:0:0:0:0:0:1")
- << "Address was: " << sa.GetIPAddress();
- ASSERT_EQ(1139, sa.GetPort());
-}
-
-TEST_F(SocketAddressTest, GetAddressInfo) {
- auto addr = SocketAddress::GetAddressInfo("127.0.0.1", nullptr, AF_UNSPEC,
- SOCK_STREAM, IPPROTO_TCP);
- ASSERT_EQ(1u, addr.size());
- EXPECT_EQ(AF_INET, addr[0].GetFamily());
- EXPECT_EQ("127.0.0.1", addr[0].GetIPAddress());
-}
-
-#ifdef _WIN32
-
-// we need to test our inet_ntop implementation for Windows XP
-const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
-
-TEST_F(SocketAddressTest, inet_ntop) {
- const uint8_t address4[4] = {255, 0, 1, 100};
- const uint8_t address6[16] = {0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 255, 0};
-
- char buffer[INET6_ADDRSTRLEN];
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ("1:203:405:607:809:a0b:c0d:ff00",
- inet_ntop(AF_INET6, address6, buffer, sizeof(buffer)));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ("1:203:405:607:809:a0b:c0d:ff00",
- inet_ntop(AF_INET6, address6, buffer, 31));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ(nullptr, inet_ntop(AF_INET6, address6, buffer, 0));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ(nullptr, inet_ntop(AF_INET6, address6, buffer, 30));
-
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ("255.0.1.100",
- inet_ntop(AF_INET, address4, buffer, sizeof(buffer)));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ("255.0.1.100", inet_ntop(AF_INET, address4, buffer, 12));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ(nullptr, inet_ntop(AF_INET, address4, buffer, 0));
- memset(buffer, 'x', sizeof(buffer));
- EXPECT_STREQ(nullptr, inet_ntop(AF_INET, address4, buffer, 11));
-}
-
-#endif
+++ /dev/null
-//===-- SocketTest.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "SocketTestUtilities.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/Config.h"
-#include "lldb/Utility/UriParser.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-struct SocketTestParams {
- bool is_ipv6;
- std::string localhost_ip;
-};
-
-class SocketTest : public testing::TestWithParam<SocketTestParams> {
-public:
- SubsystemRAII<Socket> subsystems;
-
-protected:
- bool HostSupportsProtocol() const {
- if (GetParam().is_ipv6)
- return HostSupportsIPv6();
- return HostSupportsIPv4();
- }
-};
-
-TEST_P(SocketTest, DecodeHostAndPort) {
- std::string host_str;
- std::string port_str;
- int32_t port;
- Status error;
- EXPECT_TRUE(Socket::DecodeHostAndPort("localhost:1138", host_str, port_str,
- port, &error));
- EXPECT_STREQ("localhost", host_str.c_str());
- EXPECT_STREQ("1138", port_str.c_str());
- EXPECT_EQ(1138, port);
- EXPECT_TRUE(error.Success());
-
- EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str,
- port, &error));
- EXPECT_TRUE(error.Fail());
- EXPECT_STREQ("invalid host:port specification: 'google.com:65536'",
- error.AsCString());
-
- EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:-1138", host_str, port_str,
- port, &error));
- EXPECT_TRUE(error.Fail());
- EXPECT_STREQ("invalid host:port specification: 'google.com:-1138'",
- error.AsCString());
-
- EXPECT_FALSE(Socket::DecodeHostAndPort("google.com:65536", host_str, port_str,
- port, &error));
- EXPECT_TRUE(error.Fail());
- EXPECT_STREQ("invalid host:port specification: 'google.com:65536'",
- error.AsCString());
-
- EXPECT_TRUE(
- Socket::DecodeHostAndPort("12345", host_str, port_str, port, &error));
- EXPECT_STREQ("", host_str.c_str());
- EXPECT_STREQ("12345", port_str.c_str());
- EXPECT_EQ(12345, port);
- EXPECT_TRUE(error.Success());
-
- EXPECT_TRUE(
- Socket::DecodeHostAndPort("*:0", host_str, port_str, port, &error));
- EXPECT_STREQ("*", host_str.c_str());
- EXPECT_STREQ("0", port_str.c_str());
- EXPECT_EQ(0, port);
- EXPECT_TRUE(error.Success());
-
- EXPECT_TRUE(
- Socket::DecodeHostAndPort("*:65535", host_str, port_str, port, &error));
- EXPECT_STREQ("*", host_str.c_str());
- EXPECT_STREQ("65535", port_str.c_str());
- EXPECT_EQ(65535, port);
- EXPECT_TRUE(error.Success());
-
- EXPECT_TRUE(
- Socket::DecodeHostAndPort("[::1]:12345", host_str, port_str, port, &error));
- EXPECT_STREQ("::1", host_str.c_str());
- EXPECT_STREQ("12345", port_str.c_str());
- EXPECT_EQ(12345, port);
- EXPECT_TRUE(error.Success());
-
- EXPECT_TRUE(
- Socket::DecodeHostAndPort("[abcd:12fg:AF58::1]:12345", host_str, port_str, port, &error));
- EXPECT_STREQ("abcd:12fg:AF58::1", host_str.c_str());
- EXPECT_STREQ("12345", port_str.c_str());
- EXPECT_EQ(12345, port);
- EXPECT_TRUE(error.Success());
-}
-
-#if LLDB_ENABLE_POSIX
-TEST_P(SocketTest, DomainListenConnectAccept) {
- llvm::SmallString<64> Path;
- std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path);
- ASSERT_FALSE(EC);
- llvm::sys::path::append(Path, "test");
-
- // Skip the test if the $TMPDIR is too long to hold a domain socket.
- if (Path.size() > 107u)
- return;
-
- std::unique_ptr<DomainSocket> socket_a_up;
- std::unique_ptr<DomainSocket> socket_b_up;
- CreateDomainConnectedSockets(Path, &socket_a_up, &socket_b_up);
-}
-#endif
-
-TEST_P(SocketTest, TCPListen0ConnectAccept) {
- if (!HostSupportsProtocol())
- return;
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
- &socket_b_up);
-}
-
-TEST_P(SocketTest, TCPGetAddress) {
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- if (!HostSupportsProtocol())
- return;
- CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
- &socket_b_up);
-
- EXPECT_EQ(socket_a_up->GetLocalPortNumber(),
- socket_b_up->GetRemotePortNumber());
- EXPECT_EQ(socket_b_up->GetLocalPortNumber(),
- socket_a_up->GetRemotePortNumber());
- EXPECT_NE(socket_a_up->GetLocalPortNumber(),
- socket_b_up->GetLocalPortNumber());
- EXPECT_STREQ(GetParam().localhost_ip.c_str(),
- socket_a_up->GetRemoteIPAddress().c_str());
- EXPECT_STREQ(GetParam().localhost_ip.c_str(),
- socket_b_up->GetRemoteIPAddress().c_str());
-}
-
-TEST_P(SocketTest, UDPConnect) {
- // UDPSocket::Connect() creates sockets with AF_INET (IPv4).
- if (!HostSupportsIPv4())
- return;
- llvm::Expected<std::unique_ptr<UDPSocket>> socket =
- UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false);
-
- ASSERT_THAT_EXPECTED(socket, llvm::Succeeded());
- EXPECT_TRUE(socket.get()->IsValid());
-}
-
-TEST_P(SocketTest, TCPListen0GetPort) {
- if (!HostSupportsIPv4())
- return;
- Predicate<uint16_t> port_predicate;
- port_predicate.SetValue(0, eBroadcastNever);
- llvm::Expected<std::unique_ptr<TCPSocket>> sock =
- Socket::TcpListen("10.10.12.3:0", false, &port_predicate);
- ASSERT_THAT_EXPECTED(sock, llvm::Succeeded());
- ASSERT_TRUE(sock.get()->IsValid());
- EXPECT_NE(sock.get()->GetLocalPortNumber(), 0);
-}
-
-TEST_P(SocketTest, TCPGetConnectURI) {
- std::unique_ptr<TCPSocket> socket_a_up;
- std::unique_ptr<TCPSocket> socket_b_up;
- if (!HostSupportsProtocol())
- return;
- CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up,
- &socket_b_up);
-
- llvm::StringRef scheme;
- llvm::StringRef hostname;
- int port;
- llvm::StringRef path;
- std::string uri(socket_a_up->GetRemoteConnectionURI());
- EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path));
- EXPECT_EQ(scheme, "connect");
- EXPECT_EQ(port, socket_a_up->GetRemotePortNumber());
-}
-
-TEST_P(SocketTest, UDPGetConnectURI) {
- // UDPSocket::Connect() creates sockets with AF_INET (IPv4).
- if (!HostSupportsIPv4())
- return;
- llvm::Expected<std::unique_ptr<UDPSocket>> socket =
- UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false);
- ASSERT_THAT_EXPECTED(socket, llvm::Succeeded());
-
- llvm::StringRef scheme;
- llvm::StringRef hostname;
- int port;
- llvm::StringRef path;
- std::string uri = socket.get()->GetRemoteConnectionURI();
- EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path));
- EXPECT_EQ(scheme, "udp");
-}
-
-#if LLDB_ENABLE_POSIX
-TEST_P(SocketTest, DomainGetConnectURI) {
- llvm::SmallString<64> domain_path;
- std::error_code EC =
- llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path);
- ASSERT_FALSE(EC);
- llvm::sys::path::append(domain_path, "test");
-
- // Skip the test if the $TMPDIR is too long to hold a domain socket.
- if (domain_path.size() > 107u)
- return;
-
- std::unique_ptr<DomainSocket> socket_a_up;
- std::unique_ptr<DomainSocket> socket_b_up;
- CreateDomainConnectedSockets(domain_path, &socket_a_up, &socket_b_up);
-
- llvm::StringRef scheme;
- llvm::StringRef hostname;
- int port;
- llvm::StringRef path;
- std::string uri(socket_a_up->GetRemoteConnectionURI());
- EXPECT_TRUE(UriParser::Parse(uri, scheme, hostname, port, path));
- EXPECT_EQ(scheme, "unix-connect");
- EXPECT_EQ(path, domain_path);
-}
-#endif
-
-INSTANTIATE_TEST_SUITE_P(
- SocketTests, SocketTest,
- testing::Values(SocketTestParams{/*is_ipv6=*/false,
- /*localhost_ip=*/"127.0.0.1"},
- SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}),
- // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs.
- [](const testing::TestParamInfo<SocketTestParams> &info) {
- return info.param.is_ipv6 ? "ipv6" : "ipv4";
- });
+++ /dev/null
-//===-- SocketTestUtilities.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "SocketTestUtilities.h"
-#include "lldb/Host/Config.h"
-#include "lldb/Utility/StreamString.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <arpa/inet.h>
-#endif
-
-using namespace lldb_private;
-
-static void AcceptThread(Socket *listen_socket, bool child_processes_inherit,
- Socket **accept_socket, Status *error) {
- *error = listen_socket->Accept(*accept_socket);
-}
-
-template <typename SocketType>
-void lldb_private::CreateConnectedSockets(
- llvm::StringRef listen_remote_address,
- const std::function<std::string(const SocketType &)> &get_connect_addr,
- std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up) {
- bool child_processes_inherit = false;
- Status error;
- std::unique_ptr<SocketType> listen_socket_up(
- new SocketType(true, child_processes_inherit));
- ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
- error = listen_socket_up->Listen(listen_remote_address, 5);
- ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
- ASSERT_TRUE(listen_socket_up->IsValid());
-
- Status accept_error;
- Socket *accept_socket;
- std::thread accept_thread(AcceptThread, listen_socket_up.get(),
- child_processes_inherit, &accept_socket,
- &accept_error);
-
- std::string connect_remote_address = get_connect_addr(*listen_socket_up);
- std::unique_ptr<SocketType> connect_socket_up(
- new SocketType(true, child_processes_inherit));
- ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
- error = connect_socket_up->Connect(connect_remote_address);
- ASSERT_THAT_ERROR(error.ToError(), llvm::Succeeded());
- ASSERT_TRUE(connect_socket_up->IsValid());
-
- a_up->swap(connect_socket_up);
- ASSERT_TRUE((*a_up)->IsValid());
-
- accept_thread.join();
- b_up->reset(static_cast<SocketType *>(accept_socket));
- ASSERT_THAT_ERROR(accept_error.ToError(), llvm::Succeeded());
- ASSERT_NE(nullptr, b_up->get());
- ASSERT_TRUE((*b_up)->IsValid());
-
- listen_socket_up.reset();
-}
-
-bool lldb_private::CreateTCPConnectedSockets(
- std::string listen_remote_ip, std::unique_ptr<TCPSocket> *socket_a_up,
- std::unique_ptr<TCPSocket> *socket_b_up) {
- StreamString strm;
- strm.Printf("[%s]:0", listen_remote_ip.c_str());
- CreateConnectedSockets<TCPSocket>(
- strm.GetString(),
- [=](const TCPSocket &s) {
- char connect_remote_address[64];
- snprintf(connect_remote_address, sizeof(connect_remote_address),
- "[%s]:%u", listen_remote_ip.c_str(), s.GetLocalPortNumber());
- return std::string(connect_remote_address);
- },
- socket_a_up, socket_b_up);
- return true;
-}
-
-#if LLDB_ENABLE_POSIX
-void lldb_private::CreateDomainConnectedSockets(
- llvm::StringRef path, std::unique_ptr<DomainSocket> *socket_a_up,
- std::unique_ptr<DomainSocket> *socket_b_up) {
- return CreateConnectedSockets<DomainSocket>(
- path, [=](const DomainSocket &) { return path.str(); }, socket_a_up,
- socket_b_up);
-}
-#endif
-
-static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) {
- llvm::Expected<std::unique_ptr<TCPSocket>> Sock = Socket::TcpListen(
- Addr, /*child_processes_inherit=*/false, /*predicate=*/nullptr);
- if (Sock)
- return true;
- llvm::Error Err = Sock.takeError();
- GTEST_LOG_(WARNING) << llvm::formatv(
- "Creating a canary {0} TCP socket failed: {1}.",
- Proto, Err)
- .str();
- bool HasProtocolError = false;
- handleAllErrors(std::move(Err), [&](std::unique_ptr<llvm::ECError> ECErr) {
- std::error_code ec = ECErr->convertToErrorCode();
- if (ec == std::make_error_code(std::errc::address_family_not_supported) ||
- ec == std::make_error_code(std::errc::address_not_available))
- HasProtocolError = true;
- });
- if (HasProtocolError) {
- GTEST_LOG_(WARNING)
- << llvm::formatv(
- "Assuming the host does not support {0}. Skipping test.", Proto)
- .str();
- return false;
- }
- GTEST_LOG_(WARNING) << "Continuing anyway. The test will probably fail.";
- return true;
-}
-
-bool lldb_private::HostSupportsIPv4() {
- return CheckIPSupport("IPv4", "127.0.0.1:0");
-}
-
-bool lldb_private::HostSupportsIPv6() {
- return CheckIPSupport("IPv6", "[::1]:0");
-}
+++ /dev/null
-//===--------------------- SocketTestUtilities.h ----------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_HOST_SOCKETTESTUTILITIES_H
-#define LLDB_UNITTESTS_HOST_SOCKETTESTUTILITIES_H
-
-#include <cstdio>
-#include <functional>
-#include <thread>
-
-#include "lldb/Host/Config.h"
-#include "lldb/Host/Socket.h"
-#include "lldb/Host/common/TCPSocket.h"
-#include "lldb/Host/common/UDPSocket.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Testing/Support/Error.h"
-
-#if LLDB_ENABLE_POSIX
-#include "lldb/Host/posix/DomainSocket.h"
-#endif
-
-namespace lldb_private {
-template <typename SocketType>
-void CreateConnectedSockets(
- llvm::StringRef listen_remote_address,
- const std::function<std::string(const SocketType &)> &get_connect_addr,
- std::unique_ptr<SocketType> *a_up, std::unique_ptr<SocketType> *b_up);
-bool CreateTCPConnectedSockets(std::string listen_remote_ip,
- std::unique_ptr<TCPSocket> *a_up,
- std::unique_ptr<TCPSocket> *b_up);
-#if LLDB_ENABLE_POSIX
-void CreateDomainConnectedSockets(llvm::StringRef path,
- std::unique_ptr<DomainSocket> *a_up,
- std::unique_ptr<DomainSocket> *b_up);
-#endif
-
-bool HostSupportsIPv6();
-bool HostSupportsIPv4();
-} // namespace lldb_private
-
-#endif
+++ /dev/null
-//===-- HostTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/Host.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Target/Process.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-class HostTest : public testing::Test {
-public:
- static void SetUpTestCase() {
- FileSystem::Initialize();
- HostInfo::Initialize();
- }
- static void TearDownTestCase() {
- HostInfo::Terminate();
- FileSystem::Terminate();
- }
-};
-} // namespace
-
-TEST_F(HostTest, GetProcessInfo) {
- ProcessInstanceInfo Info;
- ASSERT_FALSE(Host::GetProcessInfo(0, Info));
-
- ASSERT_TRUE(Host::GetProcessInfo(getpid(), Info));
-
- ASSERT_TRUE(Info.ProcessIDIsValid());
- EXPECT_EQ(lldb::pid_t(getpid()), Info.GetProcessID());
-
- ASSERT_TRUE(Info.ParentProcessIDIsValid());
- EXPECT_EQ(lldb::pid_t(getppid()), Info.GetParentProcessID());
-
- ASSERT_TRUE(Info.EffectiveUserIDIsValid());
- EXPECT_EQ(geteuid(), Info.GetEffectiveUserID());
-
- ASSERT_TRUE(Info.EffectiveGroupIDIsValid());
- EXPECT_EQ(getegid(), Info.GetEffectiveGroupID());
-
- ASSERT_TRUE(Info.UserIDIsValid());
- EXPECT_EQ(geteuid(), Info.GetUserID());
-
- ASSERT_TRUE(Info.GroupIDIsValid());
- EXPECT_EQ(getegid(), Info.GetGroupID());
-
- EXPECT_TRUE(Info.GetArchitecture().IsValid());
- EXPECT_EQ(HostInfo::GetArchitecture(HostInfo::eArchKindDefault),
- Info.GetArchitecture());
-}
+++ /dev/null
-//===-- SupportTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/linux/Support.h"
-#include "llvm/Support/Threading.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(Support, getProcFile_Pid) {
- auto BufferOrError = getProcFile(getpid(), "maps");
- ASSERT_TRUE(BufferOrError);
- ASSERT_TRUE(*BufferOrError);
-}
-
-TEST(Support, getProcFile_Tid) {
- auto BufferOrError = getProcFile(getpid(), llvm::get_threadid(), "comm");
- ASSERT_TRUE(BufferOrError);
- ASSERT_TRUE(*BufferOrError);
-}
+++ /dev/null
-if("ARM" IN_LIST LLVM_TARGETS_TO_BUILD)
- add_lldb_unittest(EmulatorTests
- TestAArch64Emulator.cpp
- LINK_LIBS
- lldbCore
- lldbSymbol
- lldbTarget
- lldbPluginInstructionARM64
- LINK_COMPONENTS
- Support
- ${LLVM_TARGETS_TO_BUILD})
-endif()
+++ /dev/null
-//===-- TestAArch64Emulator.cpp ------------------------------------------===//
-
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Disassembler.h"
-#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Utility/ArchSpec.h"
-
-#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-struct Arch64EmulatorTester : public EmulateInstructionARM64 {
- Arch64EmulatorTester()
- : EmulateInstructionARM64(ArchSpec("arm64-apple-ios")) {}
-
- static uint64_t AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bool carry_in,
- EmulateInstructionARM64::ProcState &proc_state) {
- return EmulateInstructionARM64::AddWithCarry(N, x, y, carry_in, proc_state);
- }
-};
-
-class TestAArch64Emulator : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
-protected:
-};
-
-void TestAArch64Emulator::SetUpTestCase() {
- EmulateInstructionARM64::Initialize();
-}
-
-void TestAArch64Emulator::TearDownTestCase() {
- EmulateInstructionARM64::Terminate();
-}
-
-TEST_F(TestAArch64Emulator, TestOverflow) {
- EmulateInstructionARM64::ProcState pstate;
- memset(&pstate, 0, sizeof(pstate));
- uint64_t ll_max = std::numeric_limits<int64_t>::max();
- Arch64EmulatorTester emu;
- ASSERT_EQ(emu.AddWithCarry(64, ll_max, 0, 0, pstate), ll_max);
- ASSERT_EQ(pstate.V, 0ULL);
- ASSERT_EQ(pstate.C, 0ULL);
- ASSERT_EQ(emu.AddWithCarry(64, ll_max, 1, 0, pstate), (uint64_t)(ll_max + 1));
- ASSERT_EQ(pstate.V, 1ULL);
- ASSERT_EQ(pstate.C, 0ULL);
- ASSERT_EQ(emu.AddWithCarry(64, ll_max, 0, 1, pstate), (uint64_t)(ll_max + 1));
- ASSERT_EQ(pstate.V, 1ULL);
- ASSERT_EQ(pstate.C, 0ULL);
-}
+++ /dev/null
-add_lldb_unittest(InterpreterTests
- TestCompletion.cpp
- TestOptionArgParser.cpp
- TestOptionValue.cpp
- TestOptionValueFileColonLine.cpp
-
- LINK_LIBS
- lldbInterpreter
- lldbUtilityHelpers
- )
+++ /dev/null
-//===-- TestCompletion.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Interpreter/CommandCompletions.h"
-#include "lldb/Utility/StringList.h"
-#include "lldb/Utility/TildeExpressionResolver.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "TestingSupport/MockTildeExpressionResolver.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace fs = llvm::sys::fs;
-namespace path = llvm::sys::path;
-using namespace llvm;
-using namespace lldb_private;
-
-namespace {
-
-class CompletionTest : public testing::Test {
- SubsystemRAII<FileSystem> subsystems;
-
-protected:
- /// Unique temporary directory in which all created filesystem entities must
- /// be placed. It is removed at the end of the test suite.
- SmallString<128> BaseDir;
-
- /// The working directory that we got when starting the test. Every test
- /// should chdir into this directory first because some tests maybe chdir
- /// into another one during their run.
- static SmallString<128> OriginalWorkingDir;
-
- SmallString<128> DirFoo;
- SmallString<128> DirFooA;
- SmallString<128> DirFooB;
- SmallString<128> DirFooC;
- SmallString<128> DirBar;
- SmallString<128> DirBaz;
- SmallString<128> DirTestFolder;
- SmallString<128> DirNested;
-
- SmallString<128> FileAA;
- SmallString<128> FileAB;
- SmallString<128> FileAC;
- SmallString<128> FileFoo;
- SmallString<128> FileBar;
- SmallString<128> FileBaz;
-
- void SetUp() override {
- // chdir back into the original working dir this test binary started with.
- // A previous test may have have changed the working dir.
- ASSERT_NO_ERROR(fs::set_current_path(OriginalWorkingDir));
-
- // Get the name of the current test. To prevent that by chance two tests
- // get the same temporary directory if createUniqueDirectory fails.
- auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
- ASSERT_TRUE(test_info != nullptr);
- std::string name = test_info->name();
- ASSERT_NO_ERROR(fs::createUniqueDirectory("FsCompletion-" + name, BaseDir));
-
- const char *DirNames[] = {"foo", "fooa", "foob", "fooc",
- "bar", "baz", "test_folder", "foo/nested"};
- const char *FileNames[] = {"aa1234.tmp", "ab1234.tmp", "ac1234.tmp",
- "foo1234.tmp", "bar1234.tmp", "baz1234.tmp"};
- SmallString<128> *Dirs[] = {&DirFoo, &DirFooA, &DirFooB, &DirFooC,
- &DirBar, &DirBaz, &DirTestFolder, &DirNested};
- for (auto Dir : llvm::zip(DirNames, Dirs)) {
- auto &Path = *std::get<1>(Dir);
- Path = BaseDir;
- path::append(Path, std::get<0>(Dir));
- ASSERT_NO_ERROR(fs::create_directories(Path));
- }
-
- SmallString<128> *Files[] = {&FileAA, &FileAB, &FileAC,
- &FileFoo, &FileBar, &FileBaz};
- for (auto File : llvm::zip(FileNames, Files)) {
- auto &Path = *std::get<1>(File);
- Path = BaseDir;
- path::append(Path, std::get<0>(File));
- int FD;
- ASSERT_NO_ERROR(fs::createUniqueFile(Path, FD, Path));
- ::close(FD);
- }
- }
-
- static void SetUpTestCase() {
- ASSERT_NO_ERROR(fs::current_path(OriginalWorkingDir));
- }
-
- void TearDown() override {
- ASSERT_NO_ERROR(fs::remove_directories(BaseDir));
- }
-
- static bool HasEquivalentFile(const Twine &Path, const StringList &Paths) {
- for (size_t I = 0; I < Paths.GetSize(); ++I) {
- if (fs::equivalent(Path, Paths[I]))
- return true;
- }
- return false;
- }
-
- void DoDirCompletions(const Twine &Prefix,
- StandardTildeExpressionResolver &Resolver,
- StringList &Results) {
- // When a partial name matches, it returns all matches. If it matches both
- // a full name AND some partial names, it returns all of them.
- CommandCompletions::DiskDirectories(Prefix + "foo", Results, Resolver);
- ASSERT_EQ(4u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));
-
- // If it matches only partial names, it still works as expected.
- CommandCompletions::DiskDirectories(Twine(Prefix) + "b", Results, Resolver);
- ASSERT_EQ(2u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirBar, Results));
- EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));
- }
-};
-
-SmallString<128> CompletionTest::OriginalWorkingDir;
-} // namespace
-
-static std::vector<std::string> toVector(const StringList &SL) {
- std::vector<std::string> Result;
- for (size_t Idx = 0; Idx < SL.GetSize(); ++Idx)
- Result.push_back(SL[Idx]);
- return Result;
-}
-using testing::UnorderedElementsAre;
-
-TEST_F(CompletionTest, DirCompletionAbsolute) {
- // All calls to DiskDirectories() return only directories, even when
- // there are files which also match. The tests below all check this
- // by asserting an exact result count, and verifying against known
- // folders.
-
- std::string Prefixes[] = {(Twine(BaseDir) + "/").str(), ""};
-
- StandardTildeExpressionResolver Resolver;
- StringList Results;
-
- // When a directory is specified that doesn't end in a slash, it searches
- // for that directory, not items under it.
- // Sanity check that the path we complete on exists and isn't too long.
- CommandCompletions::DiskDirectories(Twine(BaseDir) + "/fooa", Results,
- Resolver);
- ASSERT_EQ(1u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
-
- CommandCompletions::DiskDirectories(Twine(BaseDir) + "/.", Results, Resolver);
- ASSERT_EQ(0u, Results.GetSize());
-
- // When the same directory ends with a slash, it finds all children.
- CommandCompletions::DiskDirectories(Prefixes[0], Results, Resolver);
- ASSERT_EQ(7u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));
- EXPECT_TRUE(HasEquivalentFile(DirBar, Results));
- EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));
- EXPECT_TRUE(HasEquivalentFile(DirTestFolder, Results));
-
- DoDirCompletions(Twine(BaseDir) + "/", Resolver, Results);
- llvm::sys::fs::set_current_path(BaseDir);
- DoDirCompletions("", Resolver, Results);
-}
-
-TEST_F(CompletionTest, FileCompletionAbsolute) {
- // All calls to DiskFiles() return both files and directories The tests below
- // all check this by asserting an exact result count, and verifying against
- // known folders.
-
- StandardTildeExpressionResolver Resolver;
- StringList Results;
- // When an item is specified that doesn't end in a slash but exactly matches
- // one item, it returns that item.
- CommandCompletions::DiskFiles(Twine(BaseDir) + "/fooa", Results, Resolver);
- ASSERT_EQ(1u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
-
- // The previous check verified a directory match. But it should work for
- // files too.
- CommandCompletions::DiskFiles(Twine(BaseDir) + "/aa", Results, Resolver);
- ASSERT_EQ(1u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(FileAA, Results));
-
- // When it ends with a slash, it should find all files and directories.
- CommandCompletions::DiskFiles(Twine(BaseDir) + "/", Results, Resolver);
- ASSERT_EQ(13u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));
- EXPECT_TRUE(HasEquivalentFile(DirBar, Results));
- EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));
- EXPECT_TRUE(HasEquivalentFile(DirTestFolder, Results));
-
- EXPECT_TRUE(HasEquivalentFile(FileAA, Results));
- EXPECT_TRUE(HasEquivalentFile(FileAB, Results));
- EXPECT_TRUE(HasEquivalentFile(FileAC, Results));
- EXPECT_TRUE(HasEquivalentFile(FileFoo, Results));
- EXPECT_TRUE(HasEquivalentFile(FileBar, Results));
- EXPECT_TRUE(HasEquivalentFile(FileBaz, Results));
-
- // When a partial name matches, it returns all file & directory matches.
- CommandCompletions::DiskFiles(Twine(BaseDir) + "/foo", Results, Resolver);
- ASSERT_EQ(5u, Results.GetSize());
- EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));
- EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));
- EXPECT_TRUE(HasEquivalentFile(FileFoo, Results));
-}
-
-TEST_F(CompletionTest, DirCompletionUsername) {
- MockTildeExpressionResolver Resolver("James", BaseDir);
- Resolver.AddKnownUser("Kirk", DirFooB);
- Resolver.AddKnownUser("Lars", DirFooC);
- Resolver.AddKnownUser("Jason", DirFoo);
- Resolver.AddKnownUser("Larry", DirFooA);
- std::string sep = std::string(path::get_separator());
-
- // Just resolving current user's home directory by itself should return the
- // directory.
- StringList Results;
- CommandCompletions::DiskDirectories("~", Results, Resolver);
- EXPECT_THAT(toVector(Results), UnorderedElementsAre("~" + sep));
-
- // With a slash appended, it should return all items in the directory.
- CommandCompletions::DiskDirectories("~/", Results, Resolver);
- EXPECT_THAT(toVector(Results),
- UnorderedElementsAre(
- "~/foo" + sep, "~/fooa" + sep, "~/foob" + sep, "~/fooc" + sep,
- "~/bar" + sep, "~/baz" + sep, "~/test_folder" + sep));
-
- // Check that we can complete directories in nested paths
- CommandCompletions::DiskDirectories("~/foo/", Results, Resolver);
- EXPECT_THAT(toVector(Results), UnorderedElementsAre("~/foo/nested" + sep));
-
- CommandCompletions::DiskDirectories("~/foo/nes", Results, Resolver);
- EXPECT_THAT(toVector(Results), UnorderedElementsAre("~/foo/nested" + sep));
-
- // With ~username syntax it should return one match if there is an exact
- // match. It shouldn't translate to the actual directory, it should keep the
- // form the user typed.
- CommandCompletions::DiskDirectories("~Lars", Results, Resolver);
- EXPECT_THAT(toVector(Results), UnorderedElementsAre("~Lars" + sep));
-
- // But with a username that is not found, no results are returned.
- CommandCompletions::DiskDirectories("~Dave", Results, Resolver);
- EXPECT_THAT(toVector(Results), UnorderedElementsAre());
-
- // And if there are multiple matches, it should return all of them.
- CommandCompletions::DiskDirectories("~La", Results, Resolver);
- EXPECT_THAT(toVector(Results),
- UnorderedElementsAre("~Lars" + sep, "~Larry" + sep));
-}
+++ /dev/null
-//===-- ArgsTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include "lldb/Interpreter/OptionArgParser.h"
-
-using namespace lldb_private;
-
-TEST(OptionArgParserTest, toBoolean) {
- bool success = false;
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("true"), false, nullptr));
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("on"), false, nullptr));
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, nullptr));
- EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef("1"), false, nullptr));
-
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("true"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("on"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("yes"), false, &success));
- EXPECT_TRUE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("1"), false, &success));
- EXPECT_TRUE(success);
-
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("false"), true, nullptr));
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("off"), true, nullptr));
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("no"), true, nullptr));
- EXPECT_FALSE(OptionArgParser::ToBoolean(llvm::StringRef("0"), true, nullptr));
-
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("false"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("off"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("no"), true, &success));
- EXPECT_TRUE(success);
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("0"), true, &success));
- EXPECT_TRUE(success);
-
- EXPECT_FALSE(
- OptionArgParser::ToBoolean(llvm::StringRef("10"), false, &success));
- EXPECT_FALSE(success);
- EXPECT_TRUE(
- OptionArgParser::ToBoolean(llvm::StringRef("10"), true, &success));
- EXPECT_FALSE(success);
- EXPECT_TRUE(OptionArgParser::ToBoolean(llvm::StringRef(""), true, &success));
- EXPECT_FALSE(success);
-}
-
-TEST(OptionArgParserTest, toChar) {
- bool success = false;
-
- EXPECT_EQ('A', OptionArgParser::ToChar("A", 'B', nullptr));
- EXPECT_EQ('B', OptionArgParser::ToChar("B", 'A', nullptr));
-
- EXPECT_EQ('A', OptionArgParser::ToChar("A", 'B', &success));
- EXPECT_TRUE(success);
- EXPECT_EQ('B', OptionArgParser::ToChar("B", 'A', &success));
- EXPECT_TRUE(success);
-
- EXPECT_EQ('A', OptionArgParser::ToChar("", 'A', &success));
- EXPECT_FALSE(success);
- EXPECT_EQ('A', OptionArgParser::ToChar("ABC", 'A', &success));
- EXPECT_FALSE(success);
-}
-
-TEST(OptionArgParserTest, toScriptLanguage) {
- bool success = false;
-
- EXPECT_EQ(lldb::eScriptLanguageDefault,
- OptionArgParser::ToScriptLanguage(llvm::StringRef("default"),
- lldb::eScriptLanguageNone,
- nullptr));
- EXPECT_EQ(lldb::eScriptLanguagePython,
- OptionArgParser::ToScriptLanguage(
- llvm::StringRef("python"), lldb::eScriptLanguageNone, nullptr));
- EXPECT_EQ(lldb::eScriptLanguageNone,
- OptionArgParser::ToScriptLanguage(
- llvm::StringRef("none"), lldb::eScriptLanguagePython, nullptr));
-
- EXPECT_EQ(lldb::eScriptLanguageDefault,
- OptionArgParser::ToScriptLanguage(llvm::StringRef("default"),
- lldb::eScriptLanguageNone,
- &success));
- EXPECT_TRUE(success);
- EXPECT_EQ(lldb::eScriptLanguagePython,
- OptionArgParser::ToScriptLanguage(llvm::StringRef("python"),
- lldb::eScriptLanguageNone,
- &success));
- EXPECT_TRUE(success);
- EXPECT_EQ(lldb::eScriptLanguageNone,
- OptionArgParser::ToScriptLanguage(llvm::StringRef("none"),
- lldb::eScriptLanguagePython,
- &success));
- EXPECT_TRUE(success);
-
- EXPECT_EQ(lldb::eScriptLanguagePython,
- OptionArgParser::ToScriptLanguage(llvm::StringRef("invalid"),
- lldb::eScriptLanguagePython,
- &success));
- EXPECT_FALSE(success);
-}
+++ /dev/null
-//===-- TestOptionValue.cpp -------- -------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Interpreter/OptionValues.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-class Callback {
-public:
- virtual void Invoke() const {}
- void operator()() const { Invoke(); }
-protected:
- ~Callback() = default;
-};
-
-class MockCallback final : public Callback {
-public:
- MOCK_CONST_METHOD0(Invoke, void());
-};
-
-// Test a single-value class.
-TEST(OptionValueString, DeepCopy) {
- OptionValueString str;
- str.SetValueFromString("ab");
-
- MockCallback callback;
- str.SetValueChangedCallback([&callback] { callback(); });
- EXPECT_CALL(callback, Invoke());
-
- auto copy_sp = str.DeepCopy(nullptr);
-
- // Test that the base class data members are copied/set correctly.
- ASSERT_TRUE(copy_sp);
- ASSERT_EQ(copy_sp->GetParent().get(), nullptr);
- ASSERT_TRUE(copy_sp->OptionWasSet());
- ASSERT_EQ(copy_sp->GetStringValue(), "ab");
-
- // Trigger the callback.
- copy_sp->SetValueFromString("c", eVarSetOperationAppend);
- ASSERT_EQ(copy_sp->GetStringValue(), "abc");
-}
-
-// Test an aggregate class.
-TEST(OptionValueArgs, DeepCopy) {
- OptionValueArgs args;
- args.SetValueFromString("A B");
-
- MockCallback callback;
- args.SetValueChangedCallback([&callback] { callback(); });
- EXPECT_CALL(callback, Invoke());
-
- auto copy_sp = args.DeepCopy(nullptr);
-
- // Test that the base class data members are copied/set correctly.
- ASSERT_TRUE(copy_sp);
- ASSERT_EQ(copy_sp->GetParent(), nullptr);
- ASSERT_TRUE(copy_sp->OptionWasSet());
-
- auto *args_copy_ptr = copy_sp->GetAsArgs();
- ASSERT_EQ(args_copy_ptr->GetSize(), 2U);
- ASSERT_EQ((*args_copy_ptr)[0]->GetParent(), copy_sp);
- ASSERT_EQ((*args_copy_ptr)[0]->GetStringValue(), "A");
- ASSERT_EQ((*args_copy_ptr)[1]->GetParent(), copy_sp);
- ASSERT_EQ((*args_copy_ptr)[1]->GetStringValue(), "B");
-
- // Trigger the callback.
- copy_sp->SetValueFromString("C", eVarSetOperationAppend);
- ASSERT_TRUE(args_copy_ptr);
- ASSERT_EQ(args_copy_ptr->GetSize(), 3U);
- ASSERT_EQ((*args_copy_ptr)[2]->GetStringValue(), "C");
-}
-
-class TestProperties : public OptionValueProperties {
-public:
- static std::shared_ptr<TestProperties> CreateGlobal() {
- auto props_sp = std::make_shared<TestProperties>();
- const bool is_global = false;
-
- auto dict_sp = std::make_shared<OptionValueDictionary>(1 << eTypeUInt64);
- props_sp->AppendProperty(ConstString("dict"), ConstString(), is_global,
- dict_sp);
-
- auto file_list_sp = std::make_shared<OptionValueFileSpecList>();
- props_sp->AppendProperty(ConstString("file-list"), ConstString(), is_global,
- file_list_sp);
- return props_sp;
- }
-
- void SetDictionaryChangedCallback(const MockCallback &callback) {
- SetValueChangedCallback(m_dict_index, [&callback] { callback(); });
- }
-
- void SetFileListChangedCallback(const MockCallback &callback) {
- SetValueChangedCallback(m_file_list_index, [&callback] { callback(); });
- }
-
- OptionValueDictionary *GetDictionary() {
- return GetPropertyAtIndexAsOptionValueDictionary(nullptr, m_dict_index);
- }
-
- OptionValueFileSpecList *GetFileList() {
- return GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, true,
- m_file_list_index);
- }
-
-private:
- lldb::OptionValueSP Clone() const {
- return std::make_shared<TestProperties>(*this);
- }
-
- uint32_t m_dict_index = 0;
- uint32_t m_file_list_index = 1;
-};
-
-// Test a user-defined propery class.
-TEST(TestProperties, DeepCopy) {
- auto props_sp = TestProperties::CreateGlobal();
- props_sp->GetDictionary()->SetValueFromString("A=1 B=2");
- props_sp->GetFileList()->SetValueFromString("path/to/file");
-
- MockCallback callback;
- props_sp->SetDictionaryChangedCallback(callback);
- props_sp->SetFileListChangedCallback(callback);
- EXPECT_CALL(callback, Invoke()).Times(2);
-
- auto copy_sp = props_sp->DeepCopy(nullptr);
-
- // Test that the base class data members are copied/set correctly.
- ASSERT_TRUE(copy_sp);
- ASSERT_EQ(copy_sp->GetParent(), nullptr);
-
- // This cast is safe only if the class overrides Clone().
- auto *props_copy_ptr = static_cast<TestProperties *>(copy_sp.get());
- ASSERT_TRUE(props_copy_ptr);
-
- // Test the first child.
- auto dict_copy_ptr = props_copy_ptr->GetDictionary();
- ASSERT_TRUE(dict_copy_ptr);
- ASSERT_EQ(dict_copy_ptr->GetParent(), copy_sp);
- ASSERT_TRUE(dict_copy_ptr->OptionWasSet());
- ASSERT_EQ(dict_copy_ptr->GetNumValues(), 2U);
-
- auto value_ptr = dict_copy_ptr->GetValueForKey(ConstString("A"));
- ASSERT_TRUE(value_ptr);
- ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);
- ASSERT_EQ(value_ptr->GetUInt64Value(), 1U);
-
- value_ptr = dict_copy_ptr->GetValueForKey(ConstString("B"));
- ASSERT_TRUE(value_ptr);
- ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr);
- ASSERT_EQ(value_ptr->GetUInt64Value(), 2U);
-
- // Test the second child.
- auto file_list_copy_ptr = props_copy_ptr->GetFileList();
- ASSERT_TRUE(file_list_copy_ptr);
- ASSERT_EQ(file_list_copy_ptr->GetParent(), copy_sp);
- ASSERT_TRUE(file_list_copy_ptr->OptionWasSet());
-
- auto file_list_copy = file_list_copy_ptr->GetCurrentValue();
- ASSERT_EQ(file_list_copy.GetSize(), 1U);
- ASSERT_EQ(file_list_copy.GetFileSpecAtIndex(0), FileSpec("path/to/file"));
-
- // Trigger the callback first time.
- dict_copy_ptr->SetValueFromString("C=3", eVarSetOperationAppend);
-
- // Trigger the callback second time.
- file_list_copy_ptr->SetValueFromString("0 another/path", eVarSetOperationReplace);
-}
+++ /dev/null
-//===-- ArgsTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Interpreter/OptionValueFileColonLine.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Status.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-void CheckSetting(const char *input, bool success, FileSpec path = {},
- uint32_t line_number = LLDB_INVALID_LINE_NUMBER,
- uint32_t column_number = LLDB_INVALID_COLUMN_NUMBER) {
-
- OptionValueFileColonLine value;
- Status error;
- llvm::StringRef s_ref(input);
- error = value.SetValueFromString(s_ref);
- ASSERT_EQ(error.Success(), success);
-
- // If we were meant to fail, we don't need to do more checks:
- if (!success)
- return;
-
- ASSERT_EQ(value.GetLineNumber(), line_number);
- ASSERT_EQ(value.GetColumnNumber(), column_number);
- ASSERT_EQ(value.GetFileSpec(), path);
-}
-
-TEST(OptionValueFileColonLine, setFromString) {
- OptionValueFileColonLine value;
- Status error;
-
- // Make sure a default constructed value is invalid:
- ASSERT_EQ(value.GetLineNumber(),
- static_cast<uint32_t>(LLDB_INVALID_LINE_NUMBER));
- ASSERT_EQ(value.GetColumnNumber(),
- static_cast<uint32_t>(LLDB_INVALID_COLUMN_NUMBER));
- ASSERT_FALSE(value.GetFileSpec());
-
- // Make sure it is an error to pass a specifier with no line number:
- CheckSetting("foo.c", false);
-
- // Now try with just a file & line:
- CheckSetting("foo.c:12", true, FileSpec("foo.c"), 12);
- CheckSetting("foo.c:12:20", true, FileSpec("foo.c"), 12, 20);
- // Make sure a colon doesn't mess us up:
- CheckSetting("foo:bar.c:12", true, FileSpec("foo:bar.c"), 12);
- CheckSetting("foo:bar.c:12:20", true, FileSpec("foo:bar.c"), 12, 20);
- // Try errors in the line number:
- CheckSetting("foo.c:12c", false);
- CheckSetting("foo.c:12:20c", false);
-}
+++ /dev/null
-//===-- CLanguagesTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
-#include "Plugins/Language/ObjC/ObjCLanguage.h"
-#include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/lldb-enumerations.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-/// Returns the name of the LLDB plugin for the given language or a null
-/// ConstString if there is no fitting plugin.
-static ConstString GetPluginName(lldb::LanguageType language) {
- Language *language_plugin = Language::FindPlugin(language);
- if (language_plugin)
- return language_plugin->GetPluginName();
- return ConstString();
-}
-
-TEST(CLanguages, LookupCLanguagesByLanguageType) {
- SubsystemRAII<CPlusPlusLanguage, ObjCPlusPlusLanguage, ObjCLanguage> langs;
-
- // There is no plugin to find for C.
- EXPECT_EQ(Language::FindPlugin(lldb::eLanguageTypeC), nullptr);
- EXPECT_EQ(Language::FindPlugin(lldb::eLanguageTypeC89), nullptr);
- EXPECT_EQ(Language::FindPlugin(lldb::eLanguageTypeC99), nullptr);
- EXPECT_EQ(Language::FindPlugin(lldb::eLanguageTypeC11), nullptr);
-
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeC_plus_plus), "cplusplus");
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeC_plus_plus_03), "cplusplus");
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeC_plus_plus_11), "cplusplus");
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeC_plus_plus_14), "cplusplus");
-
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeObjC), "objc");
-
- EXPECT_EQ(GetPluginName(lldb::eLanguageTypeObjC_plus_plus), "objcplusplus");
-}
+++ /dev/null
-add_lldb_unittest(LanguageCLanguagesTests
- CLanguagesTest.cpp
-
- LINK_LIBS
- lldbPluginCPlusPlusLanguage
- lldbPluginObjCLanguage
- lldbPluginObjCPlusPlusLanguage
-)
+++ /dev/null
-add_subdirectory(CPlusPlus)
-add_subdirectory(CLanguages)
-add_subdirectory(Highlighting)
+++ /dev/null
-add_lldb_unittest(LanguageCPlusPlusTests
- CPlusPlusLanguageTest.cpp
-
- LINK_LIBS
- lldbPluginCPlusPlusLanguage
- )
+++ /dev/null
-//===-- CPlusPlusLanguageTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
-#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(CPlusPlusLanguage, MethodNameParsing) {
- struct TestCase {
- std::string input;
- std::string context, basename, arguments, qualifiers, scope_qualified_name;
- };
-
- TestCase test_cases[] = {
- {"main(int, char *[]) ", "", "main", "(int, char *[])", "", "main"},
- {"foo::bar(baz) const", "foo", "bar", "(baz)", "const", "foo::bar"},
- {"foo::~bar(baz)", "foo", "~bar", "(baz)", "", "foo::~bar"},
- {"a::b::c::d(e,f)", "a::b::c", "d", "(e,f)", "", "a::b::c::d"},
- {"void f(int)", "", "f", "(int)", "", "f"},
-
- // Operators
- {"std::basic_ostream<char, std::char_traits<char> >& "
- "std::operator<<<std::char_traits<char> >"
- "(std::basic_ostream<char, std::char_traits<char> >&, char const*)",
- "std", "operator<<<std::char_traits<char> >",
- "(std::basic_ostream<char, std::char_traits<char> >&, char const*)", "",
- "std::operator<<<std::char_traits<char> >"},
- {"operator delete[](void*, clang::ASTContext const&, unsigned long)", "",
- "operator delete[]", "(void*, clang::ASTContext const&, unsigned long)",
- "", "operator delete[]"},
- {"llvm::Optional<clang::PostInitializer>::operator bool() const",
- "llvm::Optional<clang::PostInitializer>", "operator bool", "()", "const",
- "llvm::Optional<clang::PostInitializer>::operator bool"},
- {"(anonymous namespace)::FactManager::operator[](unsigned short)",
- "(anonymous namespace)::FactManager", "operator[]", "(unsigned short)",
- "", "(anonymous namespace)::FactManager::operator[]"},
- {"const int& std::map<int, pair<short, int>>::operator[](short) const",
- "std::map<int, pair<short, int>>", "operator[]", "(short)", "const",
- "std::map<int, pair<short, int>>::operator[]"},
- {"CompareInsn::operator()(llvm::StringRef, InsnMatchEntry const&)",
- "CompareInsn", "operator()", "(llvm::StringRef, InsnMatchEntry const&)",
- "", "CompareInsn::operator()"},
- {"llvm::Optional<llvm::MCFixupKind>::operator*() const &",
- "llvm::Optional<llvm::MCFixupKind>", "operator*", "()", "const &",
- "llvm::Optional<llvm::MCFixupKind>::operator*"},
- // Internal classes
- {"operator<<(Cls, Cls)::Subclass::function()",
- "operator<<(Cls, Cls)::Subclass", "function", "()", "",
- "operator<<(Cls, Cls)::Subclass::function"},
- {"SAEC::checkFunction(context&) const::CallBack::CallBack(int)",
- "SAEC::checkFunction(context&) const::CallBack", "CallBack", "(int)", "",
- "SAEC::checkFunction(context&) const::CallBack::CallBack"},
- // Anonymous namespace
- {"XX::(anonymous namespace)::anon_class::anon_func() const",
- "XX::(anonymous namespace)::anon_class", "anon_func", "()", "const",
- "XX::(anonymous namespace)::anon_class::anon_func"},
-
- // Lambda
- {"main::{lambda()#1}::operator()() const::{lambda()#1}::operator()() const",
- "main::{lambda()#1}::operator()() const::{lambda()#1}", "operator()", "()", "const",
- "main::{lambda()#1}::operator()() const::{lambda()#1}::operator()"},
-
- // Function pointers
- {"string (*f(vector<int>&&))(float)", "", "f", "(vector<int>&&)", "",
- "f"},
- {"void (*&std::_Any_data::_M_access<void (*)()>())()", "std::_Any_data",
- "_M_access<void (*)()>", "()", "",
- "std::_Any_data::_M_access<void (*)()>"},
- {"void (*(*(*(*(*(*(*(* const&func1(int))())())())())())())())()", "",
- "func1", "(int)", "", "func1"},
-
- // Decltype
- {"decltype(nullptr)&& std::forward<decltype(nullptr)>"
- "(std::remove_reference<decltype(nullptr)>::type&)",
- "std", "forward<decltype(nullptr)>",
- "(std::remove_reference<decltype(nullptr)>::type&)", "",
- "std::forward<decltype(nullptr)>"},
-
- // Templates
- {"void llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
- "addPass<llvm::VP>(llvm::VP)",
- "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>", "addPass<llvm::VP>",
- "(llvm::VP)", "",
- "llvm::PM<llvm::Module, llvm::AM<llvm::Module>>::"
- "addPass<llvm::VP>"},
- {"void std::vector<Class, std::allocator<Class> >"
- "::_M_emplace_back_aux<Class const&>(Class const&)",
- "std::vector<Class, std::allocator<Class> >",
- "_M_emplace_back_aux<Class const&>", "(Class const&)", "",
- "std::vector<Class, std::allocator<Class> >::"
- "_M_emplace_back_aux<Class const&>"},
- {"unsigned long llvm::countTrailingOnes<unsigned int>"
- "(unsigned int, llvm::ZeroBehavior)",
- "llvm", "countTrailingOnes<unsigned int>",
- "(unsigned int, llvm::ZeroBehavior)", "",
- "llvm::countTrailingOnes<unsigned int>"},
- {"std::enable_if<(10u)<(64), bool>::type llvm::isUInt<10u>(unsigned "
- "long)",
- "llvm", "isUInt<10u>", "(unsigned long)", "", "llvm::isUInt<10u>"},
- {"f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>()", "",
- "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>", "()", "",
- "f<A<operator<(X,Y)::Subclass>, sizeof(B)<sizeof(C)>"}};
-
- for (const auto &test : test_cases) {
- CPlusPlusLanguage::MethodName method(ConstString(test.input));
- EXPECT_TRUE(method.IsValid()) << test.input;
- if (method.IsValid()) {
- EXPECT_EQ(test.context, method.GetContext().str());
- EXPECT_EQ(test.basename, method.GetBasename().str());
- EXPECT_EQ(test.arguments, method.GetArguments().str());
- EXPECT_EQ(test.qualifiers, method.GetQualifiers().str());
- EXPECT_EQ(test.scope_qualified_name, method.GetScopeQualifiedName());
- }
- }
-}
-
-TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) {
- struct TestCase {
- std::string input;
- std::string context, basename;
- };
-
- TestCase test_cases[] = {
- {"main", "", "main"},
- {"main ", "", "main"},
- {"foo01::bar", "foo01", "bar"},
- {"foo::~bar", "foo", "~bar"},
- {"std::vector<int>::push_back", "std::vector<int>", "push_back"},
- {"operator<<(Cls, Cls)::Subclass::function",
- "operator<<(Cls, Cls)::Subclass", "function"},
- {"std::vector<Class, std::allocator<Class>>"
- "::_M_emplace_back_aux<Class const&>",
- "std::vector<Class, std::allocator<Class>>",
- "_M_emplace_back_aux<Class const&>"},
- {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"},
- {"`operator<<A>'::`2'::B<0>::operator>", "`operator<<A>'::`2'::B<0>",
- "operator>"},
- {"`anonymous namespace'::S::<<::__l2::Foo",
- "`anonymous namespace'::S::<<::__l2", "Foo"},
- // These cases are idiosyncratic in how clang generates debug info for
- // names when we have template parameters. They are not valid C++ names
- // but if we fix this we need to support them for older compilers.
- {"A::operator><A::B>", "A", "operator><A::B>"},
- {"operator><A::B>", "", "operator><A::B>"},
- {"A::operator<<A::B>", "A", "operator<<A::B>"},
- {"operator<<A::B>", "", "operator<<A::B>"},
- {"A::operator<<<A::B>", "A", "operator<<<A::B>"},
- {"operator<<<A::B>", "", "operator<<<A::B>"},
- };
-
- llvm::StringRef context, basename;
- for (const auto &test : test_cases) {
- EXPECT_TRUE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- test.input.c_str(), context, basename));
- EXPECT_EQ(test.context, context.str());
- EXPECT_EQ(test.basename, basename.str());
- }
-
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier("void", context,
- basename));
- EXPECT_FALSE(
- CPlusPlusLanguage::ExtractContextAndIdentifier("321", context, basename));
- EXPECT_FALSE(
- CPlusPlusLanguage::ExtractContextAndIdentifier("", context, basename));
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "selector:", context, basename));
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "selector:otherField:", context, basename));
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "abc::", context, basename));
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "f<A<B><C>>", context, basename));
-
- // We expect these cases to fail until we turn on C++2a
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "A::operator<=><A::B>", context, basename));
- EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier(
- "operator<=><A::B>", context, basename));
-}
-
-static std::set<std::string> FindAlternate(llvm::StringRef Name) {
- std::set<ConstString> Results;
- uint32_t Count = CPlusPlusLanguage::FindAlternateFunctionManglings(
- ConstString(Name), Results);
- EXPECT_EQ(Count, Results.size());
- std::set<std::string> Strings;
- for (ConstString Str : Results)
- Strings.insert(std::string(Str.GetStringRef()));
- return Strings;
-}
-
-TEST(CPlusPlusLanguage, FindAlternateFunctionManglings) {
- using namespace testing;
-
- EXPECT_THAT(FindAlternate("_ZN1A1fEv"),
- UnorderedElementsAre("_ZNK1A1fEv", "_ZLN1A1fEv"));
- EXPECT_THAT(FindAlternate("_ZN1A1fEa"), Contains("_ZN1A1fEc"));
- EXPECT_THAT(FindAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl"));
- EXPECT_THAT(FindAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm"));
- EXPECT_THAT(FindAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci"));
- EXPECT_THAT(FindAlternate("_ZN1AC1Ev"), Contains("_ZN1AC2Ev"));
- EXPECT_THAT(FindAlternate("_ZN1AD1Ev"), Contains("_ZN1AD2Ev"));
- EXPECT_THAT(FindAlternate("_bogus"), IsEmpty());
-}
-
-TEST(CPlusPlusLanguage, CPlusPlusNameParser) {
- // Don't crash.
- CPlusPlusNameParser((const char *)nullptr);
-}
+++ /dev/null
-add_lldb_unittest(HighlighterTests
- HighlighterTest.cpp
-
- LINK_LIBS
- lldbPluginCPlusPlusLanguage
- lldbPluginObjCLanguage
- lldbPluginObjCPlusPlusLanguage
- )
+++ /dev/null
-//===-- HighlighterTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Core/Highlighter.h"
-#include "lldb/Host/FileSystem.h"
-
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
-#include "Plugins/Language/ObjC/ObjCLanguage.h"
-#include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h"
-#include "TestingSupport/SubsystemRAII.h"
-
-using namespace lldb_private;
-
-namespace {
-class HighlighterTest : public testing::Test {
- SubsystemRAII<FileSystem, CPlusPlusLanguage, ObjCLanguage,
- ObjCPlusPlusLanguage>
- subsystems;
-};
-} // namespace
-
-static std::string getName(lldb::LanguageType type) {
- HighlighterManager m;
- return m.getHighlighterFor(type, "").GetName().str();
-}
-
-static std::string getName(llvm::StringRef path) {
- HighlighterManager m;
- return m.getHighlighterFor(lldb::eLanguageTypeUnknown, path).GetName().str();
-}
-
-TEST_F(HighlighterTest, HighlighterSelectionType) {
- EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus), "clang");
- EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_03), "clang");
- EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_11), "clang");
- EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_14), "clang");
- EXPECT_EQ(getName(lldb::eLanguageTypeObjC), "clang");
- EXPECT_EQ(getName(lldb::eLanguageTypeObjC_plus_plus), "clang");
-
- EXPECT_EQ(getName(lldb::eLanguageTypeUnknown), "none");
- EXPECT_EQ(getName(lldb::eLanguageTypeJulia), "none");
- EXPECT_EQ(getName(lldb::eLanguageTypeHaskell), "none");
-}
-
-TEST_F(HighlighterTest, HighlighterSelectionPath) {
- EXPECT_EQ(getName("myfile.cc"), "clang");
- EXPECT_EQ(getName("moo.cpp"), "clang");
- EXPECT_EQ(getName("mar.cxx"), "clang");
- EXPECT_EQ(getName("foo.C"), "clang");
- EXPECT_EQ(getName("bar.CC"), "clang");
- EXPECT_EQ(getName("a/dir.CC"), "clang");
- EXPECT_EQ(getName("/a/dir.hpp"), "clang");
- EXPECT_EQ(getName("header.h"), "clang");
- EXPECT_EQ(getName("foo.m"), "clang");
- EXPECT_EQ(getName("foo.mm"), "clang");
-
- EXPECT_EQ(getName(""), "none");
- EXPECT_EQ(getName("/dev/null"), "none");
- EXPECT_EQ(getName("Factory.java"), "none");
- EXPECT_EQ(getName("poll.py"), "none");
- EXPECT_EQ(getName("reducer.hs"), "none");
-}
-
-TEST_F(HighlighterTest, FallbackHighlighter) {
- HighlighterManager mgr;
- const Highlighter &h =
- mgr.getHighlighterFor(lldb::eLanguageTypePascal83, "foo.pas");
-
- HighlightStyle style;
- style.identifier.Set("[", "]");
- style.semicolons.Set("<", ">");
-
- const char *code = "program Hello;";
- std::string output = h.Highlight(style, code, llvm::Optional<size_t>());
-
- EXPECT_STREQ(output.c_str(), code);
-}
-
-static std::string
-highlightDefault(llvm::StringRef code, HighlightStyle style,
- llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) {
- HighlighterManager mgr;
- return mgr.getDefaultHighlighter().Highlight(style, code, cursor);
-}
-
-TEST_F(HighlighterTest, DefaultHighlighter) {
- const char *code = "int my_main() { return 22; } \n";
-
- HighlightStyle style;
- EXPECT_EQ(code, highlightDefault(code, style));
-}
-
-TEST_F(HighlighterTest, DefaultHighlighterWithCursor) {
- HighlightStyle style;
- style.selected.Set("<c>", "</c>");
- EXPECT_EQ("<c>a</c> bc", highlightDefault("a bc", style, 0));
- EXPECT_EQ("a<c> </c>bc", highlightDefault("a bc", style, 1));
- EXPECT_EQ("a <c>b</c>c", highlightDefault("a bc", style, 2));
- EXPECT_EQ("a b<c>c</c>", highlightDefault("a bc", style, 3));
-}
-
-TEST_F(HighlighterTest, DefaultHighlighterWithCursorOutOfBounds) {
- HighlightStyle style;
- style.selected.Set("<c>", "</c>");
- EXPECT_EQ("a bc", highlightDefault("a bc", style, 4));
-}
-// Tests highlighting with the Clang highlighter.
-
-static std::string
-highlightC(llvm::StringRef code, HighlightStyle style,
- llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) {
- HighlighterManager mgr;
- const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c");
- return h.Highlight(style, code, cursor);
-}
-
-TEST_F(HighlighterTest, ClangEmptyInput) {
- HighlightStyle s;
- EXPECT_EQ("", highlightC("", s));
-}
-
-TEST_F(HighlighterTest, ClangScalarLiterals) {
- HighlightStyle s;
- s.scalar_literal.Set("<scalar>", "</scalar>");
-
- EXPECT_EQ(" int i = <scalar>22</scalar>;", highlightC(" int i = 22;", s));
-}
-
-TEST_F(HighlighterTest, ClangStringLiterals) {
- HighlightStyle s;
- s.string_literal.Set("<str>", "</str>");
-
- EXPECT_EQ("const char *f = 22 + <str>\"foo\"</str>;",
- highlightC("const char *f = 22 + \"foo\";", s));
-}
-
-TEST_F(HighlighterTest, ClangUnterminatedString) {
- HighlightStyle s;
- s.string_literal.Set("<str>", "</str>");
-
- EXPECT_EQ(" f = \"", highlightC(" f = \"", s));
-}
-
-TEST_F(HighlighterTest, Keywords) {
- HighlightStyle s;
- s.keyword.Set("<k>", "</k>");
-
- EXPECT_EQ(" <k>return</k> 1; ", highlightC(" return 1; ", s));
-}
-
-TEST_F(HighlighterTest, Colons) {
- HighlightStyle s;
- s.colon.Set("<c>", "</c>");
-
- EXPECT_EQ("foo<c>:</c><c>:</c>bar<c>:</c>", highlightC("foo::bar:", s));
-}
-
-TEST_F(HighlighterTest, ClangBraces) {
- HighlightStyle s;
- s.braces.Set("<b>", "</b>");
-
- EXPECT_EQ("a<b>{</b><b>}</b>", highlightC("a{}", s));
-}
-
-TEST_F(HighlighterTest, ClangSquareBrackets) {
- HighlightStyle s;
- s.square_brackets.Set("<sb>", "</sb>");
-
- EXPECT_EQ("a<sb>[</sb><sb>]</sb>", highlightC("a[]", s));
-}
-
-TEST_F(HighlighterTest, ClangCommas) {
- HighlightStyle s;
- s.comma.Set("<comma>", "</comma>");
-
- EXPECT_EQ(" bool f = foo()<comma>,</comma> 1;",
- highlightC(" bool f = foo(), 1;", s));
-}
-
-TEST_F(HighlighterTest, ClangPPDirectives) {
- HighlightStyle s;
- s.pp_directive.Set("<pp>", "</pp>");
-
- EXPECT_EQ("<pp>#</pp><pp>include</pp><pp> </pp><pp>\"foo\"</pp><pp> </pp>//c",
- highlightC("#include \"foo\" //c", s));
-}
-
-TEST_F(HighlighterTest, ClangPreserveNewLine) {
- HighlightStyle s;
- s.comment.Set("<cc>", "</cc>");
-
- EXPECT_EQ("<cc>//</cc>\n", highlightC("//\n", s));
-}
-
-TEST_F(HighlighterTest, ClangTrailingBackslashBeforeNewline) {
- HighlightStyle s;
-
- EXPECT_EQ("\\\n", highlightC("\\\n", s));
- EXPECT_EQ("\\\r\n", highlightC("\\\r\n", s));
-
- EXPECT_EQ("#define a \\\n", highlightC("#define a \\\n", s));
- EXPECT_EQ("#define a \\\r\n", highlightC("#define a \\\r\n", s));
- EXPECT_EQ("#define a \\\r", highlightC("#define a \\\r", s));
-}
-
-TEST_F(HighlighterTest, ClangTrailingBackslashWithWhitespace) {
- HighlightStyle s;
-
- EXPECT_EQ("\\ \n", highlightC("\\ \n", s));
- EXPECT_EQ("\\ \t\n", highlightC("\\ \t\n", s));
- EXPECT_EQ("\\ \n", highlightC("\\ \n", s));
- EXPECT_EQ("\\\t\n", highlightC("\\\t\n", s));
-
- EXPECT_EQ("#define a \\ \n", highlightC("#define a \\ \n", s));
- EXPECT_EQ("#define a \\ \t\n", highlightC("#define a \\ \t\n", s));
- EXPECT_EQ("#define a \\ \n", highlightC("#define a \\ \n", s));
- EXPECT_EQ("#define a \\\t\n", highlightC("#define a \\\t\n", s));
-}
-
-TEST_F(HighlighterTest, ClangTrailingBackslashMissingNewLine) {
- HighlightStyle s;
- EXPECT_EQ("\\", highlightC("\\", s));
- EXPECT_EQ("#define a\\", highlightC("#define a\\", s));
-}
-
-TEST_F(HighlighterTest, ClangComments) {
- HighlightStyle s;
- s.comment.Set("<cc>", "</cc>");
-
- EXPECT_EQ(" <cc>/*com */</cc> <cc>// com /*n*/</cc>",
- highlightC(" /*com */ // com /*n*/", s));
-}
-
-TEST_F(HighlighterTest, ClangOperators) {
- HighlightStyle s;
- s.operators.Set("[", "]");
-
- EXPECT_EQ(" 1[+]2[/]a[*]f[&]x[|][~]l", highlightC(" 1+2/a*f&x|~l", s));
-}
-
-TEST_F(HighlighterTest, ClangIdentifiers) {
- HighlightStyle s;
- s.identifier.Set("<id>", "</id>");
-
- EXPECT_EQ(" <id>foo</id> <id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s));
-}
-
-TEST_F(HighlighterTest, ClangCursorPos) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
-
- EXPECT_EQ("<c> </c>foo c = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 0));
- EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 1));
- EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 2));
- EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 3));
- EXPECT_EQ(" foo<c> </c>c = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 4));
- EXPECT_EQ(" foo <c>c</c> = bar(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 5));
-}
-
-TEST_F(HighlighterTest, ClangCursorPosEndOfLine) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
-
- EXPECT_EQ("f", highlightC("f", s, 1));
-}
-
-TEST_F(HighlighterTest, ClangCursorOutOfBounds) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
- EXPECT_EQ("f", highlightC("f", s, 2));
- EXPECT_EQ("f", highlightC("f", s, 3));
- EXPECT_EQ("f", highlightC("f", s, 4));
-}
-
-TEST_F(HighlighterTest, ClangCursorPosBeforeOtherToken) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
- s.identifier.Set("<id>", "</id>");
-
- EXPECT_EQ("<c> </c><id>foo</id> <id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 0));
-}
-
-TEST_F(HighlighterTest, ClangCursorPosAfterOtherToken) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
- s.identifier.Set("<id>", "</id>");
-
- EXPECT_EQ(" <id>foo</id><c> </c><id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 4));
-}
-
-TEST_F(HighlighterTest, ClangCursorPosInOtherToken) {
- HighlightStyle s;
- s.selected.Set("<c>", "</c>");
- s.identifier.Set("<id>", "</id>");
-
- EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 1));
- EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 2));
- EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
- highlightC(" foo c = bar(); return 1;", s, 3));
-}
+++ /dev/null
-//===-- BreakpadRecordsTest.cpp -------------------------------------------===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ObjectFile/Breakpad/BreakpadRecords.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::breakpad;
-
-TEST(Record, classify) {
- EXPECT_EQ(Record::Module, Record::classify("MODULE"));
- EXPECT_EQ(Record::Info, Record::classify("INFO"));
- EXPECT_EQ(Record::File, Record::classify("FILE"));
- EXPECT_EQ(Record::Func, Record::classify("FUNC"));
- EXPECT_EQ(Record::Public, Record::classify("PUBLIC"));
- EXPECT_EQ(Record::StackCFI, Record::classify("STACK CFI"));
- EXPECT_EQ(Record::StackWin, Record::classify("STACK WIN"));
-
- // Any obviously incorrect lines will be classified as such.
- EXPECT_EQ(llvm::None, Record::classify("STACK"));
- EXPECT_EQ(llvm::None, Record::classify("STACK CODE_ID"));
- EXPECT_EQ(llvm::None, Record::classify("CODE_ID"));
-
- // Any line which does not start with a known keyword will be classified as a
- // line record, as those are the only ones that start without a keyword.
- EXPECT_EQ(Record::Line, Record::classify("deadbeef"));
- EXPECT_EQ(Record::Line, Record::classify("12"));
-}
-
-TEST(ModuleRecord, parse) {
- EXPECT_EQ(ModuleRecord(llvm::Triple::Linux, llvm::Triple::x86_64,
- UUID::fromData("@ABCDEFGHIJKLMNO", 16)),
- ModuleRecord::parse(
- "MODULE Linux x86_64 404142434445464748494a4b4c4d4e4f0 a.out"));
-
- EXPECT_EQ(llvm::None, ModuleRecord::parse("MODULE"));
- EXPECT_EQ(llvm::None, ModuleRecord::parse("MODULE Linux"));
- EXPECT_EQ(llvm::None, ModuleRecord::parse("MODULE Linux x86_64"));
- EXPECT_EQ(llvm::None,
- ModuleRecord::parse("MODULE Linux x86_64 deadbeefbaadf00d"));
-}
-
-TEST(InfoRecord, parse) {
- EXPECT_EQ(InfoRecord(UUID::fromData("@ABCDEFGHIJKLMNO", 16)),
- InfoRecord::parse("INFO CODE_ID 404142434445464748494a4b4c4d4e4f"));
- EXPECT_EQ(InfoRecord(UUID()), InfoRecord::parse("INFO CODE_ID 47 a.exe"));
-
- EXPECT_EQ(llvm::None, InfoRecord::parse("INFO"));
- EXPECT_EQ(llvm::None, InfoRecord::parse("INFO CODE_ID"));
-}
-
-TEST(FileRecord, parse) {
- EXPECT_EQ(FileRecord(47, "foo"), FileRecord::parse("FILE 47 foo"));
- EXPECT_EQ(llvm::None, FileRecord::parse("FILE 47"));
- EXPECT_EQ(llvm::None, FileRecord::parse("FILE"));
- EXPECT_EQ(llvm::None, FileRecord::parse(""));
-}
-
-TEST(FuncRecord, parse) {
- EXPECT_EQ(FuncRecord(true, 0x47, 0x7, 0x8, "foo"),
- FuncRecord::parse("FUNC m 47 7 8 foo"));
- EXPECT_EQ(FuncRecord(false, 0x47, 0x7, 0x8, "foo"),
- FuncRecord::parse("FUNC 47 7 8 foo"));
-
- EXPECT_EQ(llvm::None, FuncRecord::parse("PUBLIC 47 7 8 foo"));
- EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC 47 7 8"));
- EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC 47 7"));
- EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC 47"));
- EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC m"));
- EXPECT_EQ(llvm::None, FuncRecord::parse("FUNC"));
-}
-
-TEST(LineRecord, parse) {
- EXPECT_EQ(LineRecord(0x47, 0x74, 47, 74), LineRecord::parse("47 74 47 74"));
- EXPECT_EQ(llvm::None, LineRecord::parse("47 74 47"));
- EXPECT_EQ(llvm::None, LineRecord::parse("47 74"));
- EXPECT_EQ(llvm::None, LineRecord::parse("47"));
- EXPECT_EQ(llvm::None, LineRecord::parse(""));
- EXPECT_EQ(llvm::None, LineRecord::parse("FUNC"));
-}
-
-TEST(PublicRecord, parse) {
- EXPECT_EQ(PublicRecord(true, 0x47, 0x8, "foo"),
- PublicRecord::parse("PUBLIC m 47 8 foo"));
- EXPECT_EQ(PublicRecord(false, 0x47, 0x8, "foo"),
- PublicRecord::parse("PUBLIC 47 8 foo"));
-
- EXPECT_EQ(llvm::None, PublicRecord::parse("FUNC 47 8 foo"));
- EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC 47 8"));
- EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC 47"));
- EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC m"));
- EXPECT_EQ(llvm::None, PublicRecord::parse("PUBLIC"));
-}
-
-TEST(StackCFIRecord, parse) {
- EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 + $eip: .cfa 4 - ^"),
- StackCFIRecord::parse(
- "STACK CFI INIT 47 8 .cfa: $esp 4 + $eip: .cfa 4 - ^"));
-
- EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: $esp 4 +"),
- StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: $esp 4 + "));
-
- EXPECT_EQ(StackCFIRecord(0x47, llvm::None, ".cfa: $esp 4 +"),
- StackCFIRecord::parse("STACK CFI 47 .cfa: $esp 4 +"));
-
- // The validity of the register value expressions is not checked
- EXPECT_EQ(StackCFIRecord(0x47, 0x8, ".cfa: ^ ^ ^"),
- StackCFIRecord::parse("STACK CFI INIT 47 8 .cfa: ^ ^ ^"));
-
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI INIT 47"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI INIT"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK CFI"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("STACK"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("FILE 47 foo"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("42 47"));
-}
-
-TEST(StackWinRecord, parse) {
- EXPECT_EQ(
- StackWinRecord(0x47, 0x8, 3, 4, 5, llvm::StringRef("$eip $esp ^ =")),
- StackWinRecord::parse("STACK WIN 4 47 8 1 2 3 4 5 6 1 $eip $esp ^ ="));
-
- EXPECT_EQ(llvm::None, StackWinRecord::parse(
- "STACK WIN 0 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
- EXPECT_EQ(llvm::None,
- StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0 0 1"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse(
- "STACK WIN 3 47 8 1 0 0 0 0 0 1 $eip $esp ^ ="));
- EXPECT_EQ(llvm::None,
- StackWinRecord::parse("STACK WIN 3 47 8 1 0 0 0 0 0 0 1"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse(
- "STACK WIN 4 47 8 1 0 0 0 0 1 $eip $esp ^ ="));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0 0"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0 0"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0 0"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0 0"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1 0"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8 1"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47 8"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4 47"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN 4"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK WIN"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse("STACK"));
- EXPECT_EQ(llvm::None, StackWinRecord::parse(""));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("FILE 47 foo"));
- EXPECT_EQ(llvm::None, StackCFIRecord::parse("42 47"));
-}
+++ /dev/null
-add_lldb_unittest(ObjectFileBreakpadTests
- BreakpadRecordsTest.cpp
-
- LINK_LIBS
- lldbPluginObjectFileBreakpad
- )
+++ /dev/null
-add_subdirectory(Breakpad)
-add_subdirectory(ELF)
-add_subdirectory(MachO)
-add_subdirectory(PECOFF)
+++ /dev/null
-add_lldb_unittest(ObjectFileELFTests
- TestObjectFileELF.cpp
-
- LINK_LIBS
- lldbPluginObjectFileELF
- lldbPluginSymbolFileSymtab
- lldbCore
- lldbUtilityHelpers
- LLVMTestingSupport
- )
-
-set(test_inputs
- early-section-headers.so
- )
-add_unittest_inputs(ObjectFileELFTests "${test_inputs}")
+++ /dev/null
-//===-- TestObjectFileELF.cpp ---------------------------------------------===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-class ObjectFileELFTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
- subsystems;
-};
-
-TEST_F(ObjectFileELFTest, SectionsResolveConsistently) {
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_X86_64
- Entry: 0x0000000000400180
-Sections:
- - Name: .note.gnu.build-id
- Type: SHT_NOTE
- Flags: [ SHF_ALLOC ]
- Address: 0x0000000000400158
- AddressAlign: 0x0000000000000004
- Content: 040000001400000003000000474E55003F3EC29E3FD83E49D18C4D49CD8A730CC13117B6
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x0000000000400180
- AddressAlign: 0x0000000000000010
- Content: 554889E58B042500106000890425041060005DC3
- - Name: .data
- Type: SHT_PROGBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000601000
- AddressAlign: 0x0000000000000004
- Content: 2F000000
- - Name: .bss
- Type: SHT_NOBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000601004
- AddressAlign: 0x0000000000000004
- Size: 0x0000000000000004
-Symbols:
- - Name: Y
- Type: STT_OBJECT
- Section: .data
- Value: 0x0000000000601000
- Size: 0x0000000000000004
- Binding: STB_GLOBAL
- - Name: _start
- Type: STT_FUNC
- Section: .text
- Value: 0x0000000000400180
- Size: 0x0000000000000014
- Binding: STB_GLOBAL
- - Name: X
- Type: STT_OBJECT
- Section: .bss
- Value: 0x0000000000601004
- Size: 0x0000000000000004
- Binding: STB_GLOBAL
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
- SectionList *list = module_sp->GetSectionList();
- ASSERT_NE(nullptr, list);
-
- auto bss_sp = list->FindSectionByName(ConstString(".bss"));
- ASSERT_NE(nullptr, bss_sp);
- auto data_sp = list->FindSectionByName(ConstString(".data"));
- ASSERT_NE(nullptr, data_sp);
- auto text_sp = list->FindSectionByName(ConstString(".text"));
- ASSERT_NE(nullptr, text_sp);
-
- const Symbol *X = module_sp->FindFirstSymbolWithNameAndType(ConstString("X"),
- eSymbolTypeAny);
- ASSERT_NE(nullptr, X);
- EXPECT_EQ(bss_sp, X->GetAddress().GetSection());
-
- const Symbol *Y = module_sp->FindFirstSymbolWithNameAndType(ConstString("Y"),
- eSymbolTypeAny);
- ASSERT_NE(nullptr, Y);
- EXPECT_EQ(data_sp, Y->GetAddress().GetSection());
-
- const Symbol *start = module_sp->FindFirstSymbolWithNameAndType(
- ConstString("_start"), eSymbolTypeAny);
- ASSERT_NE(nullptr, start);
- EXPECT_EQ(text_sp, start->GetAddress().GetSection());
-}
-
-// Test that GetModuleSpecifications works on an "atypical" object file which
-// has section headers right after the ELF header (instead of the more common
-// layout where the section headers are at the very end of the object file).
-//
-// Test file generated with yaml2obj (@svn rev 324254) from the following input:
-/*
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_X86_64
- Entry: 0x00000000004003D0
-Sections:
- - Name: .note.gnu.build-id
- Type: SHT_NOTE
- Flags: [ SHF_ALLOC ]
- Address: 0x0000000000400274
- AddressAlign: 0x0000000000000004
- Content: 040000001400000003000000474E55001B8A73AC238390E32A7FF4AC8EBE4D6A41ECF5C9
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x00000000004003D0
- AddressAlign: 0x0000000000000010
- Content: DEADBEEFBAADF00D
-...
-*/
-TEST_F(ObjectFileELFTest, GetModuleSpecifications_EarlySectionHeaders) {
- std::string SO = GetInputFilePath("early-section-headers.so");
- ModuleSpecList Specs;
- ASSERT_EQ(1u, ObjectFile::GetModuleSpecifications(FileSpec(SO), 0, 0, Specs));
- ModuleSpec Spec;
- ASSERT_TRUE(Specs.GetModuleSpecAtIndex(0, Spec)) ;
- UUID Uuid;
- Uuid.SetFromStringRef("1b8a73ac238390e32a7ff4ac8ebe4d6a41ecf5c9");
- EXPECT_EQ(Spec.GetUUID(), Uuid);
-}
-
-TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmThumbAddressClass) {
- /*
- // nosym-entrypoint-arm-thumb.s
- .thumb_func
- _start:
- mov r0, #42
- mov r7, #1
- svc #0
- // arm-linux-androideabi-as nosym-entrypoint-arm-thumb.s
- // -o nosym-entrypoint-arm-thumb.o
- // arm-linux-androideabi-ld nosym-entrypoint-arm-thumb.o
- // -o nosym-entrypoint-arm-thumb -e 0x8075 -s
- */
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS32
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_ARM
- Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
- Entry: 0x0000000000008075
-Sections:
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x0000000000008074
- AddressAlign: 0x0000000000000002
- Content: 2A20012700DF
- - Name: .data
- Type: SHT_PROGBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000009000
- AddressAlign: 0x0000000000000001
- Content: ''
- - Name: .bss
- Type: SHT_NOBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000009000
- AddressAlign: 0x0000000000000001
- - Name: .note.gnu.gold-version
- Type: SHT_NOTE
- AddressAlign: 0x0000000000000004
- Content: 040000000900000004000000474E5500676F6C6420312E3131000000
- - Name: .ARM.attributes
- Type: SHT_ARM_ATTRIBUTES
- AddressAlign: 0x0000000000000001
- Content: '4113000000616561626900010900000006020901'
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
-
- auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
- ASSERT_TRUE(entry_point_addr.GetOffset() & 1);
- // Decrease the offsite by 1 to make it into a breakable address since this
- // is Thumb.
- entry_point_addr.SetOffset(entry_point_addr.GetOffset() - 1);
- ASSERT_EQ(entry_point_addr.GetAddressClass(),
- AddressClass::eCodeAlternateISA);
-}
-
-TEST_F(ObjectFileELFTest, GetSymtab_NoSymEntryPointArmAddressClass) {
- /*
- // nosym-entrypoint-arm.s
- _start:
- movs r0, #42
- movs r7, #1
- svc #0
- // arm-linux-androideabi-as nosym-entrypoint-arm.s
- // -o nosym-entrypoint-arm.o
- // arm-linux-androideabi-ld nosym-entrypoint-arm.o
- // -o nosym-entrypoint-arm -e 0x8074 -s
- */
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS32
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_ARM
- Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ]
- Entry: 0x0000000000008074
-Sections:
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x0000000000008074
- AddressAlign: 0x0000000000000004
- Content: 2A00A0E30170A0E3000000EF
- - Name: .data
- Type: SHT_PROGBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000009000
- AddressAlign: 0x0000000000000001
- Content: ''
- - Name: .bss
- Type: SHT_NOBITS
- Flags: [ SHF_WRITE, SHF_ALLOC ]
- Address: 0x0000000000009000
- AddressAlign: 0x0000000000000001
- - Name: .note.gnu.gold-version
- Type: SHT_NOTE
- AddressAlign: 0x0000000000000004
- Content: 040000000900000004000000474E5500676F6C6420312E3131000000
- - Name: .ARM.attributes
- Type: SHT_ARM_ATTRIBUTES
- AddressAlign: 0x0000000000000001
- Content: '4113000000616561626900010900000006010801'
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
-
- auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress();
- ASSERT_EQ(entry_point_addr.GetAddressClass(), AddressClass::eCode);
-}
+++ /dev/null
-add_lldb_unittest(ObjectFileMachOTests
- TestObjectFileMachO.cpp
-
- LINK_LIBS
- lldbPluginObjectFileMachO
- lldbPluginSymbolFileSymtab
- lldbCore
- lldbUtilityHelpers
- LLVMTestingSupport
- )
+++ /dev/null
-//===-- ObjectFileMachOTest.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Host/HostInfo.h"
-#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/lldb-defines.h"
-#include "gtest/gtest.h"
-
-#ifdef __APPLE__
-#include <dlfcn.h>
-#endif
-
-using namespace lldb_private;
-using namespace llvm;
-
-namespace {
-class ObjectFileMachOTest : public ::testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO> subsystems;
-};
-} // namespace
-
-#if defined(__APPLE__)
-TEST_F(ObjectFileMachOTest, ModuleFromSharedCacheInfo) {
- SharedCacheImageInfo image_info =
- HostInfo::GetSharedCacheImageInfo("/usr/lib/libobjc.A.dylib");
- EXPECT_TRUE(image_info.uuid);
- EXPECT_TRUE(image_info.data_sp);
-
- ModuleSpec spec(FileSpec(), UUID(), image_info.data_sp);
- lldb::ModuleSP module = std::make_shared<Module>(spec);
- ObjectFile *OF = module->GetObjectFile();
- ASSERT_TRUE(llvm::isa<ObjectFileMachO>(OF));
- EXPECT_TRUE(
- OF->GetArchitecture().IsCompatibleMatch(HostInfo::GetArchitecture()));
- Symtab *symtab = OF->GetSymtab();
- ASSERT_NE(symtab, nullptr);
- void *libobjc = dlopen("/usr/lib/libobjc.A.dylib", RTLD_LAZY);
- ASSERT_NE(libobjc, nullptr);
-
- // This function checks that if we read something from the
- // ObjectFile we get through the shared cache in-mmeory
- // buffer, it matches what we get by reading directly the
- // memory of the symbol.
- auto check_symbol = [&](const char *sym_name) {
- std::vector<uint32_t> symbol_indices;
- symtab->FindAllSymbolsWithNameAndType(ConstString(sym_name),
- lldb::eSymbolTypeAny, symbol_indices);
- EXPECT_EQ(symbol_indices.size(), 1u);
-
- Symbol *sym = symtab->SymbolAtIndex(symbol_indices[0]);
- ASSERT_NE(sym, nullptr);
- Address base = sym->GetAddress();
- size_t size = sym->GetByteSize();
- ASSERT_NE(size, 0u);
- uint8_t buffer[size];
- EXPECT_EQ(OF->ReadSectionData(base.GetSection().get(), base.GetOffset(),
- buffer, size),
- size);
-
- void *sym_addr = dlsym(libobjc, sym_name);
- ASSERT_NE(sym_addr, nullptr);
- EXPECT_EQ(memcmp(buffer, sym_addr, size), 0);
- };
-
- // Read a symbol from the __TEXT segment...
- check_symbol("objc_msgSend");
- // ... and one from the __DATA segment
- check_symbol("OBJC_CLASS_$_NSObject");
-}
-#endif
+++ /dev/null
-add_lldb_unittest(ObjectFilePECOFFTests
- TestPECallFrameInfo.cpp
-
- LINK_LIBS
- lldbUtilityHelpers
- lldbPluginObjectFilePECOFF
- LLVMTestingSupport
- )
+++ /dev/null
-//===-- TestPECallFrameInfo.cpp -------------------------------------------===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/Module.h"
-#include "lldb/Symbol/CallFrameInfo.h"
-#include "lldb/Symbol/UnwindPlan.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-class PECallFrameInfoTest : public testing::Test {
- SubsystemRAII<FileSystem, ObjectFilePECOFF> subsystems;
-
-protected:
- void GetUnwindPlan(addr_t file_addr, UnwindPlan &plan) const;
-};
-
-void PECallFrameInfoTest::GetUnwindPlan(addr_t file_addr, UnwindPlan &plan) const {
- llvm::Expected<TestFile> ExpectedFile = TestFile::fromYaml(
- R"(
---- !COFF
-OptionalHeader:
- AddressOfEntryPoint: 0
- ImageBase: 16777216
- SectionAlignment: 4096
- FileAlignment: 512
- MajorOperatingSystemVersion: 6
- MinorOperatingSystemVersion: 0
- MajorImageVersion: 0
- MinorImageVersion: 0
- MajorSubsystemVersion: 6
- MinorSubsystemVersion: 0
- Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
- DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
- SizeOfStackReserve: 1048576
- SizeOfStackCommit: 4096
- SizeOfHeapReserve: 1048576
- SizeOfHeapCommit: 4096
- ExportTable:
- RelativeVirtualAddress: 0
- Size: 0
- ImportTable:
- RelativeVirtualAddress: 0
- Size: 0
- ResourceTable:
- RelativeVirtualAddress: 0
- Size: 0
- ExceptionTable:
- RelativeVirtualAddress: 12288
- Size: 60
- CertificateTable:
- RelativeVirtualAddress: 0
- Size: 0
- BaseRelocationTable:
- RelativeVirtualAddress: 0
- Size: 0
- Debug:
- RelativeVirtualAddress: 0
- Size: 0
- Architecture:
- RelativeVirtualAddress: 0
- Size: 0
- GlobalPtr:
- RelativeVirtualAddress: 0
- Size: 0
- TlsTable:
- RelativeVirtualAddress: 0
- Size: 0
- LoadConfigTable:
- RelativeVirtualAddress: 0
- Size: 0
- BoundImport:
- RelativeVirtualAddress: 0
- Size: 0
- IAT:
- RelativeVirtualAddress: 0
- Size: 0
- DelayImportDescriptor:
- RelativeVirtualAddress: 0
- Size: 0
- ClrRuntimeHeader:
- RelativeVirtualAddress: 0
- Size: 0
-header:
- Machine: IMAGE_FILE_MACHINE_AMD64
- Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
-sections:
- - Name: .text
- Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
- VirtualAddress: 4096
- VirtualSize: 4096
- - Name: .rdata
- Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
- VirtualAddress: 8192
- VirtualSize: 68
- SectionData: 010C06000C3208F006E00470036002302105020005540D0000100000001100000020000019400E352F74670028646600213465001A3315015E000EF00CE00AD008C00650
-
-
-# Unwind info at 0x2000:
-# 01 0C 06 00 No chained info, prolog size = 0xC, unwind codes size is 6 words, no frame register
-# 0C 32 UOP_AllocSmall(2) 3 * 8 + 8 bytes, offset in prolog is 0xC
-# 08 F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 8
-# 06 E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 6
-# 04 70 UOP_PushNonVol(0) RDI(7), offset in prolog is 4
-# 03 60 UOP_PushNonVol(0) RSI(6), offset in prolog is 3
-# 02 30 UOP_PushNonVol(0) RBX(3), offset in prolog is 2
-# Corresponding prolog:
-# 00 push rbx
-# 02 push rsi
-# 03 push rdi
-# 04 push r14
-# 06 push r15
-# 08 sub rsp, 20h
-
-# Unwind info at 0x2010:
-# 21 05 02 00 Has chained info, prolog size = 5, unwind codes size is 2 words, no frame register
-# 05 54 0D 00 UOP_SaveNonVol(4) RBP(5) to RSP + 0xD * 8, offset in prolog is 5
-# Chained runtime function:
-# 00 10 00 00 Start address is 0x1000
-# 00 11 00 00 End address is 0x1100
-# 00 20 00 00 Unwind info RVA is 0x2000
-# Corresponding prolog:
-# 00 mov [rsp+68h], rbp
-
-# Unwind info at 0x2024:
-# 19 40 0E 35 No chained info, prolog size = 0x40, unwind codes size is 0xE words, frame register is RBP, frame register offset is RSP + 3 * 16
-# 2F 74 67 00 UOP_SaveNonVol(4) RDI(7) to RSP + 0x67 * 8, offset in prolog is 0x2F
-# 28 64 66 00 UOP_SaveNonVol(4) RSI(6) to RSP + 0x66 * 8, offset in prolog is 0x28
-# 21 34 65 00 UOP_SaveNonVol(4) RBX(3) to RSP + 0x65 * 8, offset in prolog is 0x21
-# 1A 33 UOP_SetFPReg(3), offset in prolog is 0x1A
-# 15 01 5E 00 UOP_AllocLarge(1) 0x5E * 8 bytes, offset in prolog is 0x15
-# 0E F0 UOP_PushNonVol(0) R15(0xF), offset in prolog is 0xE
-# 0C E0 UOP_PushNonVol(0) R14(0xE), offset in prolog is 0xC
-# 0A D0 UOP_PushNonVol(0) R13(0xD), offset in prolog is 0xA
-# 08 C0 UOP_PushNonVol(0) R12(0xC), offset in prolog is 8
-# 06 50 UOP_PushNonVol(0) RBP(5), offset in prolog is 6
-# Corresponding prolog:
-# 00 mov [rsp+8], rcx
-# 05 push rbp
-# 06 push r12
-# 08 push r13
-# 0A push r14
-# 0C push r15
-# 0E sub rsp, 2F0h
-# 15 lea rbp, [rsp+30h]
-# 1A mov [rbp+2F8h], rbx
-# 21 mov [rbp+300h], rsi
-# 28 mov [rbp+308h], rdi
-
- - Name: .pdata
- Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
- VirtualAddress: 12288
- VirtualSize: 60
- SectionData: 000000000000000000000000000000000000000000000000001000000011000000200000001100000012000010200000001200000013000024200000
-
-# 00 00 00 00
-# 00 00 00 00 Test correct processing of empty runtime functions at begin
-# 00 00 00 00
-
-# 00 00 00 00
-# 00 00 00 00 Test correct processing of empty runtime functions at begin
-# 00 00 00 00
-
-# 00 10 00 00 Start address is 0x1000
-# 00 11 00 00 End address is 0x1100
-# 00 20 00 00 Unwind info RVA is 0x2000
-
-# 00 11 00 00 Start address is 0x1100
-# 00 12 00 00 End address is 0x1200
-# 10 20 00 00 Unwind info RVA is 0x2010
-
-# 00 12 00 00 Start address is 0x1200
-# 00 13 00 00 End address is 0x1300
-# 24 20 00 00 Unwind info RVA is 0x2024
-
-symbols: []
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- ModuleSP module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
- ObjectFile *object_file = module_sp->GetObjectFile();
- ASSERT_NE(object_file, nullptr);
-
- std::unique_ptr<CallFrameInfo> cfi = object_file->CreateCallFrameInfo();
- ASSERT_NE(cfi.get(), nullptr);
-
- SectionList *sect_list = object_file->GetSectionList();
- ASSERT_NE(sect_list, nullptr);
-
- EXPECT_TRUE(cfi->GetUnwindPlan(Address(file_addr, sect_list), plan));
-}
-
-TEST_F(PECallFrameInfoTest, Basic_eh) {
- UnwindPlan plan(eRegisterKindLLDB);
- GetUnwindPlan(0x1001080, plan);
- EXPECT_EQ(plan.GetRowCount(), 7);
-
- UnwindPlan::Row row;
- row.SetOffset(0);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 8);
- row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
- EXPECT_EQ(*plan.GetRowAtIndex(0), row);
-
- row.SetOffset(2);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);
- EXPECT_EQ(*plan.GetRowAtIndex(1), row);
-
- row.SetOffset(3);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);
- EXPECT_EQ(*plan.GetRowAtIndex(2), row);
-
- row.SetOffset(4);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);
- EXPECT_EQ(*plan.GetRowAtIndex(3), row);
-
- row.SetOffset(6);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
- EXPECT_EQ(*plan.GetRowAtIndex(4), row);
-
- row.SetOffset(8);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
- EXPECT_EQ(*plan.GetRowAtIndex(5), row);
-
- row.SetOffset(0xC);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x50);
- EXPECT_EQ(*plan.GetRowAtIndex(6), row);
-}
-
-TEST_F(PECallFrameInfoTest, Chained_eh) {
- UnwindPlan plan(eRegisterKindLLDB);
- GetUnwindPlan(0x1001180, plan);
- EXPECT_EQ(plan.GetRowCount(), 2);
-
- UnwindPlan::Row row;
- row.SetOffset(0);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x50);
- row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
- EXPECT_EQ(*plan.GetRowAtIndex(0), row);
-
- row.SetOffset(5);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, 0x18, true);
- EXPECT_EQ(*plan.GetRowAtIndex(1), row);
-}
-
-TEST_F(PECallFrameInfoTest, Frame_reg_eh) {
- UnwindPlan plan(eRegisterKindLLDB);
- GetUnwindPlan(0x1001280, plan);
- EXPECT_EQ(plan.GetRowCount(), 11);
-
- UnwindPlan::Row row;
- row.SetOffset(0);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 8);
- row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
- EXPECT_EQ(*plan.GetRowAtIndex(0), row);
-
- row.SetOffset(6);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, -0x10, true);
- EXPECT_EQ(*plan.GetRowAtIndex(1), row);
-
- row.SetOffset(8);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r12_x86_64, -0x18, true);
- EXPECT_EQ(*plan.GetRowAtIndex(2), row);
-
- row.SetOffset(0xA);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r13_x86_64, -0x20, true);
- EXPECT_EQ(*plan.GetRowAtIndex(3), row);
-
- row.SetOffset(0xC);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
- EXPECT_EQ(*plan.GetRowAtIndex(4), row);
-
- row.SetOffset(0xE);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
- EXPECT_EQ(*plan.GetRowAtIndex(5), row);
-
- row.SetOffset(0x15);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x320);
- EXPECT_EQ(*plan.GetRowAtIndex(6), row);
-
- row.SetOffset(0x1A);
- row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rbp_x86_64, 0x2F0);
- EXPECT_EQ(*plan.GetRowAtIndex(7), row);
-
- row.SetOffset(0x21);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, 8, true);
- EXPECT_EQ(*plan.GetRowAtIndex(8), row);
-
- row.SetOffset(0x28);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, 0x10, true);
- EXPECT_EQ(*plan.GetRowAtIndex(9), row);
-
- row.SetOffset(0x2F);
- row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, 0x18, true);
- EXPECT_EQ(*plan.GetRowAtIndex(10), row);
-}
+++ /dev/null
-//===-- AdbClientTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include "Plugins/Platform/Android/AdbClient.h"
-#include <cstdlib>
-
-static void set_env(const char *var, const char *value) {
-#ifdef _WIN32
- _putenv_s(var, value);
-#else
- setenv(var, value, true);
-#endif
-}
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace lldb_private {
-namespace platform_android {
-
-class AdbClientTest : public ::testing::Test {
-public:
- void SetUp() override { set_env("ANDROID_SERIAL", ""); }
-
- void TearDown() override { set_env("ANDROID_SERIAL", ""); }
-};
-
-TEST(AdbClientTest, CreateByDeviceId) {
- AdbClient adb;
- Status error = AdbClient::CreateByDeviceID("device1", adb);
- EXPECT_TRUE(error.Success());
- EXPECT_EQ("device1", adb.GetDeviceID());
-}
-
-TEST(AdbClientTest, CreateByDeviceId_ByEnvVar) {
- set_env("ANDROID_SERIAL", "device2");
-
- AdbClient adb;
- Status error = AdbClient::CreateByDeviceID("", adb);
- EXPECT_TRUE(error.Success());
- EXPECT_EQ("device2", adb.GetDeviceID());
-}
-
-} // end namespace platform_android
-} // end namespace lldb_private
+++ /dev/null
-include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Platform/Android)
-
-add_lldb_unittest(AdbClientTests
- AdbClientTest.cpp
-
- LINK_LIBS
- lldbPluginPlatformAndroid
- )
+++ /dev/null
-add_lldb_unittest(LLDBPlatformTests
- PlatformAppleSimulatorTest.cpp
- PlatformDarwinTest.cpp
-
- LINK_LIBS
- lldbPluginPlatformMacOSX
- LINK_COMPONENTS
- Support
- )
-
-add_subdirectory(Android)
+++ /dev/null
-//===-- PlatformAppleSimulatorTest.cpp ------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/Platform/MacOSX/PlatformAppleSimulator.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Target/Platform.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class PlatformAppleSimulatorTest : public ::testing::Test {
- SubsystemRAII<FileSystem, HostInfo, PlatformAppleSimulator>
- subsystems;
-};
-
-#ifdef __APPLE__
-
-static void testSimPlatformArchHasSimEnvironment(llvm::StringRef name) {
- Status error;
- auto platform_sp = Platform::Create(ConstString(name), error);
- ASSERT_TRUE(platform_sp);
- int num_arches = 0;
-
- while (true) {
- ArchSpec arch;
- if (!platform_sp->GetSupportedArchitectureAtIndex(num_arches, arch))
- break;
- EXPECT_EQ(arch.GetTriple().getEnvironment(), llvm::Triple::Simulator);
- num_arches++;
- }
-
- EXPECT_GT(num_arches, 0);
-}
-
-TEST_F(PlatformAppleSimulatorTest, TestSimHasSimEnvionament) {
- testSimPlatformArchHasSimEnvironment("ios-simulator");
- testSimPlatformArchHasSimEnvironment("tvos-simulator");
- testSimPlatformArchHasSimEnvironment("watchos-simulator");
-}
-
-TEST_F(PlatformAppleSimulatorTest, TestHostPlatformToSim) {
- static const ArchSpec platform_arch(
- HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
-
- const llvm::Triple::OSType sim_platforms[] = {
- llvm::Triple::IOS,
- llvm::Triple::TvOS,
- llvm::Triple::WatchOS,
- };
-
- for (auto sim : sim_platforms) {
- ArchSpec arch = platform_arch;
- arch.GetTriple().setOS(sim);
- arch.GetTriple().setEnvironment(llvm::Triple::Simulator);
-
- Status error;
- auto platform_sp = Platform::Create(arch, nullptr, error);
- EXPECT_TRUE(platform_sp);
- }
-}
-
-#endif
+++ /dev/null
-//===-- PlatformDarwinTest.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
-
-#include "llvm/ADT/StringRef.h"
-
-#include <tuple>
-
-using namespace lldb;
-using namespace lldb_private;
-
-struct PlatformDarwinTester : public PlatformDarwin {
-public:
- using PlatformDarwin::FindComponentInPath;
-};
-
-TEST(PlatformDarwinTest, TestParseVersionBuildDir) {
- llvm::VersionTuple V;
- llvm::StringRef D;
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("1.2.3 (test1)");
- EXPECT_EQ(llvm::VersionTuple(1, 2, 3), V);
- EXPECT_EQ("test1", D);
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("2.3 (test2)");
- EXPECT_EQ(llvm::VersionTuple(2, 3), V);
- EXPECT_EQ("test2", D);
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3 (test3)");
- EXPECT_EQ(llvm::VersionTuple(3), V);
- EXPECT_EQ("test3", D);
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("1.2.3 (test");
- EXPECT_EQ(llvm::VersionTuple(1, 2, 3), V);
- EXPECT_EQ("test", D);
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("2.3.4 test");
- EXPECT_EQ(llvm::VersionTuple(2, 3, 4), V);
- EXPECT_EQ("", D);
-
- std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5");
- EXPECT_EQ(llvm::VersionTuple(3, 4, 5), V);
-}
-
-TEST(PlatformDarwinTest, FindComponentInPath) {
- EXPECT_EQ("/path/to/foo",
- PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo"));
-
- EXPECT_EQ("/path/to/foo",
- PlatformDarwinTester::FindComponentInPath("/path/to/foo", "foo"));
-
- EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath(
- "/path/to/foobar", "foo"));
-
- EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath(
- "/path/to/foobar", "bar"));
-
- EXPECT_EQ("",
- PlatformDarwinTester::FindComponentInPath("/path/to/foo", "bar"));
-}
+++ /dev/null
-add_subdirectory(gdb-remote)
-if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
- add_subdirectory(Linux)
- add_subdirectory(POSIX)
-endif()
-add_subdirectory(Utility)
-add_subdirectory(minidump)
-
-add_lldb_unittest(ProcessEventDataTests
- ProcessEventDataTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbTarget
- lldbSymbol
- lldbUtility
- lldbUtilityHelpers
- lldbInterpreter
- lldbPluginPlatformMacOSX
- )
+++ /dev/null
-add_lldb_unittest(TraceIntelPTTests
- IntelPTManagerTests.cpp
-
- LINK_LIBS
- lldbPluginProcessLinux
- )
-
-target_include_directories(TraceIntelPTTests PRIVATE
- ${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux)
+++ /dev/null
-//===-- IntelPTManagerTests.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "IntelPTManager.h"
-#include "llvm/ADT/ArrayRef.h"
-
-
-using namespace lldb_private;
-using namespace process_linux;
-
-size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf,
- size_t cyc_buf_size, size_t cyc_start,
- size_t offset) {
- llvm::MutableArrayRef<uint8_t> dst(reinterpret_cast<uint8_t *>(buf),
- buf_size);
- llvm::MutableArrayRef<uint8_t> src(reinterpret_cast<uint8_t *>(cyc_buf),
- cyc_buf_size);
- IntelPTThreadTrace::ReadCyclicBuffer(dst, src, cyc_start, offset);
- return dst.size();
-}
-
-TEST(CyclicBuffer, EdgeCases) {
- size_t bytes_read;
- uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
- // We will always leave the last bytes untouched
- // so that string comparisons work.
- char smaller_buffer[4] = {};
-
- // empty buffer to read into
- bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer,
- sizeof(cyclic_buffer), 3, 0);
- ASSERT_EQ(0u, bytes_read);
-
- // empty cyclic buffer
- bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
- cyclic_buffer, 0, 3, 0);
- ASSERT_EQ(0u, bytes_read);
-
- // bigger offset
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 6);
- ASSERT_EQ(0u, bytes_read);
-
- // wrong offset
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
- ASSERT_EQ(0u, bytes_read);
-
- // wrong start
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 7);
- ASSERT_EQ(0u, bytes_read);
-}
-
-TEST(CyclicBuffer, EqualSizeBuffer) {
- size_t bytes_read = 0;
- uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
- char cyclic[] = "cyclic";
- for (size_t i = 0; i < sizeof(cyclic); i++) {
- // We will always leave the last bytes untouched
- // so that string comparisons work.
- char equal_size_buffer[7] = {};
- bytes_read =
- ReadCylicBufferWrapper(equal_size_buffer, sizeof(cyclic_buffer),
- cyclic_buffer, sizeof(cyclic_buffer), 3, i);
- ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
- ASSERT_STREQ(equal_size_buffer, (cyclic + i));
- }
-}
-
-TEST(CyclicBuffer, SmallerSizeBuffer) {
- size_t bytes_read;
- uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
- // We will always leave the last bytes untouched
- // so that string comparisons work.
- char smaller_buffer[4] = {};
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 0);
- ASSERT_EQ(3u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "cyc");
-
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 1);
- ASSERT_EQ(3u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "ycl");
-
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 2);
- ASSERT_EQ(3u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "cli");
-
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 3);
- ASSERT_EQ(3u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "lic");
-
- {
- char smaller_buffer[4] = {};
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 4);
- ASSERT_EQ(2u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "ic");
- }
- {
- char smaller_buffer[4] = {};
- bytes_read =
- ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, 5);
- ASSERT_EQ(1u, bytes_read);
- ASSERT_STREQ(smaller_buffer, "c");
- }
-}
-
-TEST(CyclicBuffer, BiggerSizeBuffer) {
- size_t bytes_read = 0;
- uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
-
- char cyclic[] = "cyclic";
- for (size_t i = 0; i < sizeof(cyclic); i++) {
- // We will always leave the last bytes untouched
- // so that string comparisons work.
- char bigger_buffer[10] = {};
- bytes_read =
- ReadCylicBufferWrapper(bigger_buffer, (sizeof(bigger_buffer) - 1),
- cyclic_buffer, sizeof(cyclic_buffer), 3, i);
- ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
- ASSERT_STREQ(bigger_buffer, (cyclic + i));
- }
-}
+++ /dev/null
-add_lldb_unittest(ProcessPOSIXTests
- NativeProcessELFTest.cpp
-
- LINK_LIBS
- lldbPluginProcessPOSIX
- )
-
-target_include_directories(ProcessPOSIXTests PRIVATE
- ${LLDB_SOURCE_DIR}/source/Plugins/Process/POSIX)
+++ /dev/null
-//===-- NativeProcessELFTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestingSupport/Host/NativeProcessTestUtils.h"
-
-#include "Plugins/Process/POSIX/NativeProcessELF.h"
-#include "Plugins/Process/Utility/AuxVector.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/DataEncoder.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-#include "gmock/gmock.h"
-
-using namespace lldb_private;
-using namespace lldb;
-using namespace testing;
-
-namespace {
-class MockProcessELF : public MockProcess<NativeProcessELF> {
-public:
- using MockProcess::MockProcess;
- using NativeProcessELF::GetAuxValue;
- using NativeProcessELF::GetELFImageInfoAddress;
-};
-
-std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
- MockProcessELF &process,
- llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
- auto addr_size = process.GetAddressByteSize();
- DataBufferSP buffer_sp(
- new DataBufferHeap(auxv_data.size() * addr_size * 2, 0));
- DataEncoder encoder(buffer_sp, process.GetByteOrder(), addr_size);
- uint32_t offset = 0;
- for (auto &pair : auxv_data) {
- offset = encoder.PutAddress(offset, pair.first);
- offset = encoder.PutAddress(offset, pair.second);
- }
- return llvm::MemoryBuffer::getMemBufferCopy(
- llvm::toStringRef(buffer_sp->GetData()), "");
-}
-
-} // namespace
-
-TEST(NativeProcessELFTest, GetAuxValue) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
-
- uint64_t phdr_addr = 0x42;
- auto auxv_buffer = CreateAuxvData(
- process, {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr)});
- EXPECT_CALL(process, GetAuxvData())
- .WillOnce(Return(ByMove(std::move(auxv_buffer))));
-
- ASSERT_EQ(phdr_addr, process.GetAuxValue(AuxVector::AUXV_AT_PHDR));
-}
-
-TEST(NativeProcessELFTest, GetELFImageInfoAddress) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
-
- uint32_t load_base = 0x1000;
- uint32_t info_addr = 0x3741;
- uint32_t phdr_addr = load_base + sizeof(llvm::ELF::Elf32_Ehdr);
-
- auto auxv_buffer = CreateAuxvData(
- process,
- {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
- std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
- std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
- EXPECT_CALL(process, GetAuxvData())
- .WillOnce(Return(ByMove(std::move(auxv_buffer))));
-
- // We're going to set up a fake memory with 2 program headers and 1 entry in
- // the dynamic section. For simplicity sake they will be contiguous in memory.
- struct MemoryContents {
- llvm::ELF::Elf32_Phdr phdr_load;
- llvm::ELF::Elf32_Phdr phdr_dynamic;
- llvm::ELF::Elf32_Dyn dyn_debug;
- } MC;
- // Setup the 2 program header entries
- MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
- MC.phdr_load.p_vaddr = phdr_addr - load_base;
-
- MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
- MC.phdr_dynamic.p_vaddr =
- (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr)) - load_base;
- MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
-
- // Setup the single entry in the .dynamic section
- MC.dyn_debug.d_tag = llvm::ELF::DT_DEBUG;
- MC.dyn_debug.d_un.d_ptr = info_addr;
-
- FakeMemory M(&MC, sizeof(MC), phdr_addr);
- EXPECT_CALL(process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
-
- lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
- llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
-
- // Read the address at the elf_info_addr location to make sure we're reading
- // the correct one.
- lldb::offset_t info_addr_offset = elf_info_addr - phdr_addr;
- DataExtractor mem_extractor(&MC, sizeof(MC), process.GetByteOrder(),
- process.GetAddressByteSize());
- ASSERT_EQ(mem_extractor.GetAddress(&info_addr_offset), info_addr);
-}
-
-TEST(NativeProcessELFTest, GetELFImageInfoAddress_NoDebugEntry) {
- NiceMock<MockDelegate> DummyDelegate;
- MockProcessELF process(DummyDelegate, ArchSpec("i386-pc-linux"));
-
- uint32_t phdr_addr = sizeof(llvm::ELF::Elf32_Ehdr);
-
- auto auxv_buffer = CreateAuxvData(
- process,
- {std::make_pair(AuxVector::AUXV_AT_PHDR, phdr_addr),
- std::make_pair(AuxVector::AUXV_AT_PHENT, sizeof(llvm::ELF::Elf32_Phdr)),
- std::make_pair(AuxVector::AUXV_AT_PHNUM, 2)});
- EXPECT_CALL(process, GetAuxvData())
- .WillOnce(Return(ByMove(std::move(auxv_buffer))));
-
- // We're going to set up a fake memory with 2 program headers and 1 entry in
- // the dynamic section. For simplicity sake they will be contiguous in memory.
- struct MemoryContents {
- llvm::ELF::Elf32_Phdr phdr_load;
- llvm::ELF::Elf32_Phdr phdr_dynamic;
- llvm::ELF::Elf32_Dyn dyn_notdebug;
- } MC;
- // Setup the 2 program header entries
- MC.phdr_load.p_type = llvm::ELF::PT_PHDR;
- MC.phdr_load.p_vaddr = phdr_addr;
-
- MC.phdr_dynamic.p_type = llvm::ELF::PT_DYNAMIC;
- MC.phdr_dynamic.p_vaddr = (phdr_addr + 2 * sizeof(llvm::ELF::Elf32_Phdr));
- MC.phdr_dynamic.p_memsz = sizeof(llvm::ELF::Elf32_Dyn);
-
- // Setup the single entry in the .dynamic section
- MC.dyn_notdebug.d_tag = llvm::ELF::DT_NULL;
-
- FakeMemory M(&MC, sizeof(MC), phdr_addr);
- EXPECT_CALL(process, ReadMemory(_, _))
- .WillRepeatedly(Invoke(&M, &FakeMemory::Read));
-
- lldb::addr_t elf_info_addr = process.GetELFImageInfoAddress<
- llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
-
- ASSERT_EQ(elf_info_addr, LLDB_INVALID_ADDRESS);
-}
+++ /dev/null
-//===-- ProcessEventDataTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
-#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Target/Thread.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/Event.h"
-#include "lldb/Utility/Reproducer.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace lldb;
-
-namespace {
-class ProcessEventDataTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
- FileSystem::Initialize();
- HostInfo::Initialize();
- PlatformMacOSX::Initialize();
- }
- void TearDown() override {
- PlatformMacOSX::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- Reproducer::Terminate();
- }
-};
-
-class DummyProcess : public Process {
-public:
- using Process::Process;
-
- bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
- return true;
- }
- Status DoDestroy() override { return {}; }
- void RefreshStateAfterStop() override {}
- size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Status &error) override {
- return 0;
- }
- bool DoUpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override {
- return false;
- }
- ConstString GetPluginName() override { return ConstString("Dummy"); }
- uint32_t GetPluginVersion() override { return 0; }
-
- ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
-};
-
-class DummyThread : public Thread {
-public:
- using Thread::Thread;
-
- ~DummyThread() override { DestroyThread(); }
-
- void RefreshStateAfterStop() override {}
-
- lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
-
- lldb::RegisterContextSP
- CreateRegisterContextForFrame(StackFrame *frame) override {
- return nullptr;
- }
-
- bool CalculateStopInfo() override { return false; }
-};
-
-class DummyStopInfo : public StopInfo {
-public:
- DummyStopInfo(Thread &thread, uint64_t value)
- : StopInfo(thread, value), m_should_stop(true),
- m_stop_reason(eStopReasonBreakpoint) {}
-
- bool ShouldStop(Event *event_ptr) override { return m_should_stop; }
-
- StopReason GetStopReason() const override { return m_stop_reason; }
-
- bool m_should_stop;
- StopReason m_stop_reason;
-};
-
-class DummyProcessEventData : public Process::ProcessEventData {
-public:
- DummyProcessEventData(ProcessSP &process_sp, StateType state)
- : ProcessEventData(process_sp, state), m_should_stop_hit_count(0) {}
- bool ShouldStop(Event *event_ptr, bool &found_valid_stopinfo) override {
- m_should_stop_hit_count++;
- return false;
- }
-
- int m_should_stop_hit_count;
-};
-} // namespace
-
-typedef std::shared_ptr<Process::ProcessEventData> ProcessEventDataSP;
-typedef std::shared_ptr<Event> EventSP;
-
-TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
- PlatformSP platform_sp;
- TargetSP target_sp;
- debugger_sp->GetTargetList().CreateTarget(
- *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
-
- return target_sp;
-}
-
-ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop,
- bool has_valid_stopinfo) {
- ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
- if (thread_sp == nullptr) {
- return nullptr;
- }
-
- if (has_valid_stopinfo) {
- StopInfoSP stopinfo_sp =
- std::make_shared<DummyStopInfo>(*thread_sp.get(), 0);
- static_cast<DummyStopInfo *>(stopinfo_sp.get())->m_should_stop =
- should_stop;
- if (stopinfo_sp == nullptr) {
- return nullptr;
- }
-
- thread_sp->SetStopInfo(stopinfo_sp);
- }
-
- process_sp->GetThreadList().AddThread(thread_sp);
-
- return thread_sp;
-}
-
-TEST_F(ProcessEventDataTest, DoOnRemoval) {
- ArchSpec arch("x86_64-apple-macosx-");
-
- Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp = CreateTarget(debugger_sp, arch);
- ASSERT_TRUE(target_sp);
-
- ListenerSP listener_sp(Listener::MakeListener("dummy"));
- ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- /*
- Should hit ShouldStop if state is eStateStopped
- */
- ProcessEventDataSP event_data_sp =
- std::make_shared<DummyProcessEventData>(process_sp, eStateStopped);
- EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
- event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
- event_data_sp->DoOnRemoval(event_sp.get());
- bool result = static_cast<DummyProcessEventData *>(event_data_sp.get())
- ->m_should_stop_hit_count == 1;
- ASSERT_TRUE(result);
-
- /*
- Should not hit ShouldStop if state is not eStateStopped
- */
- event_data_sp =
- std::make_shared<DummyProcessEventData>(process_sp, eStateStepping);
- event_sp = std::make_shared<Event>(0, event_data_sp);
- event_data_sp->SetUpdateStateOnRemoval(event_sp.get());
- event_data_sp->DoOnRemoval(event_sp.get());
- result = static_cast<DummyProcessEventData *>(event_data_sp.get())
- ->m_should_stop_hit_count == 0;
- ASSERT_TRUE(result);
-}
-
-TEST_F(ProcessEventDataTest, ShouldStop) {
- ArchSpec arch("x86_64-apple-macosx-");
-
- Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp = CreateTarget(debugger_sp, arch);
- ASSERT_TRUE(target_sp);
-
- ListenerSP listener_sp(Listener::MakeListener("dummy"));
- ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- // wants to stop and has valid StopInfo
- ThreadSP thread_sp = CreateThread(process_sp, true, true);
-
- ProcessEventDataSP event_data_sp =
- std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
- EventSP event_sp = std::make_shared<Event>(0, event_data_sp);
- /*
- Should stop if thread has valid StopInfo and not suspended
- */
- bool found_valid_stopinfo = false;
- bool should_stop =
- event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
- ASSERT_TRUE(should_stop == true && found_valid_stopinfo == true);
-
- /*
- Should not stop if thread has valid StopInfo but was suspended
- */
- found_valid_stopinfo = false;
- thread_sp->SetResumeState(eStateSuspended);
- should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
- ASSERT_TRUE(should_stop == false && found_valid_stopinfo == false);
-
- /*
- Should not stop, thread-reason of stop does not want to stop in its
- callback and suspended thread who wants to (from previous stop)
- must be ignored.
- */
- event_data_sp =
- std::make_shared<Process::ProcessEventData>(process_sp, eStateStopped);
- event_sp = std::make_shared<Event>(0, event_data_sp);
- process_sp->GetThreadList().Clear();
-
- for (int i = 0; i < 6; i++) {
- if (i == 2) {
- // Does not want to stop but has valid StopInfo
- thread_sp = CreateThread(process_sp, false, true);
- } else if (i == 5) {
- // Wants to stop and has valid StopInfo
- thread_sp = CreateThread(process_sp, true, true);
- thread_sp->SetResumeState(eStateSuspended);
- } else {
- // Thread has no StopInfo i.e is not the reason of stop
- thread_sp = CreateThread(process_sp, false, false);
- }
- }
- ASSERT_TRUE(process_sp->GetThreadList().GetSize() == 6);
-
- found_valid_stopinfo = false;
- should_stop = event_data_sp->ShouldStop(event_sp.get(), found_valid_stopinfo);
- ASSERT_TRUE(should_stop == false && found_valid_stopinfo == true);
-}
+++ /dev/null
-set(FREEBSD_SOURCES
- RegisterContextFreeBSDTest.cpp)
-set(NETBSD_SOURCES
- RegisterContextNetBSDTest_i386.cpp
- RegisterContextNetBSDTest_x86_64.cpp)
-
-if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
- list(APPEND PLATFORM_SOURCES ${FREEBSD_SOURCES})
-elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
- list(APPEND PLATFORM_SOURCES ${NETBSD_SOURCES})
-endif()
-
-set(LLVM_OPTIONAL_SOURCES
- ${FREEBSD_SOURCES}
- ${NETBSD_SOURCES})
-
-add_lldb_unittest(ProcessUtilityTests
- RegisterContextTest.cpp
- LinuxProcMapsTest.cpp
- MemoryTagManagerAArch64MTETest.cpp
- ${PLATFORM_SOURCES}
-
- LINK_LIBS
- lldbPluginProcessUtility
- LLVMTestingSupport)
+++ /dev/null
-//===-- LinuxProcMapsTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/Utility/LinuxProcMaps.h"
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Utility/Status.h"
-#include <tuple>
-
-using namespace lldb_private;
-
-typedef std::tuple<const char *, MemoryRegionInfos, const char *>
- LinuxProcMapsTestParams;
-
-// Wrapper for convenience because Range is usually begin, size
-static MemoryRegionInfo::RangeType make_range(lldb::addr_t begin,
- lldb::addr_t end) {
- MemoryRegionInfo::RangeType range(begin, 0);
- range.SetRangeEnd(end);
- return range;
-}
-
-class LinuxProcMapsTestFixture
- : public ::testing::TestWithParam<LinuxProcMapsTestParams> {
-protected:
- Status error;
- std::string err_str;
- MemoryRegionInfos regions;
- LinuxMapCallback callback;
-
- void SetUp() override {
- callback = [this](llvm::Expected<MemoryRegionInfo> Info) {
- if (Info) {
- err_str.clear();
- regions.push_back(*Info);
- return true;
- }
-
- err_str = toString(Info.takeError());
- return false;
- };
- }
-
- void check_regions(LinuxProcMapsTestParams params) {
- EXPECT_THAT(std::get<1>(params), testing::ContainerEq(regions));
- ASSERT_EQ(std::get<2>(params), err_str);
- }
-};
-
-TEST_P(LinuxProcMapsTestFixture, ParseMapRegions) {
- auto params = GetParam();
- ParseLinuxMapRegions(std::get<0>(params), callback);
- check_regions(params);
-}
-
-// Note: ConstString("") != ConstString(nullptr)
-// When a region has no name, it will have the latter in the MemoryRegionInfo
-INSTANTIATE_TEST_SUITE_P(
- ProcMapTests, LinuxProcMapsTestFixture,
- ::testing::Values(
- // Nothing in nothing out
- std::make_tuple("", MemoryRegionInfos{}, ""),
- // Various formatting error conditions
- std::make_tuple("55a4512f7000/55a451b68000 rw-p 00000000 00:00 0",
- MemoryRegionInfos{},
- "malformed /proc/{pid}/maps entry, missing dash "
- "between address range"),
- std::make_tuple("0-0 rw", MemoryRegionInfos{},
- "malformed /proc/{pid}/maps entry, missing some "
- "portion of permissions"),
- std::make_tuple("0-0 z--p 00000000 00:00 0", MemoryRegionInfos{},
- "unexpected /proc/{pid}/maps read permission char"),
- std::make_tuple("0-0 rz-p 00000000 00:00 0", MemoryRegionInfos{},
- "unexpected /proc/{pid}/maps write permission char"),
- std::make_tuple("0-0 rwzp 00000000 00:00 0", MemoryRegionInfos{},
- "unexpected /proc/{pid}/maps exec permission char"),
- // Stops at first parsing error
- std::make_tuple(
- "0-1 rw-p 00000000 00:00 0 [abc]\n"
- "0-0 rwzp 00000000 00:00 0\n"
- "2-3 r-xp 00000000 00:00 0 [def]\n",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0, 1), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, ConstString("[abc]"),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- "unexpected /proc/{pid}/maps exec permission char"),
- // Single entry
- std::make_tuple(
- "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x55a4512f7000, 0x55a451b68000),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString("[heap]"),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- ""),
- // Multiple entries
- std::make_tuple(
- "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n"
- "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
- "[vsyscall]",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x7fc090021000, 0x7fc094000000),
- MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString(nullptr),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- MemoryRegionInfo(
- make_range(0xffffffffff600000, 0xffffffffff601000),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- "")));
-
-class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
-
-INSTANTIATE_TEST_SUITE_P(
- ProcSMapTests, LinuxProcSMapsTestFixture,
- ::testing::Values(
- // Nothing in nothing out
- std::make_tuple("", MemoryRegionInfos{}, ""),
- // Uses the same parsing for first line, so same errors but referring to
- // smaps
- std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{},
- "malformed /proc/{pid}/smaps entry, missing dash "
- "between address range"),
- // Stop parsing at first error
- std::make_tuple(
- "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
- "0/0 rw-p 00000000 00:00 0",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x1111, 0x2222),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString("[foo]"),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- "malformed /proc/{pid}/smaps entry, missing dash between address "
- "range"),
- // Property line without a region is an error
- std::make_tuple("Referenced: 2188 kB\n"
- "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
- "3333-4444 rw-p 00000000 00:00 0 [bar]\n",
- MemoryRegionInfos{},
- "Found a property line without a corresponding mapping "
- "in /proc/{pid}/smaps"),
- // Single region parses, has no flags
- std::make_tuple(
- "1111-2222 rw-p 00000000 00:00 0 [foo]",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x1111, 0x2222),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString("[foo]"),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- ""),
- // Single region with flags, other lines ignored
- std::make_tuple(
- "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
- "Referenced: 2188 kB\n"
- "AnonHugePages: 0 kB\n"
- "VmFlags: mt",
- MemoryRegionInfos{
- MemoryRegionInfo(
- make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, ConstString("[foo]"),
- MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes),
- },
- ""),
- // Whitespace ignored
- std::make_tuple(
- "0-0 rw-p 00000000 00:00 0\n"
- "VmFlags: mt ",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, ConstString(nullptr),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eYes),
- },
- ""),
- // VmFlags line means it has flag info, but nothing is set
- std::make_tuple(
- "0-0 rw-p 00000000 00:00 0\n"
- "VmFlags: ",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, ConstString(nullptr),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eNo),
- },
- ""),
- // Handle some pages not having a flags line
- std::make_tuple(
- "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
- "Referenced: 2188 kB\n"
- "AnonHugePages: 0 kB\n"
- "3333-4444 r-xp 00000000 00:00 0 [bar]\n"
- "VmFlags: mt",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x1111, 0x2222),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString("[foo]"),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- MemoryRegionInfo(
- make_range(0x3333, 0x4444), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, ConstString("[bar]"),
- MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes),
- },
- ""),
- // Handle no pages having a flags line (older kernels)
- std::make_tuple(
- "1111-2222 rw-p 00000000 00:00 0\n"
- "Referenced: 2188 kB\n"
- "AnonHugePages: 0 kB\n"
- "3333-4444 r-xp 00000000 00:00 0\n"
- "KernelPageSize: 4 kB\n"
- "MMUPageSize: 4 kB\n",
- MemoryRegionInfos{
- MemoryRegionInfo(make_range(0x1111, 0x2222),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
- ConstString(nullptr),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- MemoryRegionInfo(make_range(0x3333, 0x4444),
- MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- ConstString(nullptr),
- MemoryRegionInfo::eDontKnow, 0,
- MemoryRegionInfo::eDontKnow),
- },
- "")));
-
-TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
- auto params = GetParam();
- ParseLinuxSMapRegions(std::get<0>(params), callback);
- check_regions(params);
-}
+++ /dev/null
-//===-- MemoryTagManagerAArch64MTETest.cpp --------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(MemoryTagManagerAArch64MTETest, UnpackTagsData) {
- MemoryTagManagerAArch64MTE manager;
-
- // Error for insufficient tag data
- std::vector<uint8_t> input;
- ASSERT_THAT_EXPECTED(
- manager.UnpackTagsData(input, 2),
- llvm::FailedWithMessage(
- "Packed tag data size does not match expected number of tags. "
- "Expected 2 tag(s) for 2 granule(s), got 0 tag(s)."));
-
- // This is out of the valid tag range
- input.push_back(0x1f);
- ASSERT_THAT_EXPECTED(
- manager.UnpackTagsData(input, 1),
- llvm::FailedWithMessage(
- "Found tag 0x1f which is > max MTE tag value of 0xf."));
-
- // MTE tags are 1 per byte
- input.pop_back();
- input.push_back(0xe);
- input.push_back(0xf);
-
- std::vector<lldb::addr_t> expected{0xe, 0xf};
-
- llvm::Expected<std::vector<lldb::addr_t>> got =
- manager.UnpackTagsData(input, 2);
- ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
- ASSERT_THAT(expected, testing::ContainerEq(*got));
-
- // Error for too much tag data
- ASSERT_THAT_EXPECTED(
- manager.UnpackTagsData(input, 1),
- llvm::FailedWithMessage(
- "Packed tag data size does not match expected number of tags. "
- "Expected 1 tag(s) for 1 granule(s), got 2 tag(s)."));
-
- // By default, we don't check number of tags
- llvm::Expected<std::vector<lldb::addr_t>> got_zero =
- manager.UnpackTagsData(input);
- ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded());
- ASSERT_THAT(expected, testing::ContainerEq(*got));
-
- // Which is the same as granules=0
- got_zero = manager.UnpackTagsData(input, 0);
- ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded());
- ASSERT_THAT(expected, testing::ContainerEq(*got));
-}
-
-TEST(MemoryTagManagerAArch64MTETest, PackTags) {
- MemoryTagManagerAArch64MTE manager;
-
- // Error for tag out of range
- llvm::Expected<std::vector<uint8_t>> invalid_tag_err =
- manager.PackTags({0x10});
- ASSERT_THAT_EXPECTED(
- invalid_tag_err,
- llvm::FailedWithMessage(
- "Found tag 0x10 which is > max MTE tag value of 0xf."));
-
- // 0xf here is the max tag value that we can pack
- std::vector<lldb::addr_t> tags{0, 1, 0xf};
- std::vector<uint8_t> expected{0, 1, 0xf};
- llvm::Expected<std::vector<uint8_t>> packed = manager.PackTags(tags);
- ASSERT_THAT_EXPECTED(packed, llvm::Succeeded());
- ASSERT_THAT(expected, testing::ContainerEq(*packed));
-}
-
-TEST(MemoryTagManagerAArch64MTETest, GetLogicalTag) {
- MemoryTagManagerAArch64MTE manager;
-
- // Set surrounding bits to check shift is correct
- ASSERT_EQ((lldb::addr_t)0, manager.GetLogicalTag(0xe0e00000ffffffff));
- // Max tag value
- ASSERT_EQ((lldb::addr_t)0xf, manager.GetLogicalTag(0x0f000000ffffffff));
- ASSERT_EQ((lldb::addr_t)2, manager.GetLogicalTag(0x02000000ffffffff));
-}
-
-TEST(MemoryTagManagerAArch64MTETest, ExpandToGranule) {
- MemoryTagManagerAArch64MTE manager;
- // Reading nothing, no alignment needed
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(0, 0),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0, 0)));
-
- // Ranges with 0 size are unchanged even if address is non 0
- // (normally 0x1234 would be aligned to 0x1230)
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(0x1234, 0),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0x1234, 0)));
-
- // Ranges already aligned don't change
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(0x100, 64),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0x100, 64)));
-
- // Any read of less than 1 granule is rounded up to reading 1 granule
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(0, 16),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0, 1)));
-
- // Start address is aligned down, and length modified accordingly
- // Here bytes 8 through 24 straddle 2 granules. So the resulting range starts
- // at 0 and covers 32 bytes.
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(0, 32),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(8, 16)));
-
- // Here only the size of the range needs aligning
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(16, 32),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(16, 24)));
-
- // Start and size need aligning here but we only need 1 granule to cover it
- ASSERT_EQ(
- MemoryTagManagerAArch64MTE::TagRange(16, 16),
- manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(18, 4)));
-}
-
-static MemoryRegionInfo MakeRegionInfo(lldb::addr_t base, lldb::addr_t size,
- bool tagged) {
- return MemoryRegionInfo(
- MemoryRegionInfo::RangeType(base, size), MemoryRegionInfo::eYes,
- MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
- ConstString(), MemoryRegionInfo::eNo, 0,
- /*memory_tagged=*/
- tagged ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
-}
-
-TEST(MemoryTagManagerAArch64MTETest, MakeTaggedRange) {
- MemoryTagManagerAArch64MTE manager;
- MemoryRegionInfos memory_regions;
-
- // No regions means no tagged regions, error
- ASSERT_THAT_EXPECTED(
- manager.MakeTaggedRange(0, 0x10, memory_regions),
- llvm::FailedWithMessage(
- "Address range 0x0:0x10 is not in a memory tagged region"));
-
- // Alignment is done before checking regions.
- // Here 1 is rounded up to the granule size of 0x10.
- ASSERT_THAT_EXPECTED(
- manager.MakeTaggedRange(0, 1, memory_regions),
- llvm::FailedWithMessage(
- "Address range 0x0:0x10 is not in a memory tagged region"));
-
- // Range must not be inverted
- ASSERT_THAT_EXPECTED(
- manager.MakeTaggedRange(1, 0, memory_regions),
- llvm::FailedWithMessage(
- "End address (0x0) must be greater than the start address (0x1)"));
-
- // Adding a single region to cover the whole range
- memory_regions.push_back(MakeRegionInfo(0, 0x1000, true));
-
- // Range can have different tags for begin and end
- // (which would make it look inverted if we didn't remove them)
- // Note that range comes back with an untagged base and alginment
- // applied.
- MemoryTagManagerAArch64MTE::TagRange expected_range(0x0, 0x10);
- llvm::Expected<MemoryTagManagerAArch64MTE::TagRange> got =
- manager.MakeTaggedRange(0x0f00000000000000, 0x0e00000000000001,
- memory_regions);
- ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
- ASSERT_EQ(*got, expected_range);
-
- // Error if the range isn't within any region
- ASSERT_THAT_EXPECTED(
- manager.MakeTaggedRange(0x1000, 0x1010, memory_regions),
- llvm::FailedWithMessage(
- "Address range 0x1000:0x1010 is not in a memory tagged region"));
-
- // Error if the first part of a range isn't tagged
- memory_regions.clear();
- const char *err_msg =
- "Address range 0x0:0x1000 is not in a memory tagged region";
-
- // First because it has no region entry
- memory_regions.push_back(MakeRegionInfo(0x10, 0x1000, true));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // Then because the first region is untagged
- memory_regions.push_back(MakeRegionInfo(0, 0x10, false));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // If we tag that first part it succeeds
- memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes);
- expected_range = MemoryTagManagerAArch64MTE::TagRange(0x0, 0x1000);
- got = manager.MakeTaggedRange(0, 0x1000, memory_regions);
- ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
- ASSERT_EQ(*got, expected_range);
-
- // Error if the end of a range is untagged
- memory_regions.clear();
-
- // First because it has no region entry
- memory_regions.push_back(MakeRegionInfo(0, 0xF00, true));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // Then because the last region is untagged
- memory_regions.push_back(MakeRegionInfo(0xF00, 0x100, false));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // If we tag the last part it succeeds
- memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes);
- got = manager.MakeTaggedRange(0, 0x1000, memory_regions);
- ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
- ASSERT_EQ(*got, expected_range);
-
- // Error if the middle of a range is untagged
- memory_regions.clear();
-
- // First because it has no entry
- memory_regions.push_back(MakeRegionInfo(0, 0x500, true));
- memory_regions.push_back(MakeRegionInfo(0x900, 0x700, true));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // Then because it's untagged
- memory_regions.push_back(MakeRegionInfo(0x500, 0x400, false));
- ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions),
- llvm::FailedWithMessage(err_msg));
-
- // If we tag the middle part it succeeds
- memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes);
- got = manager.MakeTaggedRange(0, 0x1000, memory_regions);
- ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
- ASSERT_EQ(*got, expected_range);
-}
-
-TEST(MemoryTagManagerAArch64MTETest, RemoveNonAddressBits) {
- MemoryTagManagerAArch64MTE manager;
-
- ASSERT_EQ(0, 0);
- ASSERT_EQ((lldb::addr_t)0x00ffeedd11223344,
- manager.RemoveNonAddressBits(0x00ffeedd11223344));
- ASSERT_EQ((lldb::addr_t)0x0000000000000000,
- manager.RemoveNonAddressBits(0xFF00000000000000));
- ASSERT_EQ((lldb::addr_t)0x0055555566666666,
- manager.RemoveNonAddressBits(0xee55555566666666));
-}
-
-TEST(MemoryTagManagerAArch64MTETest, AddressDiff) {
- MemoryTagManagerAArch64MTE manager;
-
- ASSERT_EQ(0, manager.AddressDiff(0, 0));
- // Result is signed
- ASSERT_EQ(10, manager.AddressDiff(10, 0));
- ASSERT_EQ(-10, manager.AddressDiff(0, 10));
- // Anything in the top byte is ignored
- ASSERT_EQ(0, manager.AddressDiff(0x2211222233334444, 0x3311222233334444));
- ASSERT_EQ(-32, manager.AddressDiff(0x5511222233334400, 0x4411222233334420));
- ASSERT_EQ(65, manager.AddressDiff(0x9911222233334441, 0x6611222233334400));
-}
-
-// Helper to check that repeating "tags" over "range" gives you
-// "expected_tags".
-static void
-test_repeating_tags(const std::vector<lldb::addr_t> &tags,
- MemoryTagManagerAArch64MTE::TagRange range,
- const std::vector<lldb::addr_t> &expected_tags) {
- MemoryTagManagerAArch64MTE manager;
- llvm::Expected<std::vector<lldb::addr_t>> tags_or_err =
- manager.RepeatTagsForRange(tags, range);
- ASSERT_THAT_EXPECTED(tags_or_err, llvm::Succeeded());
- ASSERT_THAT(expected_tags, testing::ContainerEq(*tags_or_err));
-}
-
-TEST(MemoryTagManagerAArch64MTETest, RepeatTagsForRange) {
- MemoryTagManagerAArch64MTE manager;
-
- // Must have some tags if your range is not empty
- llvm::Expected<std::vector<lldb::addr_t>> no_tags_err =
- manager.RepeatTagsForRange({},
- MemoryTagManagerAArch64MTE::TagRange{0, 16});
- ASSERT_THAT_EXPECTED(
- no_tags_err, llvm::FailedWithMessage(
- "Expected some tags to cover given range, got zero."));
-
- // If the range is empty, you get no tags back
- test_repeating_tags({1, 2, 3}, MemoryTagManagerAArch64MTE::TagRange{0, 0},
- {});
- // And you don't need tags for an empty range
- test_repeating_tags({}, MemoryTagManagerAArch64MTE::TagRange{0, 0}, {});
-
- // A single tag will just be multiplied as many times as needed
- test_repeating_tags({5}, MemoryTagManagerAArch64MTE::TagRange{0, 16}, {5});
- test_repeating_tags({6}, MemoryTagManagerAArch64MTE::TagRange{0, 32}, {6, 6});
-
- // If you've got as many tags as granules, it's a roundtrip
- test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 32},
- {7, 8});
-
- // If you've got fewer tags than granules, they repeat. Exactly or partially
- // as needed.
- test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 64},
- {7, 8, 7, 8});
- test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 48},
- {7, 8, 7});
-
- // If you've got more tags than granules you get back only those needed
- test_repeating_tags({1, 2, 3, 4}, MemoryTagManagerAArch64MTE::TagRange{0, 32},
- {1, 2});
-}
+++ /dev/null
-//===-- RegisterContextFreeBSDTests.cpp -----------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// clang-format off
-#include <sys/types.h>
-#include <machine/reg.h>
-#if defined(__arm__)
-#include <machine/vfp.h>
-#endif
-// clang-format on
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
-#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
-#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
-#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
-#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
-#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
-#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
-#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-std::pair<size_t, size_t> GetRegParams(RegisterInfoInterface &ctx,
- uint32_t reg) {
- const RegisterInfo &info = ctx.GetRegisterInfo()[reg];
- return {info.byte_offset, info.byte_size};
-}
-
-#define EXPECT_OFF(regname, offset, size) \
- EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \
- ::testing::Pair(offset + base_offset, size))
-
-#if defined(__x86_64__)
-
-#define EXPECT_GPR_X86_64(regname) \
- EXPECT_THAT( \
- GetRegParams(reg_ctx, lldb_##regname##_x86_64), \
- ::testing::Pair(offsetof(reg, r_##regname), sizeof(reg::r_##regname)))
-#define EXPECT_DBR_X86_64(num) \
- EXPECT_OFF(dr##num##_x86_64, offsetof(dbreg, dr[num]), sizeof(dbreg::dr[num]))
-
-TEST(RegisterContextFreeBSDTest, x86_64) {
- ArchSpec arch{"x86_64-unknown-freebsd"};
- RegisterContextFreeBSD_x86_64 reg_ctx{arch};
-
- EXPECT_GPR_X86_64(r15);
- EXPECT_GPR_X86_64(r14);
- EXPECT_GPR_X86_64(r13);
- EXPECT_GPR_X86_64(r12);
- EXPECT_GPR_X86_64(r11);
- EXPECT_GPR_X86_64(r10);
- EXPECT_GPR_X86_64(r9);
- EXPECT_GPR_X86_64(r8);
- EXPECT_GPR_X86_64(rdi);
- EXPECT_GPR_X86_64(rsi);
- EXPECT_GPR_X86_64(rbp);
- EXPECT_GPR_X86_64(rbx);
- EXPECT_GPR_X86_64(rdx);
- EXPECT_GPR_X86_64(rcx);
- EXPECT_GPR_X86_64(rax);
- EXPECT_GPR_X86_64(fs);
- EXPECT_GPR_X86_64(gs);
- EXPECT_GPR_X86_64(es);
- EXPECT_GPR_X86_64(ds);
- EXPECT_GPR_X86_64(rip);
- EXPECT_GPR_X86_64(cs);
- EXPECT_GPR_X86_64(rflags);
- EXPECT_GPR_X86_64(rsp);
- EXPECT_GPR_X86_64(ss);
-
- // fctrl is the first FPR field, it is used to determine offset of the whole
- // FPR struct
- size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_x86_64].byte_offset;
-
- // assert against FXSAVE struct
- EXPECT_OFF(fctrl_x86_64, 0x00, 2);
- EXPECT_OFF(fstat_x86_64, 0x02, 2);
- // TODO: This is a known bug, abridged ftag should is 8 bits in length.
- EXPECT_OFF(ftag_x86_64, 0x04, 2);
- EXPECT_OFF(fop_x86_64, 0x06, 2);
- // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits
- // are reserved. However, LLDB defines them to be 32-bit long for backwards
- // compatibility, as they were used to reconstruct FIP/FDP before explicit
- // register entries for them were added. Also, this is still how GDB does it.
- EXPECT_OFF(fioff_x86_64, 0x08, 4);
- EXPECT_OFF(fiseg_x86_64, 0x0C, 4);
- EXPECT_OFF(fip_x86_64, 0x08, 8);
- EXPECT_OFF(fooff_x86_64, 0x10, 4);
- EXPECT_OFF(foseg_x86_64, 0x14, 4);
- EXPECT_OFF(fdp_x86_64, 0x10, 8);
- EXPECT_OFF(mxcsr_x86_64, 0x18, 4);
- EXPECT_OFF(mxcsrmask_x86_64, 0x1C, 4);
- EXPECT_OFF(st0_x86_64, 0x20, 10);
- EXPECT_OFF(st1_x86_64, 0x30, 10);
- EXPECT_OFF(st2_x86_64, 0x40, 10);
- EXPECT_OFF(st3_x86_64, 0x50, 10);
- EXPECT_OFF(st4_x86_64, 0x60, 10);
- EXPECT_OFF(st5_x86_64, 0x70, 10);
- EXPECT_OFF(st6_x86_64, 0x80, 10);
- EXPECT_OFF(st7_x86_64, 0x90, 10);
- EXPECT_OFF(mm0_x86_64, 0x20, 8);
- EXPECT_OFF(mm1_x86_64, 0x30, 8);
- EXPECT_OFF(mm2_x86_64, 0x40, 8);
- EXPECT_OFF(mm3_x86_64, 0x50, 8);
- EXPECT_OFF(mm4_x86_64, 0x60, 8);
- EXPECT_OFF(mm5_x86_64, 0x70, 8);
- EXPECT_OFF(mm6_x86_64, 0x80, 8);
- EXPECT_OFF(mm7_x86_64, 0x90, 8);
- EXPECT_OFF(xmm0_x86_64, 0xA0, 16);
- EXPECT_OFF(xmm1_x86_64, 0xB0, 16);
- EXPECT_OFF(xmm2_x86_64, 0xC0, 16);
- EXPECT_OFF(xmm3_x86_64, 0xD0, 16);
- EXPECT_OFF(xmm4_x86_64, 0xE0, 16);
- EXPECT_OFF(xmm5_x86_64, 0xF0, 16);
- EXPECT_OFF(xmm6_x86_64, 0x100, 16);
- EXPECT_OFF(xmm7_x86_64, 0x110, 16);
- EXPECT_OFF(xmm8_x86_64, 0x120, 16);
- EXPECT_OFF(xmm9_x86_64, 0x130, 16);
- EXPECT_OFF(xmm10_x86_64, 0x140, 16);
- EXPECT_OFF(xmm11_x86_64, 0x150, 16);
- EXPECT_OFF(xmm12_x86_64, 0x160, 16);
- EXPECT_OFF(xmm13_x86_64, 0x170, 16);
- EXPECT_OFF(xmm14_x86_64, 0x180, 16);
- EXPECT_OFF(xmm15_x86_64, 0x190, 16);
-
- base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_x86_64].byte_offset;
- EXPECT_DBR_X86_64(0);
- EXPECT_DBR_X86_64(1);
- EXPECT_DBR_X86_64(2);
- EXPECT_DBR_X86_64(3);
- EXPECT_DBR_X86_64(4);
- EXPECT_DBR_X86_64(5);
- EXPECT_DBR_X86_64(6);
- EXPECT_DBR_X86_64(7);
-}
-
-#endif // defined(__x86_64__)
-
-#if defined(__i386__) || defined(__x86_64__)
-
-#define EXPECT_GPR_I386(regname) \
- EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \
- ::testing::Pair(offsetof(native_i386_regs, r_##regname), \
- sizeof(native_i386_regs::r_##regname)))
-#define EXPECT_DBR_I386(num) \
- EXPECT_OFF(dr##num##_i386, offsetof(native_i386_dbregs, dr[num]), \
- sizeof(native_i386_dbregs::dr[num]))
-
-TEST(RegisterContextFreeBSDTest, i386) {
- ArchSpec arch{"i686-unknown-freebsd"};
- RegisterContextFreeBSD_i386 reg_ctx{arch};
-
-#if defined(__i386__)
- using native_i386_regs = ::reg;
- using native_i386_dbregs = ::dbreg;
-#else
- using native_i386_regs = ::reg32;
- using native_i386_dbregs = ::dbreg32;
-#endif
-
- EXPECT_GPR_I386(fs);
- EXPECT_GPR_I386(es);
- EXPECT_GPR_I386(ds);
- EXPECT_GPR_I386(edi);
- EXPECT_GPR_I386(esi);
- EXPECT_GPR_I386(ebp);
- EXPECT_GPR_I386(ebx);
- EXPECT_GPR_I386(edx);
- EXPECT_GPR_I386(ecx);
- EXPECT_GPR_I386(eax);
- EXPECT_GPR_I386(eip);
- EXPECT_GPR_I386(cs);
- EXPECT_GPR_I386(eflags);
- EXPECT_GPR_I386(esp);
- EXPECT_GPR_I386(ss);
- EXPECT_GPR_I386(gs);
-
- // fctrl is the first FPR field, it is used to determine offset of the whole
- // FPR struct
- size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_i386].byte_offset;
-
- // assert against FXSAVE struct
- EXPECT_OFF(fctrl_i386, 0x00, 2);
- EXPECT_OFF(fstat_i386, 0x02, 2);
- // TODO: This is a known bug, abridged ftag should is 8 bits in length.
- EXPECT_OFF(ftag_i386, 0x04, 2);
- EXPECT_OFF(fop_i386, 0x06, 2);
- // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits
- // are reserved. However, we use them to access/recombine 64-bit FIP/FDP.
- EXPECT_OFF(fioff_i386, 0x08, 4);
- EXPECT_OFF(fiseg_i386, 0x0C, 4);
- EXPECT_OFF(fooff_i386, 0x10, 4);
- EXPECT_OFF(foseg_i386, 0x14, 4);
- EXPECT_OFF(mxcsr_i386, 0x18, 4);
- EXPECT_OFF(mxcsrmask_i386, 0x1C, 4);
- EXPECT_OFF(st0_i386, 0x20, 10);
- EXPECT_OFF(st1_i386, 0x30, 10);
- EXPECT_OFF(st2_i386, 0x40, 10);
- EXPECT_OFF(st3_i386, 0x50, 10);
- EXPECT_OFF(st4_i386, 0x60, 10);
- EXPECT_OFF(st5_i386, 0x70, 10);
- EXPECT_OFF(st6_i386, 0x80, 10);
- EXPECT_OFF(st7_i386, 0x90, 10);
- EXPECT_OFF(mm0_i386, 0x20, 8);
- EXPECT_OFF(mm1_i386, 0x30, 8);
- EXPECT_OFF(mm2_i386, 0x40, 8);
- EXPECT_OFF(mm3_i386, 0x50, 8);
- EXPECT_OFF(mm4_i386, 0x60, 8);
- EXPECT_OFF(mm5_i386, 0x70, 8);
- EXPECT_OFF(mm6_i386, 0x80, 8);
- EXPECT_OFF(mm7_i386, 0x90, 8);
- EXPECT_OFF(xmm0_i386, 0xA0, 16);
- EXPECT_OFF(xmm1_i386, 0xB0, 16);
- EXPECT_OFF(xmm2_i386, 0xC0, 16);
- EXPECT_OFF(xmm3_i386, 0xD0, 16);
- EXPECT_OFF(xmm4_i386, 0xE0, 16);
- EXPECT_OFF(xmm5_i386, 0xF0, 16);
- EXPECT_OFF(xmm6_i386, 0x100, 16);
- EXPECT_OFF(xmm7_i386, 0x110, 16);
-
- base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_i386].byte_offset;
- EXPECT_DBR_I386(0);
- EXPECT_DBR_I386(1);
- EXPECT_DBR_I386(2);
- EXPECT_DBR_I386(3);
- EXPECT_DBR_I386(4);
- EXPECT_DBR_I386(5);
- EXPECT_DBR_I386(6);
- EXPECT_DBR_I386(7);
-}
-
-#endif // defined(__i386__) || defined(__x86_64__)
-
-#if defined(__arm__)
-
-#define EXPECT_GPR_ARM(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm), \
- ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg)))
-#define EXPECT_FPU_ARM(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm), \
- ::testing::Pair(offsetof(vfp_state, fbsd_reg) + base_offset, \
- sizeof(vfp_state::fbsd_reg)))
-
-TEST(RegisterContextFreeBSDTest, arm) {
- ArchSpec arch{"arm-unknown-freebsd"};
- RegisterInfoPOSIX_arm reg_ctx{arch};
-
- EXPECT_GPR_ARM(r0, r[0]);
- EXPECT_GPR_ARM(r1, r[1]);
- EXPECT_GPR_ARM(r2, r[2]);
- EXPECT_GPR_ARM(r3, r[3]);
- EXPECT_GPR_ARM(r4, r[4]);
- EXPECT_GPR_ARM(r5, r[5]);
- EXPECT_GPR_ARM(r6, r[6]);
- EXPECT_GPR_ARM(r7, r[7]);
- EXPECT_GPR_ARM(r8, r[8]);
- EXPECT_GPR_ARM(r9, r[9]);
- EXPECT_GPR_ARM(r10, r[10]);
- EXPECT_GPR_ARM(r11, r[11]);
- EXPECT_GPR_ARM(r12, r[12]);
- EXPECT_GPR_ARM(sp, r_sp);
- EXPECT_GPR_ARM(lr, r_lr);
- EXPECT_GPR_ARM(pc, r_pc);
- EXPECT_GPR_ARM(cpsr, r_cpsr);
-
- size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_d0_arm].byte_offset;
-
- EXPECT_FPU_ARM(d0, reg[0]);
- EXPECT_FPU_ARM(d1, reg[1]);
- EXPECT_FPU_ARM(d2, reg[2]);
- EXPECT_FPU_ARM(d3, reg[3]);
- EXPECT_FPU_ARM(d4, reg[4]);
- EXPECT_FPU_ARM(d5, reg[5]);
- EXPECT_FPU_ARM(d6, reg[6]);
- EXPECT_FPU_ARM(d7, reg[7]);
- EXPECT_FPU_ARM(d8, reg[8]);
- EXPECT_FPU_ARM(d9, reg[9]);
- EXPECT_FPU_ARM(d10, reg[10]);
- EXPECT_FPU_ARM(d11, reg[11]);
- EXPECT_FPU_ARM(d12, reg[12]);
- EXPECT_FPU_ARM(d13, reg[13]);
- EXPECT_FPU_ARM(d14, reg[14]);
- EXPECT_FPU_ARM(d15, reg[15]);
- EXPECT_FPU_ARM(d16, reg[16]);
- EXPECT_FPU_ARM(d17, reg[17]);
- EXPECT_FPU_ARM(d18, reg[18]);
- EXPECT_FPU_ARM(d19, reg[19]);
- EXPECT_FPU_ARM(d20, reg[20]);
- EXPECT_FPU_ARM(d21, reg[21]);
- EXPECT_FPU_ARM(d22, reg[22]);
- EXPECT_FPU_ARM(d23, reg[23]);
- EXPECT_FPU_ARM(d24, reg[24]);
- EXPECT_FPU_ARM(d25, reg[25]);
- EXPECT_FPU_ARM(d26, reg[26]);
- EXPECT_FPU_ARM(d27, reg[27]);
- EXPECT_FPU_ARM(d28, reg[28]);
- EXPECT_FPU_ARM(d29, reg[29]);
- EXPECT_FPU_ARM(d30, reg[30]);
- EXPECT_FPU_ARM(d31, reg[31]);
- EXPECT_FPU_ARM(fpscr, fpscr);
-}
-
-#endif // defined(__arm__)
-
-#if defined(__aarch64__)
-
-#define EXPECT_GPR_ARM64(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm64), \
- ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg)))
-#define EXPECT_FPU_ARM64(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm64), \
- ::testing::Pair(offsetof(fpreg, fbsd_reg) + base_offset, \
- sizeof(fpreg::fbsd_reg)))
-
-TEST(RegisterContextFreeBSDTest, arm64) {
- ArchSpec arch{"aarch64-unknown-freebsd"};
- RegisterInfoPOSIX_arm64 reg_ctx{arch};
-
- EXPECT_GPR_ARM64(x0, x[0]);
- EXPECT_GPR_ARM64(x1, x[1]);
- EXPECT_GPR_ARM64(x2, x[2]);
- EXPECT_GPR_ARM64(x3, x[3]);
- EXPECT_GPR_ARM64(x4, x[4]);
- EXPECT_GPR_ARM64(x5, x[5]);
- EXPECT_GPR_ARM64(x6, x[6]);
- EXPECT_GPR_ARM64(x7, x[7]);
- EXPECT_GPR_ARM64(x8, x[8]);
- EXPECT_GPR_ARM64(x9, x[9]);
- EXPECT_GPR_ARM64(x10, x[10]);
- EXPECT_GPR_ARM64(x11, x[11]);
- EXPECT_GPR_ARM64(x12, x[12]);
- EXPECT_GPR_ARM64(x13, x[13]);
- EXPECT_GPR_ARM64(x14, x[14]);
- EXPECT_GPR_ARM64(x15, x[15]);
- EXPECT_GPR_ARM64(x16, x[16]);
- EXPECT_GPR_ARM64(x17, x[17]);
- EXPECT_GPR_ARM64(x18, x[18]);
- EXPECT_GPR_ARM64(x19, x[19]);
- EXPECT_GPR_ARM64(x20, x[20]);
- EXPECT_GPR_ARM64(x21, x[21]);
- EXPECT_GPR_ARM64(x22, x[22]);
- EXPECT_GPR_ARM64(x23, x[23]);
- EXPECT_GPR_ARM64(x24, x[24]);
- EXPECT_GPR_ARM64(x25, x[25]);
- EXPECT_GPR_ARM64(x26, x[26]);
- EXPECT_GPR_ARM64(x27, x[27]);
- EXPECT_GPR_ARM64(x28, x[28]);
- EXPECT_GPR_ARM64(fp, x[29]);
- EXPECT_GPR_ARM64(lr, lr);
- EXPECT_GPR_ARM64(sp, sp);
- EXPECT_GPR_ARM64(pc, elr);
- EXPECT_GPR_ARM64(cpsr, spsr);
-
- size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_v0_arm64].byte_offset;
-
- EXPECT_FPU_ARM64(v0, fp_q[0]);
- EXPECT_FPU_ARM64(v1, fp_q[1]);
- EXPECT_FPU_ARM64(v2, fp_q[2]);
- EXPECT_FPU_ARM64(v3, fp_q[3]);
- EXPECT_FPU_ARM64(v4, fp_q[4]);
- EXPECT_FPU_ARM64(v5, fp_q[5]);
- EXPECT_FPU_ARM64(v6, fp_q[6]);
- EXPECT_FPU_ARM64(v7, fp_q[7]);
- EXPECT_FPU_ARM64(v8, fp_q[8]);
- EXPECT_FPU_ARM64(v9, fp_q[9]);
- EXPECT_FPU_ARM64(v10, fp_q[10]);
- EXPECT_FPU_ARM64(v11, fp_q[11]);
- EXPECT_FPU_ARM64(v12, fp_q[12]);
- EXPECT_FPU_ARM64(v13, fp_q[13]);
- EXPECT_FPU_ARM64(v14, fp_q[14]);
- EXPECT_FPU_ARM64(v15, fp_q[15]);
- EXPECT_FPU_ARM64(v16, fp_q[16]);
- EXPECT_FPU_ARM64(v17, fp_q[17]);
- EXPECT_FPU_ARM64(v18, fp_q[18]);
- EXPECT_FPU_ARM64(v19, fp_q[19]);
- EXPECT_FPU_ARM64(v20, fp_q[20]);
- EXPECT_FPU_ARM64(v21, fp_q[21]);
- EXPECT_FPU_ARM64(v22, fp_q[22]);
- EXPECT_FPU_ARM64(v23, fp_q[23]);
- EXPECT_FPU_ARM64(v24, fp_q[24]);
- EXPECT_FPU_ARM64(v25, fp_q[25]);
- EXPECT_FPU_ARM64(v26, fp_q[26]);
- EXPECT_FPU_ARM64(v27, fp_q[27]);
- EXPECT_FPU_ARM64(v28, fp_q[28]);
- EXPECT_FPU_ARM64(v29, fp_q[29]);
- EXPECT_FPU_ARM64(v30, fp_q[30]);
- EXPECT_FPU_ARM64(v31, fp_q[31]);
- EXPECT_FPU_ARM64(fpsr, fp_sr);
- EXPECT_FPU_ARM64(fpcr, fp_cr);
-}
-
-#endif // defined(__aarch64__)
-
-#if defined(__mips64__)
-
-#define EXPECT_GPR_MIPS64(lldb_reg, fbsd_regno) \
- EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_mips64), \
- ::testing::Pair(offsetof(reg, r_regs[fbsd_regno]), \
- sizeof(reg::r_regs[fbsd_regno])))
-
-TEST(RegisterContextFreeBSDTest, mips64) {
- ArchSpec arch{"mips64-unknown-freebsd"};
- RegisterContextFreeBSD_mips64 reg_ctx{arch};
-
- // we can not use aliases from <machine/regnum.h> because macros defined
- // there are not namespaced and collide a lot, e.g. 'A1'
-
- EXPECT_GPR_MIPS64(zero, 0);
- EXPECT_GPR_MIPS64(r1, 1);
- EXPECT_GPR_MIPS64(r2, 2);
- EXPECT_GPR_MIPS64(r3, 3);
- EXPECT_GPR_MIPS64(r4, 4);
- EXPECT_GPR_MIPS64(r5, 5);
- EXPECT_GPR_MIPS64(r6, 6);
- EXPECT_GPR_MIPS64(r7, 7);
- EXPECT_GPR_MIPS64(r8, 8);
- EXPECT_GPR_MIPS64(r9, 9);
- EXPECT_GPR_MIPS64(r10, 10);
- EXPECT_GPR_MIPS64(r11, 11);
- EXPECT_GPR_MIPS64(r12, 12);
- EXPECT_GPR_MIPS64(r13, 13);
- EXPECT_GPR_MIPS64(r14, 14);
- EXPECT_GPR_MIPS64(r15, 15);
- EXPECT_GPR_MIPS64(r16, 16);
- EXPECT_GPR_MIPS64(r17, 17);
- EXPECT_GPR_MIPS64(r18, 18);
- EXPECT_GPR_MIPS64(r19, 19);
- EXPECT_GPR_MIPS64(r20, 20);
- EXPECT_GPR_MIPS64(r21, 21);
- EXPECT_GPR_MIPS64(r22, 22);
- EXPECT_GPR_MIPS64(r23, 23);
- EXPECT_GPR_MIPS64(r24, 24);
- EXPECT_GPR_MIPS64(r25, 25);
- EXPECT_GPR_MIPS64(r26, 26);
- EXPECT_GPR_MIPS64(r27, 27);
- EXPECT_GPR_MIPS64(gp, 28);
- EXPECT_GPR_MIPS64(sp, 29);
- EXPECT_GPR_MIPS64(r30, 30);
- EXPECT_GPR_MIPS64(ra, 31);
- EXPECT_GPR_MIPS64(sr, 32);
- EXPECT_GPR_MIPS64(mullo, 33);
- EXPECT_GPR_MIPS64(mulhi, 34);
- EXPECT_GPR_MIPS64(badvaddr, 35);
- EXPECT_GPR_MIPS64(cause, 36);
- EXPECT_GPR_MIPS64(pc, 37);
- EXPECT_GPR_MIPS64(ic, 38);
- EXPECT_GPR_MIPS64(dummy, 39);
-}
-
-#endif // defined(__mips64__)
-
-#if defined(__powerpc__)
-
-#define EXPECT_GPR_PPC(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_powerpc), \
- ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg)))
-#define EXPECT_FPU_PPC(lldb_reg, fbsd_reg) \
- EXPECT_THAT(GetRegParams(reg_ctx, fpr_##lldb_reg##_powerpc), \
- ::testing::Pair(offsetof(fpreg, fbsd_reg) + base_offset, \
- sizeof(fpreg::fbsd_reg)))
-
-TEST(RegisterContextFreeBSDTest, powerpc32) {
- ArchSpec arch{"powerpc-unknown-freebsd"};
- RegisterContextFreeBSD_powerpc32 reg_ctx{arch};
-
- EXPECT_GPR_PPC(r0, fixreg[0]);
- EXPECT_GPR_PPC(r1, fixreg[1]);
- EXPECT_GPR_PPC(r2, fixreg[2]);
- EXPECT_GPR_PPC(r3, fixreg[3]);
- EXPECT_GPR_PPC(r4, fixreg[4]);
- EXPECT_GPR_PPC(r5, fixreg[5]);
- EXPECT_GPR_PPC(r6, fixreg[6]);
- EXPECT_GPR_PPC(r7, fixreg[7]);
- EXPECT_GPR_PPC(r8, fixreg[8]);
- EXPECT_GPR_PPC(r9, fixreg[9]);
- EXPECT_GPR_PPC(r10, fixreg[10]);
- EXPECT_GPR_PPC(r11, fixreg[11]);
- EXPECT_GPR_PPC(r12, fixreg[12]);
- EXPECT_GPR_PPC(r13, fixreg[13]);
- EXPECT_GPR_PPC(r14, fixreg[14]);
- EXPECT_GPR_PPC(r15, fixreg[15]);
- EXPECT_GPR_PPC(r16, fixreg[16]);
- EXPECT_GPR_PPC(r17, fixreg[17]);
- EXPECT_GPR_PPC(r18, fixreg[18]);
- EXPECT_GPR_PPC(r19, fixreg[19]);
- EXPECT_GPR_PPC(r20, fixreg[20]);
- EXPECT_GPR_PPC(r21, fixreg[21]);
- EXPECT_GPR_PPC(r22, fixreg[22]);
- EXPECT_GPR_PPC(r23, fixreg[23]);
- EXPECT_GPR_PPC(r24, fixreg[24]);
- EXPECT_GPR_PPC(r25, fixreg[25]);
- EXPECT_GPR_PPC(r26, fixreg[26]);
- EXPECT_GPR_PPC(r27, fixreg[27]);
- EXPECT_GPR_PPC(r28, fixreg[28]);
- EXPECT_GPR_PPC(r29, fixreg[29]);
- EXPECT_GPR_PPC(r30, fixreg[30]);
- EXPECT_GPR_PPC(r31, fixreg[31]);
- EXPECT_GPR_PPC(lr, lr);
- EXPECT_GPR_PPC(cr, cr);
- EXPECT_GPR_PPC(xer, xer);
- EXPECT_GPR_PPC(ctr, ctr);
- EXPECT_GPR_PPC(pc, pc);
-
- size_t base_offset = reg_ctx.GetRegisterInfo()[fpr_f0_powerpc].byte_offset;
-
- EXPECT_FPU_PPC(f0, fpreg[0]);
- EXPECT_FPU_PPC(f1, fpreg[1]);
- EXPECT_FPU_PPC(f2, fpreg[2]);
- EXPECT_FPU_PPC(f3, fpreg[3]);
- EXPECT_FPU_PPC(f4, fpreg[4]);
- EXPECT_FPU_PPC(f5, fpreg[5]);
- EXPECT_FPU_PPC(f6, fpreg[6]);
- EXPECT_FPU_PPC(f7, fpreg[7]);
- EXPECT_FPU_PPC(f8, fpreg[8]);
- EXPECT_FPU_PPC(f9, fpreg[9]);
- EXPECT_FPU_PPC(f10, fpreg[10]);
- EXPECT_FPU_PPC(f11, fpreg[11]);
- EXPECT_FPU_PPC(f12, fpreg[12]);
- EXPECT_FPU_PPC(f13, fpreg[13]);
- EXPECT_FPU_PPC(f14, fpreg[14]);
- EXPECT_FPU_PPC(f15, fpreg[15]);
- EXPECT_FPU_PPC(f16, fpreg[16]);
- EXPECT_FPU_PPC(f17, fpreg[17]);
- EXPECT_FPU_PPC(f18, fpreg[18]);
- EXPECT_FPU_PPC(f19, fpreg[19]);
- EXPECT_FPU_PPC(f20, fpreg[20]);
- EXPECT_FPU_PPC(f21, fpreg[21]);
- EXPECT_FPU_PPC(f22, fpreg[22]);
- EXPECT_FPU_PPC(f23, fpreg[23]);
- EXPECT_FPU_PPC(f24, fpreg[24]);
- EXPECT_FPU_PPC(f25, fpreg[25]);
- EXPECT_FPU_PPC(f26, fpreg[26]);
- EXPECT_FPU_PPC(f27, fpreg[27]);
- EXPECT_FPU_PPC(f28, fpreg[28]);
- EXPECT_FPU_PPC(f29, fpreg[29]);
- EXPECT_FPU_PPC(f30, fpreg[30]);
- EXPECT_FPU_PPC(f31, fpreg[31]);
- EXPECT_FPU_PPC(fpscr, fpscr);
-}
-
-#endif // defined(__powerpc__)
+++ /dev/null
-//===-- RegisterContextNetBSDTest_i386.cpp --------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#if defined(__i386__) || defined(__x86_64__)
-
-// clang-format off
-#include <sys/types.h>
-#include <i386/reg.h>
-// clang-format on
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-static std::pair<size_t, size_t> GetRegParams(RegisterInfoInterface &ctx,
- uint32_t reg) {
- const RegisterInfo &info = ctx.GetRegisterInfo()[reg];
- return {info.byte_offset, info.byte_size};
-}
-
-#define EXPECT_OFF(regname, offset, size) \
- EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \
- ::testing::Pair(offset + base_offset, size))
-
-#define EXPECT_GPR_I386(regname) \
- EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \
- ::testing::Pair(offsetof(reg, r_##regname), \
- sizeof(reg::r_##regname)))
-#define EXPECT_DBR_I386(num) \
- EXPECT_OFF(dr##num##_i386, offsetof(dbreg, dr[num]), \
- sizeof(dbreg::dr[num]))
-
-TEST(RegisterContextNetBSDTest, i386) {
- ArchSpec arch{"i686-unknown-netbsd"};
- RegisterContextNetBSD_i386 reg_ctx{arch};
-
- EXPECT_GPR_I386(eax);
- EXPECT_GPR_I386(ecx);
- EXPECT_GPR_I386(edx);
- EXPECT_GPR_I386(ebx);
- EXPECT_GPR_I386(esp);
- EXPECT_GPR_I386(ebp);
- EXPECT_GPR_I386(esi);
- EXPECT_GPR_I386(edi);
- EXPECT_GPR_I386(eip);
- EXPECT_GPR_I386(eflags);
- EXPECT_GPR_I386(cs);
- EXPECT_GPR_I386(ss);
- EXPECT_GPR_I386(ds);
- EXPECT_GPR_I386(es);
- EXPECT_GPR_I386(fs);
- EXPECT_GPR_I386(gs);
-
- // fctrl is the first FPR field, it is used to determine offset of the whole
- // FPR struct
- size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_i386].byte_offset;
-
- // assert against FXSAVE struct
- EXPECT_OFF(fctrl_i386, 0x00, 2);
- EXPECT_OFF(fstat_i386, 0x02, 2);
- // TODO: This is a known bug, abridged ftag should is 8 bits in length.
- EXPECT_OFF(ftag_i386, 0x04, 2);
- EXPECT_OFF(fop_i386, 0x06, 2);
- // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits
- // are reserved. However, we use them to access/recombine 64-bit FIP/FDP.
- EXPECT_OFF(fioff_i386, 0x08, 4);
- EXPECT_OFF(fiseg_i386, 0x0C, 4);
- EXPECT_OFF(fooff_i386, 0x10, 4);
- EXPECT_OFF(foseg_i386, 0x14, 4);
- EXPECT_OFF(mxcsr_i386, 0x18, 4);
- EXPECT_OFF(mxcsrmask_i386, 0x1C, 4);
- EXPECT_OFF(st0_i386, 0x20, 10);
- EXPECT_OFF(st1_i386, 0x30, 10);
- EXPECT_OFF(st2_i386, 0x40, 10);
- EXPECT_OFF(st3_i386, 0x50, 10);
- EXPECT_OFF(st4_i386, 0x60, 10);
- EXPECT_OFF(st5_i386, 0x70, 10);
- EXPECT_OFF(st6_i386, 0x80, 10);
- EXPECT_OFF(st7_i386, 0x90, 10);
- EXPECT_OFF(mm0_i386, 0x20, 8);
- EXPECT_OFF(mm1_i386, 0x30, 8);
- EXPECT_OFF(mm2_i386, 0x40, 8);
- EXPECT_OFF(mm3_i386, 0x50, 8);
- EXPECT_OFF(mm4_i386, 0x60, 8);
- EXPECT_OFF(mm5_i386, 0x70, 8);
- EXPECT_OFF(mm6_i386, 0x80, 8);
- EXPECT_OFF(mm7_i386, 0x90, 8);
- EXPECT_OFF(xmm0_i386, 0xA0, 16);
- EXPECT_OFF(xmm1_i386, 0xB0, 16);
- EXPECT_OFF(xmm2_i386, 0xC0, 16);
- EXPECT_OFF(xmm3_i386, 0xD0, 16);
- EXPECT_OFF(xmm4_i386, 0xE0, 16);
- EXPECT_OFF(xmm5_i386, 0xF0, 16);
- EXPECT_OFF(xmm6_i386, 0x100, 16);
- EXPECT_OFF(xmm7_i386, 0x110, 16);
-
- base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_i386].byte_offset;
- EXPECT_DBR_I386(0);
- EXPECT_DBR_I386(1);
- EXPECT_DBR_I386(2);
- EXPECT_DBR_I386(3);
- EXPECT_DBR_I386(4);
- EXPECT_DBR_I386(5);
- EXPECT_DBR_I386(6);
- EXPECT_DBR_I386(7);
-}
-
-#endif // defined(__i386__) || defined(__x86_64__)
+++ /dev/null
-//===-- RegisterContextNetBSDTest_x86_64.cpp ------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#if defined(__x86_64__)
-
-// clang-format off
-#include <sys/types.h>
-#include <amd64/reg.h>
-// clang-format on
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
-#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-static std::pair<size_t, size_t> GetRegParams(RegisterInfoInterface &ctx,
- uint32_t reg) {
- const RegisterInfo &info = ctx.GetRegisterInfo()[reg];
- return {info.byte_offset, info.byte_size};
-}
-
-#define EXPECT_OFF(regname, offset, size) \
- EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \
- ::testing::Pair(offset + base_offset, size))
-
-#define EXPECT_GPR_X86_64(regname, regconst) \
- EXPECT_THAT( \
- GetRegParams(reg_ctx, lldb_##regname##_x86_64), \
- ::testing::Pair(offsetof(reg, regs[regconst]), \
- sizeof(reg::regs[regconst])))
-#define EXPECT_DBR_X86_64(num) \
- EXPECT_OFF(dr##num##_x86_64, offsetof(dbreg, dr[num]), sizeof(dbreg::dr[num]))
-
-TEST(RegisterContextNetBSDTest, x86_64) {
- ArchSpec arch{"x86_64-unknown-netbsd"};
- RegisterContextNetBSD_x86_64 reg_ctx{arch};
-
- EXPECT_GPR_X86_64(rdi, _REG_RDI);
- EXPECT_GPR_X86_64(rsi, _REG_RSI);
- EXPECT_GPR_X86_64(rdx, _REG_RDX);
- EXPECT_GPR_X86_64(rcx, _REG_RCX);
- EXPECT_GPR_X86_64(r8, _REG_R8);
- EXPECT_GPR_X86_64(r9, _REG_R9);
- EXPECT_GPR_X86_64(r10, _REG_R10);
- EXPECT_GPR_X86_64(r11, _REG_R11);
- EXPECT_GPR_X86_64(r12, _REG_R12);
- EXPECT_GPR_X86_64(r13, _REG_R13);
- EXPECT_GPR_X86_64(r14, _REG_R14);
- EXPECT_GPR_X86_64(r15, _REG_R15);
- EXPECT_GPR_X86_64(rbp, _REG_RBP);
- EXPECT_GPR_X86_64(rbx, _REG_RBX);
- EXPECT_GPR_X86_64(rax, _REG_RAX);
- EXPECT_GPR_X86_64(gs, _REG_GS);
- EXPECT_GPR_X86_64(fs, _REG_FS);
- EXPECT_GPR_X86_64(es, _REG_ES);
- EXPECT_GPR_X86_64(ds, _REG_DS);
- EXPECT_GPR_X86_64(rip, _REG_RIP);
- EXPECT_GPR_X86_64(cs, _REG_CS);
- EXPECT_GPR_X86_64(rflags, _REG_RFLAGS);
- EXPECT_GPR_X86_64(rsp, _REG_RSP);
- EXPECT_GPR_X86_64(ss, _REG_SS);
-
- // fctrl is the first FPR field, it is used to determine offset of the whole
- // FPR struct
- size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_x86_64].byte_offset;
-
- // assert against FXSAVE struct
- EXPECT_OFF(fctrl_x86_64, 0x00, 2);
- EXPECT_OFF(fstat_x86_64, 0x02, 2);
- // TODO: This is a known bug, abridged ftag should is 8 bits in length.
- EXPECT_OFF(ftag_x86_64, 0x04, 2);
- EXPECT_OFF(fop_x86_64, 0x06, 2);
- // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits
- // are reserved. However, LLDB defines them to be 32-bit long for backwards
- // compatibility, as they were used to reconstruct FIP/FDP before explicit
- // register entries for them were added. Also, this is still how GDB does it.
- EXPECT_OFF(fioff_x86_64, 0x08, 4);
- EXPECT_OFF(fiseg_x86_64, 0x0C, 4);
- EXPECT_OFF(fip_x86_64, 0x08, 8);
- EXPECT_OFF(fooff_x86_64, 0x10, 4);
- EXPECT_OFF(foseg_x86_64, 0x14, 4);
- EXPECT_OFF(fdp_x86_64, 0x10, 8);
- EXPECT_OFF(mxcsr_x86_64, 0x18, 4);
- EXPECT_OFF(mxcsrmask_x86_64, 0x1C, 4);
- EXPECT_OFF(st0_x86_64, 0x20, 10);
- EXPECT_OFF(st1_x86_64, 0x30, 10);
- EXPECT_OFF(st2_x86_64, 0x40, 10);
- EXPECT_OFF(st3_x86_64, 0x50, 10);
- EXPECT_OFF(st4_x86_64, 0x60, 10);
- EXPECT_OFF(st5_x86_64, 0x70, 10);
- EXPECT_OFF(st6_x86_64, 0x80, 10);
- EXPECT_OFF(st7_x86_64, 0x90, 10);
- EXPECT_OFF(mm0_x86_64, 0x20, 8);
- EXPECT_OFF(mm1_x86_64, 0x30, 8);
- EXPECT_OFF(mm2_x86_64, 0x40, 8);
- EXPECT_OFF(mm3_x86_64, 0x50, 8);
- EXPECT_OFF(mm4_x86_64, 0x60, 8);
- EXPECT_OFF(mm5_x86_64, 0x70, 8);
- EXPECT_OFF(mm6_x86_64, 0x80, 8);
- EXPECT_OFF(mm7_x86_64, 0x90, 8);
- EXPECT_OFF(xmm0_x86_64, 0xA0, 16);
- EXPECT_OFF(xmm1_x86_64, 0xB0, 16);
- EXPECT_OFF(xmm2_x86_64, 0xC0, 16);
- EXPECT_OFF(xmm3_x86_64, 0xD0, 16);
- EXPECT_OFF(xmm4_x86_64, 0xE0, 16);
- EXPECT_OFF(xmm5_x86_64, 0xF0, 16);
- EXPECT_OFF(xmm6_x86_64, 0x100, 16);
- EXPECT_OFF(xmm7_x86_64, 0x110, 16);
- EXPECT_OFF(xmm8_x86_64, 0x120, 16);
- EXPECT_OFF(xmm9_x86_64, 0x130, 16);
- EXPECT_OFF(xmm10_x86_64, 0x140, 16);
- EXPECT_OFF(xmm11_x86_64, 0x150, 16);
- EXPECT_OFF(xmm12_x86_64, 0x160, 16);
- EXPECT_OFF(xmm13_x86_64, 0x170, 16);
- EXPECT_OFF(xmm14_x86_64, 0x180, 16);
- EXPECT_OFF(xmm15_x86_64, 0x190, 16);
-
- base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_x86_64].byte_offset;
- EXPECT_DBR_X86_64(0);
- EXPECT_DBR_X86_64(1);
- EXPECT_DBR_X86_64(2);
- EXPECT_DBR_X86_64(3);
- EXPECT_DBR_X86_64(4);
- EXPECT_DBR_X86_64(5);
- EXPECT_DBR_X86_64(6);
- EXPECT_DBR_X86_64(7);
-}
-
-#endif // defined(__x86_64__)
+++ /dev/null
-//===-- RegisterContextTest.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/Utility/RegisterContext_x86.h"
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/FormatVariadic.h"
-
-#include <array>
-
-using namespace lldb_private;
-
-struct TagWordTestVector {
- uint16_t sw;
- uint16_t tw;
- uint8_t tw_abridged;
- int st_reg_num;
-};
-
-constexpr MMSReg st_from_comp(uint64_t mantissa, uint16_t sign_exp) {
- MMSReg ret = {};
- ret.comp.mantissa = mantissa;
- ret.comp.sign_exp = sign_exp;
- return ret;
-}
-
-const std::array<MMSReg, 8> st_regs = {
- st_from_comp(0x8000000000000000, 0x4000), // +2.0
- st_from_comp(0x3f00000000000000, 0x0000), // 1.654785e-4932
- st_from_comp(0x0000000000000000, 0x0000), // +0
- st_from_comp(0x0000000000000000, 0x8000), // -0
- st_from_comp(0x8000000000000000, 0x7fff), // +inf
- st_from_comp(0x8000000000000000, 0xffff), // -inf
- st_from_comp(0xc000000000000000, 0xffff), // nan
- st_from_comp(0x8000000000000000, 0xc000), // -2.0
-};
-
-const std::array<TagWordTestVector, 8> tag_word_test_vectors{
- TagWordTestVector{0x3800, 0x3fff, 0x80, 1},
- TagWordTestVector{0x3000, 0x2fff, 0xc0, 2},
- TagWordTestVector{0x2800, 0x27ff, 0xe0, 3},
- TagWordTestVector{0x2000, 0x25ff, 0xf0, 4},
- TagWordTestVector{0x1800, 0x25bf, 0xf8, 5},
- TagWordTestVector{0x1000, 0x25af, 0xfc, 6},
- TagWordTestVector{0x0800, 0x25ab, 0xfe, 7},
- TagWordTestVector{0x0000, 0x25a8, 0xff, 8},
-};
-
-TEST(RegisterContext_x86Test, AbridgedToFullTagWord) {
- for (const auto &x : llvm::enumerate(tag_word_test_vectors)) {
- SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index()));
- std::array<MMSReg, 8> test_regs;
- for (int i = 0; i < x.value().st_reg_num; ++i)
- test_regs[i] = st_regs[x.value().st_reg_num - i - 1];
- EXPECT_EQ(
- AbridgedToFullTagWord(x.value().tw_abridged, x.value().sw, test_regs),
- x.value().tw);
- }
-}
-
-TEST(RegisterContext_x86Test, FullToAbridgedTagWord) {
- for (const auto &x : llvm::enumerate(tag_word_test_vectors)) {
- SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index()));
- EXPECT_EQ(FullToAbridgedTagWord(x.value().tw), x.value().tw_abridged);
- }
-}
+++ /dev/null
-add_lldb_unittest(ProcessGdbRemoteTests
- GDBRemoteClientBaseTest.cpp
- GDBRemoteCommunicationClientTest.cpp
- GDBRemoteCommunicationServerTest.cpp
- GDBRemoteCommunicationTest.cpp
- GDBRemoteTestUtils.cpp
- PortMapTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbPluginPlatformMacOSX
- lldbPluginProcessUtility
- lldbPluginProcessGDBRemote
-
- LLVMTestingSupport
-
- LINK_COMPONENTS
- Support
- )
+++ /dev/null
-//===-- GDBRemoteClientBaseTest.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include <future>
-
-#include "GDBRemoteTestUtils.h"
-
-#include "Plugins/Process/Utility/LinuxSignals.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
-#include "lldb/Utility/GDBRemote.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private::process_gdb_remote;
-using namespace lldb_private;
-using namespace lldb;
-typedef GDBRemoteCommunication::PacketResult PacketResult;
-
-namespace {
-
-struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate {
- std::string output;
- std::string misc_data;
- unsigned stop_reply_called = 0;
- std::vector<std::string> structured_data_packets;
-
- void HandleAsyncStdout(llvm::StringRef out) override { output += out; }
- void HandleAsyncMisc(llvm::StringRef data) override { misc_data += data; }
- void HandleStopReply() override { ++stop_reply_called; }
-
- void HandleAsyncStructuredDataPacket(llvm::StringRef data) override {
- structured_data_packets.push_back(std::string(data));
- }
-};
-
-struct TestClient : public GDBRemoteClientBase {
- TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") {
- m_send_acks = false;
- }
-};
-
-class GDBRemoteClientBaseTest : public GDBRemoteTest {
-public:
- void SetUp() override {
- ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
- llvm::Succeeded());
- ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,
- listener_sp->StartListeningForEvents(
- &client, TestClient::eBroadcastBitRunPacketSent));
- }
-
-protected:
- // We don't have a process to get the interrupt timeout from, so make one up.
- static std::chrono::seconds g_timeout;
- TestClient client;
- MockServer server;
- MockDelegate delegate;
- ListenerSP listener_sp = Listener::MakeListener("listener");
-
- StateType SendCPacket(StringExtractorGDBRemote &response) {
- return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),
- "c", g_timeout,
- response);
- }
-
- void WaitForRunEvent() {
- EventSP event_sp;
- listener_sp->GetEventForBroadcasterWithType(
- &client, TestClient::eBroadcastBitRunPacketSent, event_sp, llvm::None);
- }
-};
-
-std::chrono::seconds GDBRemoteClientBaseTest::g_timeout(10);
-
-} // end anonymous namespace
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
- StringExtractorGDBRemote response;
-
- // Continue. The inferior will stop with a signal.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, SendCPacket(response));
- ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
-
- // Continue. The inferior will exit.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));
- ASSERT_EQ(eStateExited, SendCPacket(response));
- ASSERT_EQ("W01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
-
- // Continue. The inferior will get killed.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));
- ASSERT_EQ(eStateExited, SendCPacket(response));
- ASSERT_EQ("X01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
- StringExtractorGDBRemote continue_response, response;
-
- // SendAsyncSignal should do nothing when we are not running.
- ASSERT_FALSE(client.SendAsyncSignal(0x47, g_timeout));
-
- // Continue. After the run packet is sent, send an async signal.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- std::future<bool> async_result = std::async(std::launch::async, [&] {
- return client.SendAsyncSignal(0x47, g_timeout);
- });
-
- // First we'll get interrupted.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
-
- // Then we get the signal packet.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("C47", response.GetStringRef());
- ASSERT_TRUE(async_result.get());
-
- // And we report back a signal stop.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));
- ASSERT_EQ(eStateStopped, continue_state.get());
- ASSERT_EQ("T47", continue_response.GetStringRef());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
- StringExtractorGDBRemote continue_response, async_response, response;
-
- // Continue. After the run packet is sent, send an async packet.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- // Sending without async enabled should fail.
- ASSERT_EQ(PacketResult::ErrorSendFailed,
- client.SendPacketAndWaitForResponse("qTest1", response));
-
- std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
- return client.SendPacketAndWaitForResponse("qTest2", async_response,
- g_timeout);
- });
-
- // First we'll get interrupted.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
-
- // Then we get the async packet.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("qTest2", response.GetStringRef());
-
- // Send the response and receive it.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));
- ASSERT_EQ(PacketResult::Success, async_result.get());
- ASSERT_EQ("QTest2", async_response.GetStringRef());
-
- // And we get resumed again.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, continue_state.get());
- ASSERT_EQ("T01", continue_response.GetStringRef());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
- StringExtractorGDBRemote continue_response, response;
-
- // Interrupt should do nothing when we're not running.
- ASSERT_FALSE(client.Interrupt(g_timeout));
-
- // Continue. After the run packet is sent, send an interrupt.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- std::future<bool> async_result = std::async(
- std::launch::async, [&] { return client.Interrupt(g_timeout); });
-
- // We get interrupted.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
-
- // And that's it.
- ASSERT_EQ(eStateStopped, continue_state.get());
- ASSERT_EQ("T13", continue_response.GetStringRef());
- ASSERT_TRUE(async_result.get());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
- StringExtractorGDBRemote continue_response, response;
-
- // Continue. After the run packet is sent, send an interrupt.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- std::future<bool> async_result = std::async(
- std::launch::async, [&] { return client.Interrupt(g_timeout); });
-
- // However, the target stops due to a different reason than the original
- // interrupt.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, continue_state.get());
- ASSERT_EQ("T01", continue_response.GetStringRef());
- ASSERT_TRUE(async_result.get());
-
- // The subsequent continue packet should work normally.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, SendCPacket(response));
- ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
- StringExtractorGDBRemote continue_response, async_response, response;
-
- // Interrupt should do nothing when we're not running.
- ASSERT_FALSE(client.Interrupt(g_timeout));
-
- // Continue. After the run packet is sent, send an async signal.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- std::future<bool> interrupt_result = std::async(
- std::launch::async, [&] { return client.Interrupt(g_timeout); });
-
- // We get interrupted. We'll send two packets to simulate a buggy stub.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
-
- // We should stop.
- ASSERT_EQ(eStateStopped, continue_state.get());
- ASSERT_EQ("T13", continue_response.GetStringRef());
- ASSERT_TRUE(interrupt_result.get());
-
- // Packet stream should remain synchronized.
- std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
- return client.SendPacketAndWaitForResponse("qTest", async_response);
- });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("qTest", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));
- ASSERT_EQ(PacketResult::Success, send_result.get());
- ASSERT_EQ("QTest", async_response.GetStringRef());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
- StringExtractorGDBRemote response;
-
- // Continue. We'll have the server send a bunch of async packets before it
- // stops.
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, SendCPacket(response));
- ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
-
- EXPECT_EQ("ABCD", delegate.output);
- EXPECT_EQ("profile", delegate.misc_data);
- EXPECT_EQ(1u, delegate.stop_reply_called);
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
- // Build the plain-text version of the JSON data we will have the
- // server send.
- const std::string json_payload =
- "{ \"type\": \"MyFeatureType\", "
- " \"elements\": [ \"entry1\", \"entry2\" ] }";
- const std::string json_packet = "JSON-async:" + json_payload;
-
- // Escape it properly for transit.
- StreamGDBRemote stream;
- stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
- stream.Flush();
-
- StringExtractorGDBRemote response;
-
- // Send async structured data packet, then stop.
- ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
- ASSERT_EQ(eStateStopped, SendCPacket(response));
- ASSERT_EQ("T01", response.GetStringRef());
- ASSERT_EQ(1ul, delegate.structured_data_packets.size());
-
- // Verify the packet contents. It should have been unescaped upon packet
- // reception.
- ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
-}
-
-TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
- StringExtractorGDBRemote continue_response, response;
-
- // Continue. After the run packet is sent, send an interrupt.
- std::future<StateType> continue_state = std::async(
- std::launch::async, [&] { return SendCPacket(continue_response); });
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("c", response.GetStringRef());
- WaitForRunEvent();
-
- std::future<bool> async_result = std::async(
- std::launch::async, [&] { return client.Interrupt(g_timeout); });
-
- // We get interrupted, but we don't send a stop packet.
- ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
- ASSERT_EQ("\x03", response.GetStringRef());
-
- // The functions should still terminate (after a timeout).
- ASSERT_TRUE(async_result.get());
- ASSERT_EQ(eStateInvalid, continue_state.get());
-}
-
-TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) {
- StringExtractorGDBRemote response;
- StreamString command_output;
-
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O20"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64"));
- ASSERT_EQ(PacketResult::Success, server.SendPacket("OK"));
-
- PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport(
- "qRcmd,test", response, g_timeout,
- [&command_output](llvm::StringRef output) { command_output << output; });
-
- ASSERT_EQ(PacketResult::Success, result);
- ASSERT_EQ("OK", response.GetStringRef());
- ASSERT_EQ("Hello, world", command_output.GetString().str());
-}
+++ /dev/null
-//===-- GDBRemoteCommunicationClientTest.cpp ------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
-#include "GDBRemoteTestUtils.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/XML.h"
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Utility/DataBuffer.h"
-#include "lldb/Utility/StructuredData.h"
-#include "lldb/lldb-enumerations.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-#include <future>
-#include <limits>
-
-using namespace lldb_private::process_gdb_remote;
-using namespace lldb_private;
-using namespace lldb;
-using namespace llvm;
-
-namespace {
-
-typedef GDBRemoteCommunication::PacketResult PacketResult;
-
-struct TestClient : public GDBRemoteCommunicationClient {
- TestClient() { m_send_acks = false; }
-};
-
-void Handle_QThreadSuffixSupported(MockServer &server, bool supported) {
- StringExtractorGDBRemote request;
- ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
- ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
- if (supported)
- ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
- else
- ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
-}
-
-void HandlePacket(MockServer &server,
- const testing::Matcher<const std::string &> &expected,
- StringRef response) {
- StringExtractorGDBRemote request;
- ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
- ASSERT_THAT(std::string(request.GetStringRef()), expected);
- ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
-}
-
-uint8_t all_registers[] = {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
- 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'};
-std::string all_registers_hex = "404142434445464748494a4b4c4d4e4f";
-uint8_t one_register[] = {'A', 'B', 'C', 'D'};
-std::string one_register_hex = "41424344";
-
-} // end anonymous namespace
-
-class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
-public:
- void SetUp() override {
- ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
- llvm::Succeeded());
- }
-
-protected:
- TestClient client;
- MockServer server;
-};
-
-TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
- const lldb::tid_t tid = 0x47;
- const uint32_t reg_num = 4;
- std::future<bool> write_result = std::async(std::launch::async, [&] {
- return client.WriteRegister(tid, reg_num, one_register);
- });
-
- Handle_QThreadSuffixSupported(server, true);
-
- HandlePacket(server, "P4=" + one_register_hex + ";thread:0047;", "OK");
- ASSERT_TRUE(write_result.get());
-
- write_result = std::async(std::launch::async, [&] {
- return client.WriteAllRegisters(tid, all_registers);
- });
-
- HandlePacket(server, "G" + all_registers_hex + ";thread:0047;", "OK");
- ASSERT_TRUE(write_result.get());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
- const lldb::tid_t tid = 0x47;
- const uint32_t reg_num = 4;
- std::future<bool> write_result = std::async(std::launch::async, [&] {
- return client.WriteRegister(tid, reg_num, one_register);
- });
-
- Handle_QThreadSuffixSupported(server, false);
- HandlePacket(server, "Hg47", "OK");
- HandlePacket(server, "P4=" + one_register_hex, "OK");
- ASSERT_TRUE(write_result.get());
-
- write_result = std::async(std::launch::async, [&] {
- return client.WriteAllRegisters(tid, all_registers);
- });
-
- HandlePacket(server, "G" + all_registers_hex, "OK");
- ASSERT_TRUE(write_result.get());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
- const lldb::tid_t tid = 0x47;
- const uint32_t reg_num = 4;
- std::future<bool> async_result = std::async(
- std::launch::async, [&] { return client.GetpPacketSupported(tid); });
- Handle_QThreadSuffixSupported(server, true);
- HandlePacket(server, "p0;thread:0047;", one_register_hex);
- ASSERT_TRUE(async_result.get());
-
- std::future<DataBufferSP> read_result = std::async(
- std::launch::async, [&] { return client.ReadRegister(tid, reg_num); });
- HandlePacket(server, "p4;thread:0047;", "41424344");
- auto buffer_sp = read_result.get();
- ASSERT_TRUE(bool(buffer_sp));
- ASSERT_EQ(0,
- memcmp(buffer_sp->GetBytes(), one_register, sizeof one_register));
-
- read_result = std::async(std::launch::async,
- [&] { return client.ReadAllRegisters(tid); });
- HandlePacket(server, "g;thread:0047;", all_registers_hex);
- buffer_sp = read_result.get();
- ASSERT_TRUE(bool(buffer_sp));
- ASSERT_EQ(0,
- memcmp(buffer_sp->GetBytes(), all_registers, sizeof all_registers));
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
- const lldb::tid_t tid = 0x47;
- uint32_t save_id;
- std::future<bool> async_result = std::async(std::launch::async, [&] {
- return client.SaveRegisterState(tid, save_id);
- });
- Handle_QThreadSuffixSupported(server, false);
- HandlePacket(server, "Hg47", "OK");
- HandlePacket(server, "QSaveRegisterState", "1");
- ASSERT_TRUE(async_result.get());
- EXPECT_EQ(1u, save_id);
-
- async_result = std::async(std::launch::async, [&] {
- return client.RestoreRegisterState(tid, save_id);
- });
- HandlePacket(server, "QRestoreRegisterState:1", "OK");
- ASSERT_TRUE(async_result.get());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
- const lldb::tid_t tid = 0x47;
- std::future<bool> async_result = std::async(
- std::launch::async, [&] { return client.SyncThreadState(tid); });
- HandlePacket(server, "qSyncThreadStateSupported", "OK");
- HandlePacket(server, "QSyncThreadState:0047;", "OK");
- ASSERT_TRUE(async_result.get());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
- llvm::Triple triple("i386-pc-linux");
-
- FileSpec file_specs[] = {
- FileSpec("/foo/bar.so", FileSpec::Style::posix),
- FileSpec("/foo/baz.so", FileSpec::Style::posix),
-
- // This is a bit dodgy but we currently depend on GetModulesInfo not
- // performing denormalization. It can go away once the users
- // (DynamicLoaderPOSIXDYLD, at least) correctly set the path syntax for
- // the FileSpecs they create.
- FileSpec("/foo/baw.so", FileSpec::Style::windows),
- };
- std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
- std::async(std::launch::async,
- [&] { return client.GetModulesInfo(file_specs, triple); });
- HandlePacket(
- server, "jModulesInfo:["
- R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)"
- R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)"
- R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])",
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
-
- auto result = async_result.get();
- ASSERT_TRUE(result.hasValue());
- ASSERT_EQ(1u, result->size());
- EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
- EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16),
- result.getValue()[0].GetUUID());
- EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
- EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo_UUID20) {
- llvm::Triple triple("i386-pc-linux");
-
- FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
- std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
- std::async(std::launch::async,
- [&] { return client.GetModulesInfo(file_spec, triple); });
- HandlePacket(
- server,
- "jModulesInfo:["
- R"({"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f50515253","triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])");
-
- auto result = async_result.get();
- ASSERT_TRUE(result.hasValue());
- ASSERT_EQ(1u, result->size());
- EXPECT_EQ("/foo/bar.so", result.getValue()[0].GetFileSpec().GetPath());
- EXPECT_EQ(triple, result.getValue()[0].GetArchitecture().GetTriple());
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20),
- result.getValue()[0].GetUUID());
- EXPECT_EQ(0u, result.getValue()[0].GetObjectOffset());
- EXPECT_EQ(1234u, result.getValue()[0].GetObjectSize());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
- llvm::Triple triple("i386-pc-linux");
- FileSpec file_spec("/foo/bar.so", FileSpec::Style::posix);
-
- const char *invalid_responses[] = {
- // no UUID
- R"([{"triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
- // invalid UUID
- R"([{"uuid":"XXXXXX","triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
- // no triple
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f",)"
- R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])",
- // no file_path
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
- R"("file_offset":0,"file_size":1234}]])",
- // no file_offset
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_size":1234}]])",
- // no file_size
- R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)"
- R"("file_path":"/foo/bar.so","file_offset":0}]])",
- };
-
- for (const char *response : invalid_responses) {
- std::future<llvm::Optional<std::vector<ModuleSpec>>> async_result =
- std::async(std::launch::async,
- [&] { return client.GetModulesInfo(file_spec, triple); });
- HandlePacket(
- server,
- R"(jModulesInfo:[{"file":"/foo/bar.so","triple":"i386-pc-linux"}])",
- response);
-
- auto result = async_result.get();
- ASSERT_TRUE(result);
- ASSERT_EQ(0u, result->size()) << "response was: " << response;
- }
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
- std::thread server_thread([this] {
- for (;;) {
- StringExtractorGDBRemote request;
- PacketResult result = server.GetPacket(request);
- if (result == PacketResult::ErrorDisconnected)
- return;
- ASSERT_EQ(PacketResult::Success, result);
- StringRef ref = request.GetStringRef();
- ASSERT_TRUE(ref.consume_front("qSpeedTest:response_size:"));
- int size;
- ASSERT_FALSE(ref.consumeInteger(10, size)) << "ref: " << ref;
- std::string response(size, 'X');
- ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
- }
- });
-
- StreamString ss;
- client.TestPacketSpeed(10, 32, 32, 4096, true, ss);
- client.Disconnect();
- server_thread.join();
-
- GTEST_LOG_(INFO) << "Formatted output: " << ss.GetData();
- auto object_sp = StructuredData::ParseJSON(std::string(ss.GetString()));
- ASSERT_TRUE(bool(object_sp));
- auto dict_sp = object_sp->GetAsDictionary();
- ASSERT_TRUE(bool(dict_sp));
-
- object_sp = dict_sp->GetValueForKey("packet_speeds");
- ASSERT_TRUE(bool(object_sp));
- dict_sp = object_sp->GetAsDictionary();
- ASSERT_TRUE(bool(dict_sp));
-
- int num_packets;
- ASSERT_TRUE(dict_sp->GetValueForKeyAsInteger("num_packets", num_packets))
- << ss.GetString();
- ASSERT_EQ(10, num_packets);
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
- std::future<Status> result = std::async(std::launch::async, [&] {
- return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
- });
-
- HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
- EXPECT_TRUE(result.get().Success());
-
- result = std::async(std::launch::async, [&] {
- return client.SendSignalsToIgnore(std::vector<int32_t>());
- });
-
- HandlePacket(server, "QPassSignals:", "OK");
- EXPECT_TRUE(result.get().Success());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
- const lldb::addr_t addr = 0xa000;
- MemoryRegionInfo region_info;
- std::future<Status> result = std::async(std::launch::async, [&] {
- return client.GetMemoryRegionInfo(addr, region_info);
- });
-
- HandlePacket(server,
- "qMemoryRegionInfo:a000",
- "start:a000;size:2000;permissions:rx;name:2f666f6f2f6261722e736f;");
- if (XMLDocument::XMLEnabled()) {
- // In case we have XML support, this will also do a "qXfer:memory-map".
- // Preceeded by a query for supported extensions. Pretend we don't support
- // that.
- HandlePacket(server, testing::StartsWith("qSupported:"), "");
- }
- EXPECT_TRUE(result.get().Success());
- EXPECT_EQ(addr, region_info.GetRange().GetRangeBase());
- EXPECT_EQ(0x2000u, region_info.GetRange().GetByteSize());
- EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetReadable());
- EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
- EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
- EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
- EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged());
-
- result = std::async(std::launch::async, [&] {
- return client.GetMemoryRegionInfo(addr, region_info);
- });
-
- HandlePacket(server, "qMemoryRegionInfo:a000",
- "start:a000;size:2000;flags:;");
- EXPECT_TRUE(result.get().Success());
- EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged());
-
- result = std::async(std::launch::async, [&] {
- return client.GetMemoryRegionInfo(addr, region_info);
- });
-
- HandlePacket(server, "qMemoryRegionInfo:a000",
- "start:a000;size:2000;flags: mt zz mt ;");
- EXPECT_TRUE(result.get().Success());
- EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
- const lldb::addr_t addr = 0x4000;
- MemoryRegionInfo region_info;
- std::future<Status> result = std::async(std::launch::async, [&] {
- return client.GetMemoryRegionInfo(addr, region_info);
- });
-
- HandlePacket(server, "qMemoryRegionInfo:4000", "start:4000;size:0000;");
- if (XMLDocument::XMLEnabled()) {
- // In case we have XML support, this will also do a "qXfer:memory-map".
- // Preceeded by a query for supported extensions. Pretend we don't support
- // that.
- HandlePacket(server, testing::StartsWith("qSupported:"), "");
- }
- EXPECT_FALSE(result.get().Success());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedPacket) {
- TraceSupportedResponse trace_type;
- std::string error_message;
- auto callback = [&] {
- std::chrono::seconds timeout(10);
- if (llvm::Expected<TraceSupportedResponse> trace_type_or_err =
- client.SendTraceSupported(timeout)) {
- trace_type = *trace_type_or_err;
- error_message = "";
- return true;
- } else {
- trace_type = {};
- error_message = llvm::toString(trace_type_or_err.takeError());
- return false;
- }
- };
-
- // Success response
- {
- std::future<bool> result = std::async(std::launch::async, callback);
-
- HandlePacket(
- server, "jLLDBTraceSupported",
- R"({"name":"intel-pt","description":"Intel Processor Trace"}])");
-
- EXPECT_TRUE(result.get());
- ASSERT_STREQ(trace_type.name.c_str(), "intel-pt");
- ASSERT_STREQ(trace_type.description.c_str(), "Intel Processor Trace");
- }
-
- // Error response - wrong json
- {
- std::future<bool> result = std::async(std::launch::async, callback);
-
- HandlePacket(server, "jLLDBTraceSupported", R"({"type":"intel-pt"}])");
-
- EXPECT_FALSE(result.get());
- ASSERT_STREQ(error_message.c_str(), "missing value at TraceSupportedResponse.description");
- }
-
- // Error response
- {
- std::future<bool> result = std::async(std::launch::async, callback);
-
- HandlePacket(server, "jLLDBTraceSupported", "E23");
-
- EXPECT_FALSE(result.get());
- }
-
- // Error response with error message
- {
- std::future<bool> result = std::async(std::launch::async, callback);
-
- HandlePacket(server, "jLLDBTraceSupported",
- "E23;50726F63657373206E6F742072756E6E696E672E");
-
- EXPECT_FALSE(result.get());
- ASSERT_STREQ(error_message.c_str(), "Process not running.");
- }
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) {
- const auto &GetQOffsets = [&](llvm::StringRef response) {
- std::future<Optional<QOffsets>> result = std::async(
- std::launch::async, [&] { return client.GetQOffsets(); });
-
- HandlePacket(server, "qOffsets", response);
- return result.get();
- };
- EXPECT_EQ((QOffsets{false, {0x1234, 0x1234}}),
- GetQOffsets("Text=1234;Data=1234"));
- EXPECT_EQ((QOffsets{false, {0x1234, 0x1234, 0x1234}}),
- GetQOffsets("Text=1234;Data=1234;Bss=1234"));
- EXPECT_EQ((QOffsets{true, {0x1234}}), GetQOffsets("TextSeg=1234"));
- EXPECT_EQ((QOffsets{true, {0x1234, 0x2345}}),
- GetQOffsets("TextSeg=1234;DataSeg=2345"));
-
- EXPECT_EQ(llvm::None, GetQOffsets("E05"));
- EXPECT_EQ(llvm::None, GetQOffsets("Text=bogus"));
- EXPECT_EQ(llvm::None, GetQOffsets("Text=1234"));
- EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;"));
- EXPECT_EQ(llvm::None, GetQOffsets("Text=1234;Data=1234;Bss=1234;"));
- EXPECT_EQ(llvm::None, GetQOffsets("TEXTSEG=1234"));
- EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=0x1234"));
- EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=12345678123456789"));
-}
-
-static void
-check_qmemtags(TestClient &client, MockServer &server, size_t read_len,
- int32_t type, const char *packet, llvm::StringRef response,
- llvm::Optional<std::vector<uint8_t>> expected_tag_data) {
- const auto &ReadMemoryTags = [&]() {
- std::future<DataBufferSP> result = std::async(std::launch::async, [&] {
- return client.ReadMemoryTags(0xDEF0, read_len, type);
- });
-
- HandlePacket(server, packet, response);
- return result.get();
- };
-
- auto result = ReadMemoryTags();
- if (expected_tag_data) {
- ASSERT_TRUE(result);
- llvm::ArrayRef<uint8_t> expected(*expected_tag_data);
- llvm::ArrayRef<uint8_t> got = result->GetData();
- ASSERT_THAT(expected, testing::ContainerEq(got));
- } else {
- ASSERT_FALSE(result);
- }
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, ReadMemoryTags) {
- // Zero length reads are valid
- check_qmemtags(client, server, 0, 1, "qMemTags:def0,0:1", "m",
- std::vector<uint8_t>{});
-
- // Type can be negative. Put into the packet as the raw bytes
- // (as opposed to a literal -1)
- check_qmemtags(client, server, 0, -1, "qMemTags:def0,0:ffffffff", "m",
- std::vector<uint8_t>{});
- check_qmemtags(client, server, 0, std::numeric_limits<int32_t>::min(),
- "qMemTags:def0,0:80000000", "m", std::vector<uint8_t>{});
- check_qmemtags(client, server, 0, std::numeric_limits<int32_t>::max(),
- "qMemTags:def0,0:7fffffff", "m", std::vector<uint8_t>{});
-
- // The client layer does not check the length of the received data.
- // All we need is the "m" and for the decode to use all of the chars
- check_qmemtags(client, server, 32, 2, "qMemTags:def0,20:2", "m09",
- std::vector<uint8_t>{0x9});
-
- // Zero length response is fine as long as the "m" is present
- check_qmemtags(client, server, 0, 0x34, "qMemTags:def0,0:34", "m",
- std::vector<uint8_t>{});
-
- // Normal responses
- check_qmemtags(client, server, 16, 1, "qMemTags:def0,10:1", "m66",
- std::vector<uint8_t>{0x66});
- check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m0102",
- std::vector<uint8_t>{0x1, 0x2});
-
- // Empty response is an error
- check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "", llvm::None);
- // Usual error response
- check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "E01",
- llvm::None);
- // Leading m missing
- check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "01", llvm::None);
- // Anything other than m is an error
- check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "z01",
- llvm::None);
- // Decoding tag data doesn't use all the chars in the packet
- check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m09zz",
- llvm::None);
- // Data that is not hex bytes
- check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "mhello",
- llvm::None);
- // Data is not a complete hex char
- check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m9", llvm::None);
- // Data has a trailing hex char
- check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m01020",
- llvm::None);
-}
-
-static void check_Qmemtags(TestClient &client, MockServer &server,
- lldb::addr_t addr, size_t len, int32_t type,
- const std::vector<uint8_t> &tags, const char *packet,
- llvm::StringRef response, bool should_succeed) {
- const auto &WriteMemoryTags = [&]() {
- std::future<Status> result = std::async(std::launch::async, [&] {
- return client.WriteMemoryTags(addr, len, type, tags);
- });
-
- HandlePacket(server, packet, response);
- return result.get();
- };
-
- auto result = WriteMemoryTags();
- if (should_succeed)
- ASSERT_TRUE(result.Success());
- else
- ASSERT_TRUE(result.Fail());
-}
-
-TEST_F(GDBRemoteCommunicationClientTest, WriteMemoryTags) {
- check_Qmemtags(client, server, 0xABCD, 0x20, 1,
- std::vector<uint8_t>{0x12, 0x34}, "QMemTags:abcd,20:1:1234",
- "OK", true);
-
- // The GDB layer doesn't care that the number of tags !=
- // the length of the write.
- check_Qmemtags(client, server, 0x4321, 0x20, 9, std::vector<uint8_t>{},
- "QMemTags:4321,20:9:", "OK", true);
-
- check_Qmemtags(client, server, 0x8877, 0x123, 0x34,
- std::vector<uint8_t>{0x55, 0x66, 0x77},
- "QMemTags:8877,123:34:556677", "E01", false);
-
- // Type is a signed integer but is packed as its raw bytes,
- // instead of having a +/-.
- check_Qmemtags(client, server, 0x456789, 0, -1, std::vector<uint8_t>{0x99},
- "QMemTags:456789,0:ffffffff:99", "E03", false);
- check_Qmemtags(client, server, 0x456789, 0,
- std::numeric_limits<int32_t>::max(),
- std::vector<uint8_t>{0x99}, "QMemTags:456789,0:7fffffff:99",
- "E03", false);
- check_Qmemtags(client, server, 0x456789, 0,
- std::numeric_limits<int32_t>::min(),
- std::vector<uint8_t>{0x99}, "QMemTags:456789,0:80000000:99",
- "E03", false);
-}
+++ /dev/null
-//===-- GDBRemoteCommunicationServerTest.cpp ------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "GDBRemoteTestUtils.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
-#include "lldb/Utility/Connection.h"
-#include "lldb/Utility/UnimplementedError.h"
-
-namespace lldb_private {
-namespace process_gdb_remote {
-
-TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_ErrorNumber) {
- MockServerWithMockConnection server;
- server.SendErrorResponse(0x42);
-
- EXPECT_THAT(server.GetPackets(), testing::ElementsAre("$E42#ab"));
-}
-
-TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_Status) {
- MockServerWithMockConnection server;
- Status status;
-
- status.SetError(0x42, lldb::eErrorTypeGeneric);
- status.SetErrorString("Test error message");
- server.SendErrorResponse(status);
-
- EXPECT_THAT(
- server.GetPackets(),
- testing::ElementsAre("$E42;54657374206572726f72206d657373616765#ad"));
-}
-
-TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_UnimplementedError) {
- MockServerWithMockConnection server;
-
- auto error = llvm::make_error<UnimplementedError>();
- server.SendErrorResponse(std::move(error));
-
- EXPECT_THAT(server.GetPackets(), testing::ElementsAre("$#00"));
-}
-
-TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_StringError) {
- MockServerWithMockConnection server;
-
- auto error = llvm::createStringError(llvm::inconvertibleErrorCode(),
- "String error test");
- server.SendErrorResponse(std::move(error));
-
- EXPECT_THAT(
- server.GetPackets(),
- testing::ElementsAre("$Eff;537472696e67206572726f722074657374#b0"));
-}
-
-TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_ErrorList) {
- MockServerWithMockConnection server;
-
- auto error = llvm::joinErrors(llvm::make_error<UnimplementedError>(),
- llvm::make_error<UnimplementedError>());
-
- server.SendErrorResponse(std::move(error));
- // Make sure only one packet is sent even when there are multiple errors.
- EXPECT_EQ(server.GetPackets().size(), 1UL);
-}
-
-} // namespace process_gdb_remote
-} // namespace lldb_private
+++ /dev/null
-//===-- GDBRemoteCommunicationTest.cpp ------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include "GDBRemoteTestUtils.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private::process_gdb_remote;
-using namespace lldb_private;
-using namespace lldb;
-typedef GDBRemoteCommunication::PacketResult PacketResult;
-
-namespace {
-
-class TestClient : public GDBRemoteCommunication {
-public:
- TestClient()
- : GDBRemoteCommunication("test.client", "test.client.listener") {}
-
- PacketResult ReadPacket(StringExtractorGDBRemote &response) {
- return GDBRemoteCommunication::ReadPacket(response, std::chrono::seconds(1),
- /*sync_on_timeout*/ false);
- }
-};
-
-class GDBRemoteCommunicationTest : public GDBRemoteTest {
-public:
- void SetUp() override {
- ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server),
- llvm::Succeeded());
- }
-
-protected:
- TestClient client;
- MockServer server;
-
- bool Write(llvm::StringRef packet) {
- ConnectionStatus status;
- return server.Write(packet.data(), packet.size(), status, nullptr) ==
- packet.size();
- }
-};
-} // end anonymous namespace
-
-TEST_F(GDBRemoteCommunicationTest, ReadPacket_checksum) {
- struct TestCase {
- llvm::StringLiteral Packet;
- llvm::StringLiteral Payload;
- };
- static constexpr TestCase Tests[] = {
- {{"$#00"}, {""}},
- {{"$foobar#79"}, {"foobar"}},
- {{"$}}#fa"}, {"]"}},
- {{"$x*%#c7"}, {"xxxxxxxxx"}},
- };
- for (const auto &Test : Tests) {
- SCOPED_TRACE(Test.Packet + " -> " + Test.Payload);
- StringExtractorGDBRemote response;
- ASSERT_TRUE(Write(Test.Packet));
- ASSERT_EQ(PacketResult::Success, client.ReadPacket(response));
- ASSERT_EQ(Test.Payload, response.GetStringRef());
- ASSERT_EQ(PacketResult::Success, server.GetAck());
- }
-}
+++ /dev/null
-//===-- GDBRemoteTestUtils.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "GDBRemoteTestUtils.h"
-#include "lldb/Host/Socket.h"
-#include "llvm/Testing/Support/Error.h"
-
-namespace lldb_private {
-namespace process_gdb_remote {
-
-void GDBRemoteTest::SetUpTestCase() {
- ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded());
-}
-
-void GDBRemoteTest::TearDownTestCase() { Socket::Terminate(); }
-
-} // namespace process_gdb_remote
-} // namespace lldb_private
+++ /dev/null
-//===-- GDBRemoteTestUtils.h ------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
-#define LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
-#include "lldb/Utility/Connection.h"
-
-namespace lldb_private {
-namespace process_gdb_remote {
-
-class GDBRemoteTest : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-};
-
-class MockConnection : public lldb_private::Connection {
-public:
- MockConnection(std::vector<std::string> &packets) { m_packets = &packets; };
-
- MOCK_METHOD2(Connect,
- lldb::ConnectionStatus(llvm::StringRef url, Status *error_ptr));
- MOCK_METHOD5(Read, size_t(void *dst, size_t dst_len,
- const Timeout<std::micro> &timeout,
- lldb::ConnectionStatus &status, Status *error_ptr));
- MOCK_METHOD0(GetURI, std::string());
- MOCK_METHOD0(InterruptRead, bool());
-
- lldb::ConnectionStatus Disconnect(Status *error_ptr) {
- return lldb::eConnectionStatusSuccess;
- };
-
- bool IsConnected() const { return true; };
- size_t Write(const void *dst, size_t dst_len, lldb::ConnectionStatus &status,
- Status *error_ptr) {
- m_packets->emplace_back(static_cast<const char *>(dst), dst_len);
- return dst_len;
- };
-
- lldb::IOObjectSP GetReadObject() { return lldb::IOObjectSP(); }
-
- std::vector<std::string> *m_packets;
-};
-
-class MockServer : public GDBRemoteCommunicationServer {
-public:
- MockServer()
- : GDBRemoteCommunicationServer("mock-server", "mock-server.listener") {
- m_send_acks = false;
- m_send_error_strings = true;
- }
-
- PacketResult SendPacket(llvm::StringRef payload) {
- return GDBRemoteCommunicationServer::SendPacketNoLock(payload);
- }
-
- PacketResult GetPacket(StringExtractorGDBRemote &response) {
- const bool sync_on_timeout = false;
- return WaitForPacketNoLock(response, std::chrono::seconds(1),
- sync_on_timeout);
- }
-
- using GDBRemoteCommunicationServer::SendErrorResponse;
- using GDBRemoteCommunicationServer::SendOKResponse;
- using GDBRemoteCommunicationServer::SendUnimplementedResponse;
-};
-
-class MockServerWithMockConnection : public MockServer {
-public:
- MockServerWithMockConnection() : MockServer() {
- SetConnection(std::make_unique<MockConnection>(m_packets));
- }
-
- llvm::ArrayRef<std::string> GetPackets() { return m_packets; };
-
- std::vector<std::string> m_packets;
-};
-
-} // namespace process_gdb_remote
-} // namespace lldb_private
-
-#endif // LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
+++ /dev/null
-//===-- PortMapTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h"
-
-using namespace lldb_private::process_gdb_remote;
-
-TEST(PortMapTest, Constructors) {
- // Default construct to empty map
- GDBRemoteCommunicationServerPlatform::PortMap p1;
- ASSERT_TRUE(p1.empty());
-
- // Empty means no restrictions, return 0 and and bind to get a port
- llvm::Expected<uint16_t> available_port = p1.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(0));
-
- // Adding any port makes it not empty
- p1.AllowPort(1);
- ASSERT_FALSE(p1.empty());
-
- // So we will return the added port this time
- available_port = p1.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(1));
-
- // Construct from a range of ports
- GDBRemoteCommunicationServerPlatform::PortMap p2(1, 4);
- ASSERT_FALSE(p2.empty());
-
- // Use up all the ports
- for (uint16_t expected = 1; expected < 4; ++expected) {
- available_port = p2.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(expected));
- p2.AssociatePortWithProcess(*available_port, 1);
- }
-
- // Now we fail since we're not an empty port map but all ports are used
- available_port = p2.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::Failed());
-}
-
-TEST(PortMapTest, FreePort) {
- GDBRemoteCommunicationServerPlatform::PortMap p(1, 4);
- // Use up all the ports
- for (uint16_t port = 1; port < 4; ++port) {
- p.AssociatePortWithProcess(port, 1);
- }
-
- llvm::Expected<uint16_t> available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::Failed());
-
- // Can't free a port that isn't in the map
- ASSERT_FALSE(p.FreePort(0));
- ASSERT_FALSE(p.FreePort(4));
-
- // After freeing a port it becomes available
- ASSERT_TRUE(p.FreePort(2));
- available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(2));
-}
-
-TEST(PortMapTest, FreePortForProcess) {
- GDBRemoteCommunicationServerPlatform::PortMap p;
- p.AllowPort(1);
- p.AllowPort(2);
- ASSERT_TRUE(p.AssociatePortWithProcess(1, 11));
- ASSERT_TRUE(p.AssociatePortWithProcess(2, 22));
-
- // All ports have been used
- llvm::Expected<uint16_t> available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::Failed());
-
- // Can't free a port for a process that doesn't have any
- ASSERT_FALSE(p.FreePortForProcess(33));
-
- // You can move a used port to a new pid
- ASSERT_TRUE(p.AssociatePortWithProcess(1, 99));
-
- ASSERT_TRUE(p.FreePortForProcess(22));
- available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::Succeeded());
- ASSERT_EQ(2, *available_port);
-
- // proces 22 no longer has a port
- ASSERT_FALSE(p.FreePortForProcess(22));
-}
-
-TEST(PortMapTest, AllowPort) {
- GDBRemoteCommunicationServerPlatform::PortMap p;
-
- // Allow port 1 and tie it to process 11
- p.AllowPort(1);
- ASSERT_TRUE(p.AssociatePortWithProcess(1, 11));
-
- // Allowing it a second time shouldn't change existing mapping
- p.AllowPort(1);
- llvm::Expected<uint16_t> available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::Failed());
-
- // A new port is marked as free when allowed
- p.AllowPort(2);
- available_port = p.GetNextAvailablePort();
- ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(2));
-
- // 11 should still be tied to port 1
- ASSERT_TRUE(p.FreePortForProcess(11));
-}
+++ /dev/null
-add_lldb_unittest(LLDBMinidumpTests
- MinidumpParserTest.cpp
- RegisterContextMinidumpTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbTarget
- lldbPluginProcessUtility
- lldbPluginProcessMinidump
- lldbUtilityHelpers
- LLVMTestingSupport
- LINK_COMPONENTS
- ObjectYAML
- Support
- )
-
-set(test_inputs
- fizzbuzz_no_heap.dmp
- fizzbuzz_wow64.dmp
- linux-x86_64.dmp
- regions-memlist64.dmp
- )
-
-add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")
+++ /dev/null
-// Example source from breakpad's linux tutorial
-// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "client/linux/handler/exception_handler.h"
-
-static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
- void *context, bool succeeded) {
- printf("Dump path: %s\n", descriptor.path());
- return succeeded;
-}
-
-void crash() {
- volatile int *a = (int *)(NULL);
- *a = 1;
-}
-
-int main(int argc, char *argv[]) {
- google_breakpad::MinidumpDescriptor descriptor("/tmp");
- google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL,
- true, -1);
- printf("pid: %d\n", getpid());
- crash();
- return 0;
-}
+++ /dev/null
-//===-- MinidumpTypesTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Process/minidump/MinidumpParser.h"
-#include "Plugins/Process/minidump/MinidumpTypes.h"
-#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
-#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/FileSpec.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ObjectYAML/yaml2obj.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/YAMLTraits.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-// C includes
-
-// C++ includes
-#include <memory>
-
-using namespace lldb_private;
-using namespace minidump;
-
-class MinidumpParserTest : public testing::Test {
-public:
- SubsystemRAII<FileSystem> subsystems;
-
- void SetUpData(const char *minidump_filename) {
- std::string filename = GetInputFilePath(minidump_filename);
- auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0);
- ASSERT_NE(BufferPtr, nullptr);
- llvm::Expected<MinidumpParser> expected_parser =
- MinidumpParser::Create(BufferPtr);
- ASSERT_THAT_EXPECTED(expected_parser, llvm::Succeeded());
- parser = std::move(*expected_parser);
- ASSERT_GT(parser->GetData().size(), 0UL);
- }
-
- llvm::Error SetUpFromYaml(llvm::StringRef yaml) {
- std::string data;
- llvm::raw_string_ostream os(data);
- llvm::yaml::Input YIn(yaml);
- if (!llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg) {}))
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "convertYAML() failed");
-
- os.flush();
- auto data_buffer_sp =
- std::make_shared<DataBufferHeap>(data.data(), data.size());
- auto expected_parser = MinidumpParser::Create(std::move(data_buffer_sp));
- if (!expected_parser)
- return expected_parser.takeError();
- parser = std::move(*expected_parser);
- return llvm::Error::success();
- }
-
- llvm::Optional<MinidumpParser> parser;
-};
-
-TEST_F(MinidumpParserTest, InvalidMinidump) {
- std::string duplicate_streams;
- llvm::raw_string_ostream os(duplicate_streams);
- llvm::yaml::Input YIn(R"(
---- !minidump
-Streams:
- - Type: LinuxAuxv
- Content: DEADBEEFBAADF00D
- - Type: LinuxAuxv
- Content: DEADBEEFBAADF00D
- )");
-
- ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){}));
- os.flush();
- auto data_buffer_sp = std::make_shared<DataBufferHeap>(
- duplicate_streams.data(), duplicate_streams.size());
- ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());
-}
-
-TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ThreadList
- Threads:
- - Thread Id: 0x00003E81
- Stack:
- Start of Memory Range: 0x00007FFCEB34A000
- Content: C84D04BCE97F00
- Context: 00000000000000
-...
-)"),
- llvm::Succeeded());
- llvm::ArrayRef<minidump::Thread> thread_list;
-
- thread_list = parser->GetThreads();
- ASSERT_EQ(1UL, thread_list.size());
-
- const minidump::Thread &thread = thread_list[0];
-
- EXPECT_EQ(0x3e81u, thread.ThreadId);
-
- llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
- EXPECT_EQ(7u, context.size());
-}
-
-TEST_F(MinidumpParserTest, GetArchitecture) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: SystemInfo
- Processor Arch: AMD64
- Processor Level: 6
- Processor Revision: 16130
- Number of Processors: 1
- Platform ID: Linux
- CPU:
- Vendor ID: GenuineIntel
- Version Info: 0x00000000
- Feature Info: 0x00000000
-...
-)"),
- llvm::Succeeded());
- ASSERT_EQ(llvm::Triple::ArchType::x86_64,
- parser->GetArchitecture().GetMachine());
- ASSERT_EQ(llvm::Triple::OSType::Linux,
- parser->GetArchitecture().GetTriple().getOS());
-}
-
-TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) {
- // Test that GetMiscInfo returns nullptr when the minidump does not contain
- // this stream.
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
-...
-)"),
- llvm::Succeeded());
- EXPECT_EQ(nullptr, parser->GetMiscInfo());
-}
-
-TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: SystemInfo
- Processor Arch: AMD64
- Processor Level: 6
- Processor Revision: 16130
- Number of Processors: 1
- Platform ID: Linux
- CSD Version: 'Linux 3.13.0-91-generic'
- CPU:
- Vendor ID: GenuineIntel
- Version Info: 0x00000000
- Feature Info: 0x00000000
- - Type: LinuxProcStatus
- Text: |
- Name: a.out
- State: t (tracing stop)
- Tgid: 16001
- Ngid: 0
- Pid: 16001
- PPid: 13243
- TracerPid: 16002
- Uid: 404696 404696 404696 404696
- Gid: 5762 5762 5762 5762
-...
-)"),
- llvm::Succeeded());
- llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
- ASSERT_TRUE(proc_status.hasValue());
- lldb::pid_t pid = proc_status->GetPid();
- ASSERT_EQ(16001UL, pid);
-}
-
-TEST_F(MinidumpParserTest, GetPid) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: SystemInfo
- Processor Arch: AMD64
- Processor Level: 6
- Processor Revision: 16130
- Number of Processors: 1
- Platform ID: Linux
- CSD Version: 'Linux 3.13.0-91-generic'
- CPU:
- Vendor ID: GenuineIntel
- Version Info: 0x00000000
- Feature Info: 0x00000000
- - Type: LinuxProcStatus
- Text: |
- Name: a.out
- State: t (tracing stop)
- Tgid: 16001
- Ngid: 0
- Pid: 16001
- PPid: 13243
- TracerPid: 16002
- Uid: 404696 404696 404696 404696
- Gid: 5762 5762 5762 5762
-...
-)"),
- llvm::Succeeded());
- llvm::Optional<lldb::pid_t> pid = parser->GetPid();
- ASSERT_TRUE(pid.hasValue());
- ASSERT_EQ(16001UL, pid.getValue());
-}
-
-TEST_F(MinidumpParserTest, GetFilteredModuleList) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x0000000000400000
- Size of Image: 0x00001000
- Module Name: '/tmp/test/linux-x86_64_not_crashed'
- CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
- - Base of Image: 0x0000000000600000
- Size of Image: 0x00002000
- Module Name: '/tmp/test/linux-x86_64_not_crashed'
- CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
-...
-)"),
- llvm::Succeeded());
- llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList();
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- EXPECT_EQ(2u, modules.size());
- ASSERT_EQ(1u, filtered_modules.size());
- const minidump::Module &M = *filtered_modules[0];
- EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA),
- llvm::HasValue("/tmp/test/linux-x86_64_not_crashed"));
-}
-
-TEST_F(MinidumpParserTest, GetExceptionStream) {
- SetUpData("linux-x86_64.dmp");
- const llvm::minidump::ExceptionStream *exception_stream =
- parser->GetExceptionStream();
- ASSERT_NE(nullptr, exception_stream);
- ASSERT_EQ(11UL, exception_stream->ExceptionRecord.ExceptionCode);
-}
-
-void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start,
- const uint64_t range_size) {
- llvm::Optional<minidump::Range> range = parser.FindMemoryRange(range_start);
- ASSERT_TRUE(range.hasValue()) << "There is no range containing this address";
- EXPECT_EQ(range_start, range->start);
- EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
-}
-
-TEST_F(MinidumpParserTest, FindMemoryRange) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: MemoryList
- Memory Ranges:
- - Start of Memory Range: 0x00007FFCEB34A000
- Content: C84D04BCE9
- - Start of Memory Range: 0x0000000000401D46
- Content: 5421
-...
-)"),
- llvm::Succeeded());
- EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x00));
- EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x2a));
- EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}),
- parser->FindMemoryRange(0x401d46));
- EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x401d46 + 2));
-
- EXPECT_EQ(
- (minidump::Range{0x7ffceb34a000,
- llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}),
- parser->FindMemoryRange(0x7ffceb34a000 + 2));
- EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x7ffceb34a000 + 5));
-}
-
-TEST_F(MinidumpParserTest, GetMemory) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: MemoryList
- Memory Ranges:
- - Start of Memory Range: 0x00007FFCEB34A000
- Content: C84D04BCE9
- - Start of Memory Range: 0x0000000000401D46
- Content: 5421
-...
-)"),
- llvm::Succeeded());
-
- EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1));
- EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}),
- parser->GetMemory(0x401d46, 4));
-
- EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}),
- parser->GetMemory(0x7ffceb34a000, 5));
- EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}),
- parser->GetMemory(0x7ffceb34a000, 3));
-
- EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
-}
-
-TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
- SetUpData("fizzbuzz_wow64.dmp");
-
- // There are a lot of ranges in the file, just testing with some of them
- EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
- EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
- check_mem_range_exists(*parser, 0x10000, 65536); // first range
- check_mem_range_exists(*parser, 0x40000, 4096);
- EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue());
- check_mem_range_exists(*parser, 0x77c12000, 8192);
- check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range
- EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
-}
-
-constexpr auto yes = MemoryRegionInfo::eYes;
-constexpr auto no = MemoryRegionInfo::eNo;
-constexpr auto unknown = MemoryRegionInfo::eDontKnow;
-
-TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: MemoryInfoList
- Memory Ranges:
- - Base Address: 0x0000000000000000
- Allocation Protect: [ ]
- Region Size: 0x0000000000010000
- State: [ MEM_FREE ]
- Protect: [ PAGE_NO_ACCESS ]
- Type: [ ]
- - Base Address: 0x0000000000010000
- Allocation Protect: [ PAGE_READ_WRITE ]
- Region Size: 0x0000000000021000
- State: [ MEM_COMMIT ]
- Type: [ MEM_MAPPED ]
- - Base Address: 0x0000000000040000
- Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]
- Region Size: 0x0000000000001000
- State: [ MEM_COMMIT ]
- Protect: [ PAGE_READ_ONLY ]
- Type: [ MEM_IMAGE ]
- - Base Address: 0x000000007FFE0000
- Allocation Protect: [ PAGE_READ_ONLY ]
- Region Size: 0x0000000000001000
- State: [ MEM_COMMIT ]
- Type: [ MEM_PRIVATE ]
- - Base Address: 0x000000007FFE1000
- Allocation Base: 0x000000007FFE0000
- Allocation Protect: [ PAGE_READ_ONLY ]
- Region Size: 0x000000000000F000
- State: [ MEM_RESERVE ]
- Protect: [ PAGE_NO_ACCESS ]
- Type: [ MEM_PRIVATE ]
-...
-)"),
- llvm::Succeeded());
-
- EXPECT_THAT(
- parser->BuildMemoryRegions(),
- testing::Pair(testing::ElementsAre(
- MemoryRegionInfo({0x0, 0x10000}, no, no, no, no,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes,
- ConstString(), unknown, 0, unknown)),
- true));
-}
-
-TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: MemoryList
- Memory Ranges:
- - Start of Memory Range: 0x0000000000001000
- Content: '31313131313131313131313131313131'
- - Start of Memory Range: 0x0000000000002000
- Content: '3333333333333333333333333333333333333333333333333333333333333333'
-...
-)"),
- llvm::Succeeded());
-
- // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
- // we don't have a MemoryInfoListStream.
-
- EXPECT_THAT(
- parser->BuildMemoryRegions(),
- testing::Pair(
- testing::ElementsAre(
- MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
- ConstString(), unknown, 0, unknown)),
- false));
-}
-
-TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
- SetUpData("regions-memlist64.dmp");
-
- // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
- // we don't have a MemoryInfoListStream.
- EXPECT_THAT(
- parser->BuildMemoryRegions(),
- testing::Pair(
- testing::ElementsAre(
- MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
- ConstString(), unknown, 0, unknown)),
- false));
-}
-
-TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: LinuxMaps
- Text: |
- 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
- 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
- 400dc000-400dd000 rw-p 00000000 00:00 0
- 400ec000-400ed000 r--p 00000000 00:00 0
- 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker
- 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so
-
-...
-)"),
- llvm::Succeeded());
- // Test we can get memory regions from the linux /proc/<pid>/maps stream when
- // we don't have a MemoryInfoListStream.
- ConstString app_process("/system/bin/app_process");
- ConstString linker("/system/bin/linker");
- ConstString liblog("/system/lib/liblog.so");
- EXPECT_THAT(parser->BuildMemoryRegions(),
- testing::Pair(
- testing::ElementsAre(
- MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, yes,
- app_process, unknown, 0, unknown),
- MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes,
- app_process, unknown, 0, unknown),
- MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes,
- ConstString(), unknown, 0, unknown),
- MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes,
- linker, unknown, 0, unknown),
- MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes,
- liblog, unknown, 0, unknown)),
- true));
-}
-
-TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: LinuxMaps
- Text: |
- 400d9000-400db000 r?xp 00000000 b3:04 227
- 400fc000-400fd000 rwxp 00001000 b3:04 1096
-...
-)"),
- llvm::Succeeded());
- // Test that when a /proc/maps region fails to parse
- // we handle the error and continue with the rest.
- EXPECT_THAT(parser->BuildMemoryRegions(),
- testing::Pair(testing::ElementsAre(MemoryRegionInfo(
- {0x400fc000, 0x1000}, yes, yes, yes, yes,
- ConstString(nullptr), unknown, 0, unknown)),
- true));
-}
-
-// Windows Minidump tests
-TEST_F(MinidumpParserTest, GetArchitectureWindows) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: SystemInfo
- Processor Arch: X86
- Processor Level: 6
- Processor Revision: 15876
- Number of Processors: 32
- Product type: 1
- Major Version: 6
- Minor Version: 1
- Build Number: 7601
- Platform ID: Win32NT
- CSD Version: Service Pack 1
- Suite Mask: 0x0100
- CPU:
- Vendor ID: GenuineIntel
- Version Info: 0x000306E4
- Feature Info: 0xBFEBFBFF
- AMD Extended Features: 0x771EEC80
-...
-)"),
- llvm::Succeeded());
- ASSERT_EQ(llvm::Triple::ArchType::x86,
- parser->GetArchitecture().GetMachine());
- ASSERT_EQ(llvm::Triple::OSType::Win32,
- parser->GetArchitecture().GetTriple().getOS());
-}
-
-TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) {
- // Test that GetLinuxProcStatus returns nullptr when the minidump does not
- // contain this stream.
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
-...
-)"),
- llvm::Succeeded());
- EXPECT_EQ(llvm::None, parser->GetLinuxProcStatus());
-}
-
-TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
- SetUpData("fizzbuzz_no_heap.dmp");
- const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
- ASSERT_NE(nullptr, misc_info);
- llvm::Optional<lldb::pid_t> pid = misc_info->GetPid();
- ASSERT_TRUE(pid.hasValue());
- ASSERT_EQ(4440UL, pid.getValue());
-}
-
-TEST_F(MinidumpParserTest, GetPidWindows) {
- SetUpData("fizzbuzz_no_heap.dmp");
- llvm::Optional<lldb::pid_t> pid = parser->GetPid();
- ASSERT_TRUE(pid.hasValue());
- ASSERT_EQ(4440UL, pid.getValue());
-}
-
-// wow64
-TEST_F(MinidumpParserTest, GetPidWow64) {
- SetUpData("fizzbuzz_wow64.dmp");
- llvm::Optional<lldb::pid_t> pid = parser->GetPid();
- ASSERT_TRUE(pid.hasValue());
- ASSERT_EQ(7836UL, pid.getValue());
-}
-
-// Register tests
-#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
-#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
-
-TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ThreadList
- Threads:
- - Thread Id: 0x00026804
- Stack:
- Start of Memory Range: 0x00000000FF9DD000
- Content: 68D39DFF
- Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-)"),
- llvm::Succeeded());
-
- llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
- const minidump::Thread &thread = thread_list[0];
- llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
- const MinidumpContext_x86_32 *context;
- EXPECT_TRUE(consumeObject(registers, context).Success());
-
- EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
- MinidumpContext_x86_32_Flags::x86_32_Flag |
- MinidumpContext_x86_32_Flags::Full |
- MinidumpContext_x86_32_Flags::FloatingPoint);
-
- EXPECT_EQ(0x00000000u, context->eax);
- EXPECT_EQ(0xf7778000u, context->ebx);
- EXPECT_EQ(0x00000001u, context->ecx);
- EXPECT_EQ(0xff9dd4a3u, context->edx);
- EXPECT_EQ(0x080482a8u, context->edi);
- EXPECT_EQ(0xff9dd55cu, context->esi);
- EXPECT_EQ(0xff9dd53cu, context->ebp);
- EXPECT_EQ(0xff9dd52cu, context->esp);
- EXPECT_EQ(0x080482a0u, context->eip);
- EXPECT_EQ(0x00010282u, context->eflags);
- EXPECT_EQ(0x0023u, context->cs);
- EXPECT_EQ(0x0000u, context->fs);
- EXPECT_EQ(0x0063u, context->gs);
- EXPECT_EQ(0x002bu, context->ss);
- EXPECT_EQ(0x002bu, context->ds);
- EXPECT_EQ(0x002bu, context->es);
-}
-
-TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ThreadList
- Threads:
- - Thread Id: 0x00003E81
- Stack:
- Start of Memory Range: 0x00007FFCEB34A000
- Content: C84D04BCE97F00
- Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-...
-)"),
- llvm::Succeeded());
- llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
- const minidump::Thread &thread = thread_list[0];
- llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
- const MinidumpContext_x86_64 *context;
- EXPECT_TRUE(consumeObject(registers, context).Success());
-
- EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),
- MinidumpContext_x86_64_Flags::x86_64_Flag |
- MinidumpContext_x86_64_Flags::Control |
- MinidumpContext_x86_64_Flags::FloatingPoint |
- MinidumpContext_x86_64_Flags::Integer);
- EXPECT_EQ(0x0000000000000000u, context->rax);
- EXPECT_EQ(0x0000000000000000u, context->rbx);
- EXPECT_EQ(0x0000000000000010u, context->rcx);
- EXPECT_EQ(0x0000000000000000u, context->rdx);
- EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);
- EXPECT_EQ(0x0000000000000000u, context->rsi);
- EXPECT_EQ(0x00007ffceb34a210u, context->rbp);
- EXPECT_EQ(0x00007ffceb34a210u, context->rsp);
- EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);
- EXPECT_EQ(0x0000000000000000u, context->r9);
- EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);
- EXPECT_EQ(0x0000000000000246u, context->r11);
- EXPECT_EQ(0x0000000000401c92u, context->r12);
- EXPECT_EQ(0x00007ffceb34a430u, context->r13);
- EXPECT_EQ(0x0000000000000000u, context->r14);
- EXPECT_EQ(0x0000000000000000u, context->r15);
- EXPECT_EQ(0x0000000000401dc6u, context->rip);
- EXPECT_EQ(0x00010206u, context->eflags);
- EXPECT_EQ(0x0033u, context->cs);
- EXPECT_EQ(0x0000u, context->ss);
-}
-
-TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {
- SetUpData("fizzbuzz_wow64.dmp");
- llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
- const minidump::Thread &thread = thread_list[0];
- llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));
- const MinidumpContext_x86_32 *context;
- EXPECT_TRUE(consumeObject(registers, context).Success());
-
- EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
- MinidumpContext_x86_32_Flags::x86_32_Flag |
- MinidumpContext_x86_32_Flags::Full |
- MinidumpContext_x86_32_Flags::FloatingPoint |
- MinidumpContext_x86_32_Flags::ExtendedRegisters);
-
- EXPECT_EQ(0x00000000u, context->eax);
- EXPECT_EQ(0x0037f608u, context->ebx);
- EXPECT_EQ(0x00e61578u, context->ecx);
- EXPECT_EQ(0x00000008u, context->edx);
- EXPECT_EQ(0x00000000u, context->edi);
- EXPECT_EQ(0x00000002u, context->esi);
- EXPECT_EQ(0x0037f654u, context->ebp);
- EXPECT_EQ(0x0037f5b8u, context->esp);
- EXPECT_EQ(0x77ce01fdu, context->eip);
- EXPECT_EQ(0x00000246u, context->eflags);
- EXPECT_EQ(0x0023u, context->cs);
- EXPECT_EQ(0x0053u, context->fs);
- EXPECT_EQ(0x002bu, context->gs);
- EXPECT_EQ(0x002bu, context->ss);
- EXPECT_EQ(0x002bu, context->ds);
- EXPECT_EQ(0x002bu, context->es);
-}
-
-TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x0000000000002000
- Size of Image: 0x00001000
- Module Name: '/tmp/a'
- CodeView Record: ''
- - Base of Image: 0x0000000000001000
- Size of Image: 0x00001000
- Module Name: '/tmp/a'
- CodeView Record: ''
-...
-)"),
- llvm::Succeeded());
- // If we have a module mentioned twice in the module list, the filtered
- // module list should contain the instance with the lowest BaseOfImage.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(1u, filtered_modules.size());
- EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage);
-}
-
-TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x400d0000
- Size of Image: 0x00002000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Base of Image: 0x400d3000
- Size of Image: 0x00001000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Type: LinuxMaps
- Text: |
- 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
- 400d2000-400d3000 rw-p 00000000 00:00 0
- 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
- 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
-...
-)"),
- llvm::Succeeded());
- // If we have a module mentioned twice in the module list, and we have full
- // linux maps for all of the memory regions, make sure we pick the one that
- // has a consecutive region with a matching path that has executable
- // permissions. If clients open an object file with mmap, breakpad can create
- // multiple mappings for a library errnoneously and the lowest address isn't
- // always the right address. In this case we check the consective memory
- // regions whose path matches starting at the base of image address and make
- // sure one of the regions is executable and prefer that one.
- //
- // This test will make sure that if the executable is second in the module
- // list, that it will become the selected module in the filtered list.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(1u, filtered_modules.size());
- EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
-}
-
-TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x400d0000
- Size of Image: 0x00002000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Base of Image: 0x400d3000
- Size of Image: 0x00001000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Type: LinuxMaps
- Text: |
- 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
- 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
- 400d2000-400d3000 rw-p 00000000 00:00 0
- 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so
-...
-)"),
- llvm::Succeeded());
- // If we have a module mentioned twice in the module list, and we have full
- // linux maps for all of the memory regions, make sure we pick the one that
- // has a consecutive region with a matching path that has executable
- // permissions. If clients open an object file with mmap, breakpad can create
- // multiple mappings for a library errnoneously and the lowest address isn't
- // always the right address. In this case we check the consective memory
- // regions whose path matches starting at the base of image address and make
- // sure one of the regions is executable and prefer that one.
- //
- // This test will make sure that if the executable is first in the module
- // list, that it will remain the correctly selected module in the filtered
- // list.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(1u, filtered_modules.size());
- EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage);
-}
-
-TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x400d3000
- Size of Image: 0x00002000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Base of Image: 0x400d0000
- Size of Image: 0x00001000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Type: LinuxMaps
- Text: |
- 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
- 400d2000-400d3000 rw-p 00000000 00:00 0
- 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
- 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
-...
-)"),
- llvm::Succeeded());
- // If we have a module mentioned twice in the module list, and we have full
- // linux maps for all of the memory regions, make sure we pick the one that
- // has a consecutive region with a matching path that has executable
- // permissions. If clients open an object file with mmap, breakpad can create
- // multiple mappings for a library errnoneously and the lowest address isn't
- // always the right address. In this case we check the consective memory
- // regions whose path matches starting at the base of image address and make
- // sure one of the regions is executable and prefer that one.
- //
- // This test will make sure that if the executable is first in the module
- // list, that it will remain the correctly selected module in the filtered
- // list, even if the non-executable module was loaded at a lower base address.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(1u, filtered_modules.size());
- EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
-}
-
-TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x400d0000
- Size of Image: 0x00002000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Base of Image: 0x400d5000
- Size of Image: 0x00001000
- Module Name: '/usr/lib/libc.so'
- CodeView Record: ''
- - Type: LinuxMaps
- Text: |
- 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so
- 400d3000-400d5000 rw-p 00000000 00:00 0
- 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so
- 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
- 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
-...
-)"),
- llvm::Succeeded());
- // If we have a module mentioned twice in the module list, and we have full
- // linux maps for all of the memory regions, make sure we pick the one that
- // has a consecutive region with a matching path that has executable
- // permissions. If clients open an object file with mmap, breakpad can create
- // multiple mappings for a library errnoneously and the lowest address isn't
- // always the right address. In this case we check the consective memory
- // regions whose path matches starting at the base of image address and make
- // sure one of the regions is executable and prefer that one.
- //
- // This test will make sure if binaries are compiled with "-z separate-code",
- // where the first region for a binary won't be marked as executable, that
- // it gets selected by detecting the second consecutive mapping at 0x400d7000
- // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(1u, filtered_modules.size());
- EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage);
-}
-
-TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
- ASSERT_THAT_ERROR(SetUpFromYaml(R"(
---- !minidump
-Streams:
- - Type: ModuleList
- Modules:
- - Base of Image: 0x0000000000002000
- Size of Image: 0x00001000
- Module Name: '/tmp/a'
- CodeView Record: ''
- - Base of Image: 0x0000000000001000
- Size of Image: 0x00001000
- Module Name: '/tmp/b'
- CodeView Record: ''
-...
-)"),
- llvm::Succeeded());
- // Test module filtering does not affect the overall module order. Previous
- // versions of the MinidumpParser::GetFilteredModuleList() function would sort
- // all images by address and modify the order of the modules.
- std::vector<const minidump::Module *> filtered_modules =
- parser->GetFilteredModuleList();
- ASSERT_EQ(2u, filtered_modules.size());
- EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage);
- EXPECT_THAT_EXPECTED(
- parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA),
- llvm::HasValue("/tmp/a"));
- EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage);
- EXPECT_THAT_EXPECTED(
- parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),
- llvm::HasValue("/tmp/b"));
-}
+++ /dev/null
-//===-- RegisterContextMinidumpTest.cpp -----------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
-#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
-#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
-#include "Plugins/Process/minidump/RegisterContextMinidump_ARM.h"
-#include "lldb/Utility/DataBuffer.h"
-#include "llvm/ADT/StringRef.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::minidump;
-
-static uint32_t reg32(const DataBuffer &Buf, const RegisterInfo &Info) {
- return *reinterpret_cast<const uint32_t *>(Buf.GetBytes() + Info.byte_offset);
-}
-
-static uint64_t reg64(const DataBuffer &Buf, const RegisterInfo &Info) {
- return *reinterpret_cast<const uint64_t *>(Buf.GetBytes() + Info.byte_offset);
-}
-
-TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_32) {
- MinidumpContext_x86_32 Context;
- Context.context_flags =
- static_cast<uint32_t>(MinidumpContext_x86_32_Flags::x86_32_Flag |
- MinidumpContext_x86_32_Flags::Control |
- MinidumpContext_x86_32_Flags::Segments |
- MinidumpContext_x86_32_Flags::Integer);
- Context.eax = 0x00010203;
- Context.ebx = 0x04050607;
- Context.ecx = 0x08090a0b;
- Context.edx = 0x0c0d0e0f;
- Context.edi = 0x10111213;
- Context.esi = 0x14151617;
- Context.ebp = 0x18191a1b;
- Context.esp = 0x1c1d1e1f;
- Context.eip = 0x20212223;
- Context.eflags = 0x24252627;
- Context.cs = 0x2829;
- Context.fs = 0x2a2b;
- Context.gs = 0x2c2d;
- Context.ss = 0x2e2f;
- Context.ds = 0x3031;
- Context.es = 0x3233;
- llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
- sizeof(Context));
-
- ArchSpec arch("i386-pc-linux");
- auto RegInterface = std::make_unique<RegisterContextLinux_i386>(arch);
- lldb::DataBufferSP Buf =
- ConvertMinidumpContext_x86_32(ContextRef, RegInterface.get());
- ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
-
- const RegisterInfo *Info = RegInterface->GetRegisterInfo();
- ASSERT_NE(nullptr, Info);
-
- EXPECT_EQ(Context.eax, reg32(*Buf, Info[lldb_eax_i386]));
- EXPECT_EQ(Context.ebx, reg32(*Buf, Info[lldb_ebx_i386]));
- EXPECT_EQ(Context.ecx, reg32(*Buf, Info[lldb_ecx_i386]));
- EXPECT_EQ(Context.edx, reg32(*Buf, Info[lldb_edx_i386]));
- EXPECT_EQ(Context.edi, reg32(*Buf, Info[lldb_edi_i386]));
- EXPECT_EQ(Context.esi, reg32(*Buf, Info[lldb_esi_i386]));
- EXPECT_EQ(Context.ebp, reg32(*Buf, Info[lldb_ebp_i386]));
- EXPECT_EQ(Context.esp, reg32(*Buf, Info[lldb_esp_i386]));
- EXPECT_EQ(Context.eip, reg32(*Buf, Info[lldb_eip_i386]));
- EXPECT_EQ(Context.eflags, reg32(*Buf, Info[lldb_eflags_i386]));
- EXPECT_EQ(Context.cs, reg32(*Buf, Info[lldb_cs_i386]));
- EXPECT_EQ(Context.fs, reg32(*Buf, Info[lldb_fs_i386]));
- EXPECT_EQ(Context.gs, reg32(*Buf, Info[lldb_gs_i386]));
- EXPECT_EQ(Context.ss, reg32(*Buf, Info[lldb_ss_i386]));
- EXPECT_EQ(Context.ds, reg32(*Buf, Info[lldb_ds_i386]));
- EXPECT_EQ(Context.es, reg32(*Buf, Info[lldb_es_i386]));
-}
-
-TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_64) {
- MinidumpContext_x86_64 Context;
- Context.context_flags =
- static_cast<uint32_t>(MinidumpContext_x86_64_Flags::x86_64_Flag |
- MinidumpContext_x86_64_Flags::Control |
- MinidumpContext_x86_64_Flags::Segments |
- MinidumpContext_x86_64_Flags::Integer);
- Context.rax = 0x0001020304050607;
- Context.rbx = 0x08090a0b0c0d0e0f;
- Context.rcx = 0x1011121314151617;
- Context.rdx = 0x18191a1b1c1d1e1f;
- Context.rdi = 0x2021222324252627;
- Context.rsi = 0x28292a2b2c2d2e2f;
- Context.rbp = 0x3031323334353637;
- Context.rsp = 0x38393a3b3c3d3e3f;
- Context.r8 = 0x4041424344454647;
- Context.r9 = 0x48494a4b4c4d4e4f;
- Context.r10 = 0x5051525354555657;
- Context.r11 = 0x58595a5b5c5d5e5f;
- Context.r12 = 0x6061626364656667;
- Context.r13 = 0x68696a6b6c6d6e6f;
- Context.r14 = 0x7071727374757677;
- Context.r15 = 0x78797a7b7c7d7e7f;
- Context.rip = 0x8081828384858687;
- Context.eflags = 0x88898a8b;
- Context.cs = 0x8c8d;
- Context.fs = 0x8e8f;
- Context.gs = 0x9091;
- Context.ss = 0x9293;
- Context.ds = 0x9495;
- Context.ss = 0x9697;
- llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
- sizeof(Context));
-
- ArchSpec arch("x86_64-pc-linux");
- auto RegInterface = std::make_unique<RegisterContextLinux_x86_64>(arch);
- lldb::DataBufferSP Buf =
- ConvertMinidumpContext_x86_64(ContextRef, RegInterface.get());
- ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
-
- const RegisterInfo *Info = RegInterface->GetRegisterInfo();
- EXPECT_EQ(Context.rax, reg64(*Buf, Info[lldb_rax_x86_64]));
- EXPECT_EQ(Context.rbx, reg64(*Buf, Info[lldb_rbx_x86_64]));
- EXPECT_EQ(Context.rcx, reg64(*Buf, Info[lldb_rcx_x86_64]));
- EXPECT_EQ(Context.rdx, reg64(*Buf, Info[lldb_rdx_x86_64]));
- EXPECT_EQ(Context.rdi, reg64(*Buf, Info[lldb_rdi_x86_64]));
- EXPECT_EQ(Context.rsi, reg64(*Buf, Info[lldb_rsi_x86_64]));
- EXPECT_EQ(Context.rbp, reg64(*Buf, Info[lldb_rbp_x86_64]));
- EXPECT_EQ(Context.rsp, reg64(*Buf, Info[lldb_rsp_x86_64]));
- EXPECT_EQ(Context.r8, reg64(*Buf, Info[lldb_r8_x86_64]));
- EXPECT_EQ(Context.r9, reg64(*Buf, Info[lldb_r9_x86_64]));
- EXPECT_EQ(Context.r10, reg64(*Buf, Info[lldb_r10_x86_64]));
- EXPECT_EQ(Context.r11, reg64(*Buf, Info[lldb_r11_x86_64]));
- EXPECT_EQ(Context.r12, reg64(*Buf, Info[lldb_r12_x86_64]));
- EXPECT_EQ(Context.r13, reg64(*Buf, Info[lldb_r13_x86_64]));
- EXPECT_EQ(Context.r14, reg64(*Buf, Info[lldb_r14_x86_64]));
- EXPECT_EQ(Context.r15, reg64(*Buf, Info[lldb_r15_x86_64]));
- EXPECT_EQ(Context.rip, reg64(*Buf, Info[lldb_rip_x86_64]));
- EXPECT_EQ(Context.eflags, reg64(*Buf, Info[lldb_rflags_x86_64]));
- EXPECT_EQ(Context.cs, reg64(*Buf, Info[lldb_cs_x86_64]));
- EXPECT_EQ(Context.fs, reg64(*Buf, Info[lldb_fs_x86_64]));
- EXPECT_EQ(Context.gs, reg64(*Buf, Info[lldb_gs_x86_64]));
- EXPECT_EQ(Context.ss, reg64(*Buf, Info[lldb_ss_x86_64]));
- EXPECT_EQ(Context.ds, reg64(*Buf, Info[lldb_ds_x86_64]));
- EXPECT_EQ(Context.es, reg64(*Buf, Info[lldb_es_x86_64]));
-}
-
-static void TestARMRegInfo(const lldb_private::RegisterInfo *info) {
- // Make sure we have valid register numbers for eRegisterKindEHFrame and
- // eRegisterKindDWARF for GPR registers r0-r15 so that we can unwind
- // correctly when using this information.
- llvm::StringRef name(info->name);
- llvm::StringRef alt_name(info->alt_name);
- if (name.startswith("r") || alt_name.startswith("r")) {
- EXPECT_NE(info->kinds[lldb::eRegisterKindEHFrame], LLDB_INVALID_REGNUM);
- EXPECT_NE(info->kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
- }
- // Verify generic register are set correctly
- if (name == "r0") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_ARG1);
- } else if (name == "r1") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_ARG2);
- } else if (name == "r2") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_ARG3);
- } else if (name == "r3") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_ARG4);
- } else if (name == "sp") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_SP);
- } else if (name == "fp") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_FP);
- } else if (name == "lr") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_RA);
- } else if (name == "pc") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_PC);
- } else if (name == "cpsr") {
- EXPECT_EQ(info->kinds[lldb::eRegisterKindGeneric],
- (uint32_t)LLDB_REGNUM_GENERIC_FLAGS);
- }
-}
-
-TEST(RegisterContextMinidump, CheckRegisterContextMinidump_ARM) {
- size_t num_regs = RegisterContextMinidump_ARM::GetRegisterCountStatic();
- const lldb_private::RegisterInfo *reg_info;
- for (size_t reg=0; reg<num_regs; ++reg) {
- reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg,
- true);
- TestARMRegInfo(reg_info);
- reg_info = RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(reg,
- false);
- TestARMRegInfo(reg_info);
- }
-}
+++ /dev/null
-if (LLDB_ENABLE_PYTHON)
- add_subdirectory(Python)
-endif()
-if (LLDB_ENABLE_LUA)
- add_subdirectory(Lua)
-endif()
+++ /dev/null
-add_lldb_unittest(ScriptInterpreterLuaTests
- LuaTests.cpp
- ScriptInterpreterTests.cpp
-
- LINK_LIBS
- lldbHost
- lldbPluginScriptInterpreterLua
- lldbPluginPlatformLinux
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
+++ /dev/null
-//===-- LuaTests.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ScriptInterpreter/Lua/Lua.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-extern "C" int luaopen_lldb(lua_State *L) { return 0; }
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
-
-// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
-// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
-// incompatible with C
-#if _MSC_VER
-#pragma warning (push)
-#pragma warning (disable : 4190)
-#endif
-
-extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction(
- lua_State *L, lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl) {
- return false;
-}
-
-extern "C" llvm::Expected<bool> LLDBSwigLuaWatchpointCallbackFunction(
- lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp) {
- return false;
-}
-
-#if _MSC_VER
-#pragma warning (pop)
-#endif
-
-#pragma clang diagnostic pop
-
-TEST(LuaTest, RunValid) {
- Lua lua;
- llvm::Error error = lua.Run("foo = 1");
- EXPECT_FALSE(static_cast<bool>(error));
-}
-
-TEST(LuaTest, RunInvalid) {
- Lua lua;
- llvm::Error error = lua.Run("nil = foo");
- EXPECT_TRUE(static_cast<bool>(error));
- EXPECT_EQ(llvm::toString(std::move(error)),
- "[string \"buffer\"]:1: unexpected symbol near 'nil'\n");
-}
+++ /dev/null
-//===-- LuaTests.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Platform/Linux/PlatformLinux.h"
-#include "Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Target/Platform.h"
-#include "lldb/Utility/Reproducer.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace lldb;
-
-namespace {
-class ScriptInterpreterTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
- FileSystem::Initialize();
- HostInfo::Initialize();
-
- // Pretend Linux is the host platform.
- platform_linux::PlatformLinux::Initialize();
- ArchSpec arch("powerpc64-pc-linux");
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
- }
- void TearDown() override {
- platform_linux::PlatformLinux::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- Reproducer::Terminate();
- }
-};
-} // namespace
-
-TEST_F(ScriptInterpreterTest, ExecuteOneLine) {
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- ScriptInterpreterLua script_interpreter(*debugger_sp);
- CommandReturnObject result(/*colors*/ false);
- EXPECT_TRUE(script_interpreter.ExecuteOneLine("foo = 1", &result));
- EXPECT_FALSE(script_interpreter.ExecuteOneLine("nil = foo", &result));
- EXPECT_TRUE(result.GetErrorData().startswith(
- "error: lua failed attempting to evaluate 'nil = foo'"));
-}
+++ /dev/null
-add_lldb_unittest(ScriptInterpreterPythonTests
- PythonDataObjectsTests.cpp
- PythonTestSuite.cpp
-
- LINK_LIBS
- lldbHost
- lldbPluginScriptInterpreterPython
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
-
-if(Python3_RPATH)
- set_property(TARGET ScriptInterpreterPythonTests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}")
-endif()
+++ /dev/null
-//===-- PythonDataObjectsTests.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
-#include "gtest/gtest.h"
-
-#include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h"
-#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/lldb-enumerations.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "PythonTestSuite.h"
-
-using namespace lldb_private;
-using namespace lldb_private::python;
-using llvm::Error;
-using llvm::Expected;
-
-class PythonDataObjectsTest : public PythonTestSuite {
-public:
- void SetUp() override {
- PythonTestSuite::SetUp();
-
- m_sys_module = unwrapIgnoringErrors(PythonModule::Import("sys"));
- m_main_module = PythonModule::MainModule();
- m_builtins_module = PythonModule::BuiltinsModule();
- }
-
- void TearDown() override {
- m_sys_module.Reset();
- m_main_module.Reset();
- m_builtins_module.Reset();
-
- PythonTestSuite::TearDown();
- }
-
-protected:
- PythonModule m_sys_module;
- PythonModule m_main_module;
- PythonModule m_builtins_module;
-};
-
-TEST_F(PythonDataObjectsTest, TestOwnedReferences) {
- // After creating a new object, the refcount should be >= 1
- PyObject *obj = PyLong_FromLong(3);
- Py_ssize_t original_refcnt = obj->ob_refcnt;
- EXPECT_LE(1, original_refcnt);
-
- // If we take an owned reference, the refcount should be the same
- PythonObject owned_long(PyRefType::Owned, obj);
- EXPECT_EQ(original_refcnt, owned_long.get()->ob_refcnt);
-
- // Take another reference and verify that the refcount increases by 1
- PythonObject strong_ref(owned_long);
- EXPECT_EQ(original_refcnt + 1, strong_ref.get()->ob_refcnt);
-
- // If we reset the first one, the refcount should be the original value.
- owned_long.Reset();
- EXPECT_EQ(original_refcnt, strong_ref.get()->ob_refcnt);
-}
-
-TEST_F(PythonDataObjectsTest, TestResetting) {
- PythonDictionary dict(PyInitialValue::Empty);
-
- PyObject *new_dict = PyDict_New();
- dict = Take<PythonDictionary>(new_dict);
- EXPECT_EQ(new_dict, dict.get());
-
- dict = Take<PythonDictionary>(PyDict_New());
- EXPECT_NE(nullptr, dict.get());
- dict.Reset();
- EXPECT_EQ(nullptr, dict.get());
-}
-
-TEST_F(PythonDataObjectsTest, TestBorrowedReferences) {
- PythonInteger long_value(PyRefType::Owned, PyLong_FromLong(3));
- Py_ssize_t original_refcnt = long_value.get()->ob_refcnt;
- EXPECT_LE(1, original_refcnt);
-
- PythonInteger borrowed_long(PyRefType::Borrowed, long_value.get());
- EXPECT_EQ(original_refcnt + 1, borrowed_long.get()->ob_refcnt);
-}
-
-TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionNoDot) {
- PythonObject sys_module = m_main_module.ResolveName("sys");
- EXPECT_EQ(m_sys_module.get(), sys_module.get());
- EXPECT_TRUE(sys_module.IsAllocated());
- EXPECT_TRUE(PythonModule::Check(sys_module.get()));
-}
-
-TEST_F(PythonDataObjectsTest, TestModuleNameResolutionNoDot) {
- PythonObject sys_path = m_sys_module.ResolveName("path");
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
- EXPECT_TRUE(sys_path.IsAllocated());
- EXPECT_TRUE(sys_version_info.IsAllocated());
-
- EXPECT_TRUE(PythonList::Check(sys_path.get()));
-}
-
-TEST_F(PythonDataObjectsTest, TestTypeNameResolutionNoDot) {
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
-
- PythonObject version_info_type(PyRefType::Owned,
- PyObject_Type(sys_version_info.get()));
- EXPECT_TRUE(version_info_type.IsAllocated());
- PythonObject major_version_field = version_info_type.ResolveName("major");
- EXPECT_TRUE(major_version_field.IsAllocated());
-}
-
-TEST_F(PythonDataObjectsTest, TestInstanceNameResolutionNoDot) {
- PythonObject sys_version_info = m_sys_module.ResolveName("version_info");
- PythonObject major_version_field = sys_version_info.ResolveName("major");
- PythonObject minor_version_field = sys_version_info.ResolveName("minor");
-
- EXPECT_TRUE(major_version_field.IsAllocated());
- EXPECT_TRUE(minor_version_field.IsAllocated());
-
- auto major_version_value = As<long long>(major_version_field);
- auto minor_version_value = As<long long>(minor_version_field);
-
- EXPECT_THAT_EXPECTED(major_version_value, llvm::HasValue(PY_MAJOR_VERSION));
- EXPECT_THAT_EXPECTED(minor_version_value, llvm::HasValue(PY_MINOR_VERSION));
-}
-
-TEST_F(PythonDataObjectsTest, TestGlobalNameResolutionWithDot) {
- PythonObject sys_path = m_main_module.ResolveName("sys.path");
- EXPECT_TRUE(sys_path.IsAllocated());
- EXPECT_TRUE(PythonList::Check(sys_path.get()));
-
- auto version_major =
- As<long long>(m_main_module.ResolveName("sys.version_info.major"));
-
- auto version_minor =
- As<long long>(m_main_module.ResolveName("sys.version_info.minor"));
-
- EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
- EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
-}
-
-TEST_F(PythonDataObjectsTest, TestDictionaryResolutionWithDot) {
- // Make up a custom dictionary with "sys" pointing to the `sys` module.
- PythonDictionary dict(PyInitialValue::Empty);
- dict.SetItemForKey(PythonString("sys"), m_sys_module);
-
- // Now use that dictionary to resolve `sys.version_info.major`
- auto version_major = As<long long>(
- PythonObject::ResolveNameWithDictionary("sys.version_info.major", dict));
-
- auto version_minor = As<long long>(
- PythonObject::ResolveNameWithDictionary("sys.version_info.minor", dict));
-
- EXPECT_THAT_EXPECTED(version_major, llvm::HasValue(PY_MAJOR_VERSION));
- EXPECT_THAT_EXPECTED(version_minor, llvm::HasValue(PY_MINOR_VERSION));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonInteger) {
- // Test that integers behave correctly when wrapped by a PythonInteger.
-
-#if PY_MAJOR_VERSION < 3
- // Verify that `PythonInt` works correctly when given a PyInt object.
- // Note that PyInt doesn't exist in Python 3.x, so this is only for 2.x
- PyObject *py_int = PyInt_FromLong(12);
- EXPECT_TRUE(PythonInteger::Check(py_int));
- PythonInteger python_int(PyRefType::Owned, py_int);
-
- EXPECT_EQ(PyObjectType::Integer, python_int.GetObjectType());
- auto python_int_value = As<long long>(python_int);
- EXPECT_THAT_EXPECTED(python_int_value, llvm::HasValue(12));
-#endif
-
- // Verify that `PythonInteger` works correctly when given a PyLong object.
- PyObject *py_long = PyLong_FromLong(12);
- EXPECT_TRUE(PythonInteger::Check(py_long));
- PythonInteger python_long(PyRefType::Owned, py_long);
- EXPECT_EQ(PyObjectType::Integer, python_long.GetObjectType());
-
- // Verify that you can reset the value and that it is reflected properly.
- python_long.SetInteger(40);
- auto e = As<long long>(python_long);
- EXPECT_THAT_EXPECTED(e, llvm::HasValue(40));
-
- // Test that creating a `PythonInteger` object works correctly with the
- // int constructor.
- PythonInteger constructed_int(7);
- auto value = As<long long>(constructed_int);
- EXPECT_THAT_EXPECTED(value, llvm::HasValue(7));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonBoolean) {
- // Test PythonBoolean constructed from Py_True
- EXPECT_TRUE(PythonBoolean::Check(Py_True));
- PythonBoolean python_true(PyRefType::Owned, Py_True);
- EXPECT_EQ(PyObjectType::Boolean, python_true.GetObjectType());
-
- // Test PythonBoolean constructed from Py_False
- EXPECT_TRUE(PythonBoolean::Check(Py_False));
- PythonBoolean python_false(PyRefType::Owned, Py_False);
- EXPECT_EQ(PyObjectType::Boolean, python_false.GetObjectType());
-
- auto test_from_long = [](long value) {
- PyObject *py_bool = PyBool_FromLong(value);
- EXPECT_TRUE(PythonBoolean::Check(py_bool));
- PythonBoolean python_boolean(PyRefType::Owned, py_bool);
- EXPECT_EQ(PyObjectType::Boolean, python_boolean.GetObjectType());
- EXPECT_EQ(bool(value), python_boolean.GetValue());
- };
-
- // Test PythonBoolean constructed from long integer values.
- test_from_long(0); // Test 'false' value.
- test_from_long(1); // Test 'true' value.
- test_from_long(~0); // Any value != 0 is 'true'.
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonBytes) {
- static const char *test_bytes = "PythonDataObjectsTest::TestPythonBytes";
- PyObject *py_bytes = PyBytes_FromString(test_bytes);
- EXPECT_TRUE(PythonBytes::Check(py_bytes));
- PythonBytes python_bytes(PyRefType::Owned, py_bytes);
-
-#if PY_MAJOR_VERSION < 3
- EXPECT_TRUE(PythonString::Check(py_bytes));
- EXPECT_EQ(PyObjectType::String, python_bytes.GetObjectType());
-#else
- EXPECT_FALSE(PythonString::Check(py_bytes));
- EXPECT_EQ(PyObjectType::Bytes, python_bytes.GetObjectType());
-#endif
-
- llvm::ArrayRef<uint8_t> bytes = python_bytes.GetBytes();
- EXPECT_EQ(bytes.size(), strlen(test_bytes));
- EXPECT_EQ(0, ::memcmp(bytes.data(), test_bytes, bytes.size()));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonByteArray) {
- static const char *test_bytes = "PythonDataObjectsTest::TestPythonByteArray";
- llvm::StringRef orig_bytes(test_bytes);
- PyObject *py_bytes =
- PyByteArray_FromStringAndSize(test_bytes, orig_bytes.size());
- EXPECT_TRUE(PythonByteArray::Check(py_bytes));
- PythonByteArray python_bytes(PyRefType::Owned, py_bytes);
- EXPECT_EQ(PyObjectType::ByteArray, python_bytes.GetObjectType());
-
- llvm::ArrayRef<uint8_t> after_bytes = python_bytes.GetBytes();
- EXPECT_EQ(after_bytes.size(), orig_bytes.size());
- EXPECT_EQ(0, ::memcmp(orig_bytes.data(), test_bytes, orig_bytes.size()));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonString) {
- // Test that strings behave correctly when wrapped by a PythonString.
-
- static const char *test_string = "PythonDataObjectsTest::TestPythonString1";
- static const char *test_string2 = "PythonDataObjectsTest::TestPythonString2";
-
-#if PY_MAJOR_VERSION < 3
- // Verify that `PythonString` works correctly when given a PyString object.
- // Note that PyString doesn't exist in Python 3.x, so this is only for 2.x
- PyObject *py_string = PyString_FromString(test_string);
- EXPECT_TRUE(PythonString::Check(py_string));
- PythonString python_string(PyRefType::Owned, py_string);
-
- EXPECT_EQ(PyObjectType::String, python_string.GetObjectType());
- EXPECT_STREQ(test_string, python_string.GetString().data());
-#else
- // Verify that `PythonString` works correctly when given a PyUnicode object.
- PyObject *py_unicode = PyUnicode_FromString(test_string);
- EXPECT_TRUE(PythonString::Check(py_unicode));
- PythonString python_unicode(PyRefType::Owned, py_unicode);
- EXPECT_EQ(PyObjectType::String, python_unicode.GetObjectType());
- EXPECT_STREQ(test_string, python_unicode.GetString().data());
-#endif
-
- // Test that creating a `PythonString` object works correctly with the
- // string constructor
- PythonString constructed_string(test_string2);
- EXPECT_EQ(test_string2, constructed_string.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonStringToStr) {
- const char *GetString = "PythonDataObjectsTest::TestPythonStringToStr";
-
- PythonString str(GetString);
- EXPECT_EQ(GetString, str.GetString());
-
- PythonString str_str = str.Str();
- EXPECT_EQ(GetString, str_str.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonIntegerToStr) {}
-
-TEST_F(PythonDataObjectsTest, TestPythonIntegerToStructuredInteger) {
- PythonInteger integer(7);
- auto int_sp = integer.CreateStructuredInteger();
- EXPECT_EQ(7U, int_sp->GetValue());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonStringToStructuredString) {
- static const char *test_string =
- "PythonDataObjectsTest::TestPythonStringToStructuredString";
- PythonString constructed_string(test_string);
- auto string_sp = constructed_string.CreateStructuredString();
- EXPECT_EQ(test_string, string_sp->GetStringValue());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonListValueEquality) {
- // Test that a list which is built through the native
- // Python API behaves correctly when wrapped by a PythonList.
- static const unsigned list_size = 2;
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
-
- PyObject *py_list = PyList_New(2);
- EXPECT_TRUE(PythonList::Check(py_list));
- PythonList list(PyRefType::Owned, py_list);
-
- PythonObject list_items[list_size];
- list_items[0] = PythonInteger(long_value0);
- list_items[1] = PythonString(string_value1);
-
- for (unsigned i = 0; i < list_size; ++i)
- list.SetItemAtIndex(i, list_items[i]);
-
- EXPECT_EQ(list_size, list.GetSize());
- EXPECT_EQ(PyObjectType::List, list.GetObjectType());
-
- // Verify that the values match
- PythonObject chk_value1 = list.GetItemAtIndex(0);
- PythonObject chk_value2 = list.GetItemAtIndex(1);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
-
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
-
- auto chkint = As<long long>(chk_value1);
- ASSERT_THAT_EXPECTED(chkint, llvm::HasValue(long_value0));
- EXPECT_EQ(string_value1, chk_str.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonListManipulation) {
- // Test that manipulation of a PythonList behaves correctly when
- // wrapped by a PythonDictionary.
-
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
-
- PythonList list(PyInitialValue::Empty);
- PythonInteger integer(long_value0);
- PythonString string(string_value1);
-
- list.AppendItem(integer);
- list.AppendItem(string);
- EXPECT_EQ(2U, list.GetSize());
-
- // Verify that the values match
- PythonObject chk_value1 = list.GetItemAtIndex(0);
- PythonObject chk_value2 = list.GetItemAtIndex(1);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
-
- PythonInteger chk_int(PyRefType::Borrowed, chk_value1.get());
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
-
- auto e = As<long long>(chk_int);
- EXPECT_THAT_EXPECTED(e, llvm::HasValue(long_value0));
- EXPECT_EQ(string_value1, chk_str.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonListToStructuredList) {
- static const long long_value0 = 5;
- static const char *const string_value1 = "String Index 1";
-
- PythonList list(PyInitialValue::Empty);
- list.AppendItem(PythonInteger(long_value0));
- list.AppendItem(PythonString(string_value1));
-
- auto array_sp = list.CreateStructuredArray();
- EXPECT_EQ(lldb::eStructuredDataTypeInteger,
- array_sp->GetItemAtIndex(0)->GetType());
- EXPECT_EQ(lldb::eStructuredDataTypeString,
- array_sp->GetItemAtIndex(1)->GetType());
-
- auto int_sp = array_sp->GetItemAtIndex(0)->GetAsInteger();
- auto string_sp = array_sp->GetItemAtIndex(1)->GetAsString();
-
- EXPECT_EQ(long_value0, long(int_sp->GetValue()));
- EXPECT_EQ(string_value1, string_sp->GetValue());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonTupleSize) {
- PythonTuple tuple(PyInitialValue::Empty);
- EXPECT_EQ(0U, tuple.GetSize());
-
- tuple = PythonTuple(3);
- EXPECT_EQ(3U, tuple.GetSize());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonTupleValues) {
- PythonTuple tuple(3);
-
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
-
- tuple.SetItemAtIndex(0, int_value);
- tuple.SetItemAtIndex(1, string_value);
- tuple.SetItemAtIndex(2, none_value);
-
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList) {
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
- PythonTuple tuple{int_value, string_value, none_value};
- EXPECT_EQ(3U, tuple.GetSize());
-
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonTupleInitializerList2) {
- PythonInteger int_value(1);
- PythonString string_value("Test");
- PythonObject none_value(PyRefType::Borrowed, Py_None);
-
- PythonTuple tuple{int_value.get(), string_value.get(), none_value.get()};
- EXPECT_EQ(3U, tuple.GetSize());
-
- EXPECT_EQ(tuple.GetItemAtIndex(0).get(), int_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(1).get(), string_value.get());
- EXPECT_EQ(tuple.GetItemAtIndex(2).get(), none_value.get());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonTupleToStructuredList) {
- PythonInteger int_value(1);
- PythonString string_value("Test");
-
- PythonTuple tuple{int_value.get(), string_value.get()};
-
- auto array_sp = tuple.CreateStructuredArray();
- EXPECT_EQ(tuple.GetSize(), array_sp->GetSize());
- EXPECT_EQ(lldb::eStructuredDataTypeInteger,
- array_sp->GetItemAtIndex(0)->GetType());
- EXPECT_EQ(lldb::eStructuredDataTypeString,
- array_sp->GetItemAtIndex(1)->GetType());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
- // Test that a dictionary which is built through the native
- // Python API behaves correctly when wrapped by a PythonDictionary.
- static const unsigned dict_entries = 2;
- const char *key_0 = "Key 0";
- int key_1 = 1;
- const int value_0 = 0;
- const char *value_1 = "Value 1";
-
- PythonObject py_keys[dict_entries];
- PythonObject py_values[dict_entries];
-
- py_keys[0] = PythonString(key_0);
- py_keys[1] = PythonInteger(key_1);
- py_values[0] = PythonInteger(value_0);
- py_values[1] = PythonString(value_1);
-
- PyObject *py_dict = PyDict_New();
- EXPECT_TRUE(PythonDictionary::Check(py_dict));
- PythonDictionary dict(PyRefType::Owned, py_dict);
-
- for (unsigned i = 0; i < dict_entries; ++i)
- PyDict_SetItem(py_dict, py_keys[i].get(), py_values[i].get());
- EXPECT_EQ(dict.GetSize(), dict_entries);
- EXPECT_EQ(PyObjectType::Dictionary, dict.GetObjectType());
-
- // Verify that the values match
- PythonObject chk_value1 = dict.GetItemForKey(py_keys[0]);
- PythonObject chk_value2 = dict.GetItemForKey(py_keys[1]);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
-
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
- auto chkint = As<long long>(chk_value1);
-
- EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
- EXPECT_EQ(value_1, chk_str.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
- // Test that manipulation of a dictionary behaves correctly when wrapped
- // by a PythonDictionary.
- static const unsigned dict_entries = 2;
-
- const char *const key_0 = "Key 0";
- const char *const key_1 = "Key 1";
- const long value_0 = 1;
- const char *const value_1 = "Value 1";
-
- PythonString keys[dict_entries];
- PythonObject values[dict_entries];
-
- keys[0] = PythonString(key_0);
- keys[1] = PythonString(key_1);
- values[0] = PythonInteger(value_0);
- values[1] = PythonString(value_1);
-
- PythonDictionary dict(PyInitialValue::Empty);
- for (int i = 0; i < 2; ++i)
- dict.SetItemForKey(keys[i], values[i]);
-
- EXPECT_EQ(dict_entries, dict.GetSize());
-
- // Verify that the keys and values match
- PythonObject chk_value1 = dict.GetItemForKey(keys[0]);
- PythonObject chk_value2 = dict.GetItemForKey(keys[1]);
- EXPECT_TRUE(PythonInteger::Check(chk_value1.get()));
- EXPECT_TRUE(PythonString::Check(chk_value2.get()));
-
- auto chkint = As<long long>(chk_value1);
- PythonString chk_str(PyRefType::Borrowed, chk_value2.get());
-
- EXPECT_THAT_EXPECTED(chkint, llvm::HasValue(value_0));
- EXPECT_EQ(value_1, chk_str.GetString());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonDictionaryToStructuredDictionary) {
- static const char *const string_key0 = "String Key 0";
- static const char *const string_key1 = "String Key 1";
-
- static const char *const string_value0 = "String Value 0";
- static const long int_value1 = 7;
-
- PythonDictionary dict(PyInitialValue::Empty);
- dict.SetItemForKey(PythonString(string_key0), PythonString(string_value0));
- dict.SetItemForKey(PythonString(string_key1), PythonInteger(int_value1));
-
- auto dict_sp = dict.CreateStructuredDictionary();
- EXPECT_EQ(2U, dict_sp->GetSize());
-
- EXPECT_TRUE(dict_sp->HasKey(string_key0));
- EXPECT_TRUE(dict_sp->HasKey(string_key1));
-
- auto string_sp = dict_sp->GetValueForKey(string_key0)->GetAsString();
- auto int_sp = dict_sp->GetValueForKey(string_key1)->GetAsInteger();
-
- EXPECT_EQ(string_value0, string_sp->GetValue());
- EXPECT_EQ(int_value1, long(int_sp->GetValue()));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonCallableCheck) {
- PythonObject sys_exc_info = m_sys_module.ResolveName("exc_info");
- PythonObject none(PyRefType::Borrowed, Py_None);
-
- EXPECT_TRUE(PythonCallable::Check(sys_exc_info.get()));
- EXPECT_FALSE(PythonCallable::Check(none.get()));
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) {
- auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>();
- PythonInteger one(1);
- PythonString two("two");
- PythonTuple three = {one, two};
-
- PythonTuple tuple_to_convert = {one, two, three};
- PythonObject result = list({tuple_to_convert});
-
- EXPECT_TRUE(PythonList::Check(result.get()));
- auto list_result = result.AsType<PythonList>();
- EXPECT_EQ(3U, list_result.GetSize());
- EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get());
- EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get());
- EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get());
-}
-
-TEST_F(PythonDataObjectsTest, TestPythonFile) {
- auto file = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
- File::eOpenOptionRead);
- ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
- auto py_file = PythonFile::FromFile(*file.get(), "r");
- ASSERT_THAT_EXPECTED(py_file, llvm::Succeeded());
- EXPECT_TRUE(PythonFile::Check(py_file.get().get()));
-}
-
-TEST_F(PythonDataObjectsTest, TestObjectAttributes) {
- PythonInteger py_int(42);
- EXPECT_TRUE(py_int.HasAttribute("numerator"));
- EXPECT_FALSE(py_int.HasAttribute("this_should_not_exist"));
-
- auto numerator_attr = As<long long>(py_int.GetAttributeValue("numerator"));
-
- EXPECT_THAT_EXPECTED(numerator_attr, llvm::HasValue(42));
-}
-
-TEST_F(PythonDataObjectsTest, TestExtractingUInt64ThroughStructuredData) {
- // Make up a custom dictionary with "sys" pointing to the `sys` module.
- const char *key_name = "addr";
- const uint64_t value = 0xf000000000000000ull;
- PythonDictionary python_dict(PyInitialValue::Empty);
- PythonInteger python_ull_value(PyRefType::Owned,
- PyLong_FromUnsignedLongLong(value));
- python_dict.SetItemForKey(PythonString(key_name), python_ull_value);
- StructuredData::ObjectSP structured_data_sp =
- python_dict.CreateStructuredObject();
- EXPECT_TRUE((bool)structured_data_sp);
- if (structured_data_sp) {
- StructuredData::Dictionary *structured_dict_ptr =
- structured_data_sp->GetAsDictionary();
- EXPECT_TRUE(structured_dict_ptr != nullptr);
- if (structured_dict_ptr) {
- StructuredData::ObjectSP structured_addr_value_sp =
- structured_dict_ptr->GetValueForKey(key_name);
- EXPECT_TRUE((bool)structured_addr_value_sp);
- const uint64_t extracted_value =
- structured_addr_value_sp->GetIntegerValue(123);
- EXPECT_TRUE(extracted_value == value);
- }
- }
-}
-
-TEST_F(PythonDataObjectsTest, TestCallable) {
-
- PythonDictionary globals(PyInitialValue::Empty);
- auto builtins = PythonModule::BuiltinsModule();
- llvm::Error error = globals.SetItem("__builtins__", builtins);
- ASSERT_FALSE(error);
-
- {
- PyObject *o = PyRun_String("lambda x : x", Py_eval_input, globals.get(),
- globals.get());
- ASSERT_FALSE(o == NULL);
- auto lambda = Take<PythonCallable>(o);
- auto arginfo = lambda.GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
- }
-
- {
- PyObject *o = PyRun_String("lambda x,y=0: x", Py_eval_input, globals.get(),
- globals.get());
- ASSERT_FALSE(o == NULL);
- auto lambda = Take<PythonCallable>(o);
- auto arginfo = lambda.GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 2u);
- }
-
- {
- PyObject *o = PyRun_String("lambda x,y=0, **kw: x", Py_eval_input,
- globals.get(), globals.get());
- ASSERT_FALSE(o == NULL);
- auto lambda = Take<PythonCallable>(o);
- auto arginfo = lambda.GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 2u);
- }
-
- {
- PyObject *o = PyRun_String("lambda x,y,*a: x", Py_eval_input, globals.get(),
- globals.get());
- ASSERT_FALSE(o == NULL);
- auto lambda = Take<PythonCallable>(o);
- auto arginfo = lambda.GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args,
- PythonCallable::ArgInfo::UNBOUNDED);
- }
-
- {
- PyObject *o = PyRun_String("lambda x,y,*a,**kw: x", Py_eval_input,
- globals.get(), globals.get());
- ASSERT_FALSE(o == NULL);
- auto lambda = Take<PythonCallable>(o);
- auto arginfo = lambda.GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args,
- PythonCallable::ArgInfo::UNBOUNDED);
- }
-
- {
- const char *script = R"(
-class Foo:
- def bar(self, x):
- return x
- @classmethod
- def classbar(cls, x):
- return x
- @staticmethod
- def staticbar(x):
- return x
- def __call__(self, x):
- return x
-obj = Foo()
-bar_bound = Foo().bar
-bar_class = Foo().classbar
-bar_static = Foo().staticbar
-bar_unbound = Foo.bar
-
-
-class OldStyle:
- def __init__(self, one, two, three):
- pass
-
-class NewStyle(object):
- def __init__(self, one, two, three):
- pass
-
-)";
- PyObject *o =
- PyRun_String(script, Py_file_input, globals.get(), globals.get());
- ASSERT_FALSE(o == NULL);
- Take<PythonObject>(o);
-
- auto bar_bound = As<PythonCallable>(globals.GetItem("bar_bound"));
- ASSERT_THAT_EXPECTED(bar_bound, llvm::Succeeded());
- auto arginfo = bar_bound.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
-
- auto bar_unbound = As<PythonCallable>(globals.GetItem("bar_unbound"));
- ASSERT_THAT_EXPECTED(bar_unbound, llvm::Succeeded());
- arginfo = bar_unbound.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 2u);
-
- auto bar_class = As<PythonCallable>(globals.GetItem("bar_class"));
- ASSERT_THAT_EXPECTED(bar_class, llvm::Succeeded());
- arginfo = bar_class.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
-
- auto bar_static = As<PythonCallable>(globals.GetItem("bar_static"));
- ASSERT_THAT_EXPECTED(bar_static, llvm::Succeeded());
- arginfo = bar_static.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
-
- auto obj = As<PythonCallable>(globals.GetItem("obj"));
- ASSERT_THAT_EXPECTED(obj, llvm::Succeeded());
- arginfo = obj.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
-
- auto oldstyle = As<PythonCallable>(globals.GetItem("OldStyle"));
- ASSERT_THAT_EXPECTED(oldstyle, llvm::Succeeded());
- arginfo = oldstyle.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 3u);
-
- auto newstyle = As<PythonCallable>(globals.GetItem("NewStyle"));
- ASSERT_THAT_EXPECTED(newstyle, llvm::Succeeded());
- arginfo = newstyle.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 3u);
- }
-
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
-
- // the old implementation of GetArgInfo just doesn't work on builtins.
-
- {
- auto builtins = PythonModule::BuiltinsModule();
- auto hex = As<PythonCallable>(builtins.GetAttribute("hex"));
- ASSERT_THAT_EXPECTED(hex, llvm::Succeeded());
- auto arginfo = hex.get().GetArgInfo();
- ASSERT_THAT_EXPECTED(arginfo, llvm::Succeeded());
- EXPECT_EQ(arginfo.get().max_positional_args, 1u);
- }
-
-#endif
-}
-
-TEST_F(PythonDataObjectsTest, TestScript) {
-
- static const char script[] = R"(
-def factorial(n):
- if n > 1:
- return n * factorial(n-1)
- else:
- return 1;
-main = factorial
-)";
-
- PythonScript factorial(script);
-
- EXPECT_THAT_EXPECTED(As<long long>(factorial(5ll)), llvm::HasValue(120));
-}
-
-TEST_F(PythonDataObjectsTest, TestExceptions) {
-
- static const char script[] = R"(
-def foo():
- return bar()
-def bar():
- return baz()
-def baz():
- return 1 / 0
-main = foo
-)";
-
- PythonScript foo(script);
-
- EXPECT_THAT_EXPECTED(
- foo(), llvm::Failed<PythonException>(testing::Property(
- &PythonException::ReadBacktrace,
- testing::AllOf(testing::ContainsRegex("line 3, in foo"),
- testing::ContainsRegex("line 5, in bar"),
- testing::ContainsRegex("line 7, in baz"),
- testing::ContainsRegex("ZeroDivisionError")))));
-
- static const char script2[] = R"(
-class MyError(Exception):
- def __str__(self):
- return self.my_message
-
-def main():
- raise MyError("lol")
-
-)";
-
- PythonScript lol(script2);
-
- EXPECT_THAT_EXPECTED(lol(),
- llvm::Failed<PythonException>(testing::Property(
- &PythonException::ReadBacktrace,
- testing::ContainsRegex("unprintable MyError"))));
-}
-
-TEST_F(PythonDataObjectsTest, TestRun) {
-
- PythonDictionary globals(PyInitialValue::Empty);
-
- auto x = As<long long>(runStringOneLine("40 + 2", globals, globals));
- ASSERT_THAT_EXPECTED(x, llvm::Succeeded());
- EXPECT_EQ(x.get(), 42l);
-
- Expected<PythonObject> r = runStringOneLine("n = 42", globals, globals);
- ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
- auto y = As<long long>(globals.GetItem("n"));
- ASSERT_THAT_EXPECTED(y, llvm::Succeeded());
- EXPECT_EQ(y.get(), 42l);
-
- const char script[] = R"(
-def foobar():
- return "foo" + "bar" + "baz"
-g = foobar()
-)";
-
- r = runStringMultiLine(script, globals, globals);
- ASSERT_THAT_EXPECTED(r, llvm::Succeeded());
- auto g = As<std::string>(globals.GetItem("g"));
- ASSERT_THAT_EXPECTED(g, llvm::HasValue("foobarbaz"));
-}
\ No newline at end of file
+++ /dev/null
-//===-- PythonTestSuite.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
-
-#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h"
-#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h"
-#include "lldb/API/SBError.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-
-#include "PythonTestSuite.h"
-
-using namespace lldb_private;
-class TestScriptInterpreterPython : public ScriptInterpreterPythonImpl {
-public:
- using ScriptInterpreterPythonImpl::Initialize;
- using ScriptInterpreterPythonImpl::InitializePrivate;
-};
-
-void PythonTestSuite::SetUp() {
- FileSystem::Initialize();
- HostInfoBase::Initialize();
- // ScriptInterpreterPython::Initialize() depends on HostInfo being
- // initializedso it can compute the python directory etc.
- TestScriptInterpreterPython::Initialize();
- TestScriptInterpreterPython::InitializePrivate();
-
- // Although we don't care about concurrency for the purposes of running
- // this test suite, Python requires the GIL to be locked even for
- // deallocating memory, which can happen when you call Py_DECREF or
- // Py_INCREF. So acquire the GIL for the entire duration of this
- // test suite.
- m_gil_state = PyGILState_Ensure();
-}
-
-void PythonTestSuite::TearDown() {
- PyGILState_Release(m_gil_state);
-
- TestScriptInterpreterPython::Terminate();
- HostInfoBase::Terminate();
- FileSystem::Terminate();
-}
-
-// The following functions are the Pythonic implementations of the required
-// callbacks. Because they're defined in libLLDB which we cannot link for the
-// unit test, we have a 'default' implementation here.
-
-#if PY_MAJOR_VERSION >= 3
-extern "C" PyObject *PyInit__lldb(void) { return nullptr; }
-#define LLDBSwigPyInit PyInit__lldb
-#else
-extern "C" void init_lldb(void) {}
-#define LLDBSwigPyInit init_lldb
-#endif
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
-
-// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has
-// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is
-// incompatible with C
-#if _MSC_VER
-#pragma warning (push)
-#pragma warning (disable : 4190)
-#endif
-
-extern "C" llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction(
- const char *python_function_name, const char *session_dictionary_name,
- const lldb::StackFrameSP &sb_frame,
- const lldb::BreakpointLocationSP &sb_bp_loc,
- StructuredDataImpl *args_impl) {
- return false;
-}
-
-#if _MSC_VER
-#pragma warning (pop)
-#endif
-
-#pragma clang diagnostic pop
-
-extern "C" bool LLDBSwigPythonWatchpointCallbackFunction(
- const char *python_function_name, const char *session_dictionary_name,
- const lldb::StackFrameSP &sb_frame, const lldb::WatchpointSP &sb_wp) {
- return false;
-}
-
-extern "C" bool LLDBSwigPythonCallTypeScript(
- const char *python_function_name, void *session_dictionary,
- const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper,
- const lldb::TypeSummaryOptionsSP &options_sp, std::string &retval) {
- return false;
-}
-
-extern "C" void *
-LLDBSwigPythonCreateSyntheticProvider(const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ValueObjectSP &valobj_sp) {
- return nullptr;
-}
-
-extern "C" void *
-LLDBSwigPythonCreateCommandObject(const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::DebuggerSP debugger_sp) {
- return nullptr;
-}
-
-extern "C" void *LLDBSwigPythonCreateScriptedThreadPlan(
- const char *python_class_name, const char *session_dictionary_name,
- StructuredDataImpl *args_data,
- std::string &error_string,
- const lldb::ThreadPlanSP &thread_plan_sp) {
- return nullptr;
-}
-
-extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor,
- const char *method_name,
- Event *event_sp, bool &got_error) {
- return false;
-}
-
-extern "C" void *LLDBSwigPythonCreateScriptedBreakpointResolver(
- const char *python_class_name, const char *session_dictionary_name,
- lldb_private::StructuredDataImpl *args, lldb::BreakpointSP &bkpt_sp) {
- return nullptr;
-}
-
-extern "C" unsigned int
-LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name,
- lldb_private::SymbolContext *sym_ctx) {
- return 0;
-}
-
-extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor,
- uint32_t max) {
- return 0;
-}
-
-extern "C" void *LLDBSwigPython_GetChildAtIndex(void *implementor,
- uint32_t idx) {
- return nullptr;
-}
-
-extern "C" int LLDBSwigPython_GetIndexOfChildWithName(void *implementor,
- const char *child_name) {
- return 0;
-}
-
-extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data) {
- return nullptr;
-}
-
-extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data) {
- return nullptr;
-}
-
-extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data) {
- return nullptr;
-}
-
-extern lldb::ValueObjectSP
-LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data) {
- return nullptr;
-}
-
-extern "C" bool LLDBSwigPython_UpdateSynthProviderInstance(void *implementor) {
- return false;
-}
-
-extern "C" bool
-LLDBSwigPython_MightHaveChildrenSynthProviderInstance(void *implementor) {
- return false;
-}
-
-extern "C" void *
-LLDBSwigPython_GetValueSynthProviderInstance(void *implementor) {
- return nullptr;
-}
-
-extern "C" bool
-LLDBSwigPythonCallCommand(const char *python_function_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP &debugger, const char *args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
- return false;
-}
-
-extern "C" bool
-LLDBSwigPythonCallCommandObject(void *implementor, lldb::DebuggerSP &debugger,
- const char *args,
- lldb_private::CommandReturnObject &cmd_retobj,
- lldb::ExecutionContextRefSP exe_ctx_ref_sp) {
- return false;
-}
-
-extern "C" bool
-LLDBSwigPythonCallModuleInit(const char *python_module_name,
- const char *session_dictionary_name,
- lldb::DebuggerSP &debugger) {
- return false;
-}
-
-extern "C" void *
-LLDBSWIGPythonCreateOSPlugin(const char *python_class_name,
- const char *session_dictionary_name,
- const lldb::ProcessSP &process_sp) {
- return nullptr;
-}
-
-extern "C" void *LLDBSwigPythonCreateScriptedProcess(
- const char *python_class_name, const char *session_dictionary_name,
- const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl,
- std::string &error_string) {
- return nullptr;
-}
-
-extern "C" void *
-LLDBSWIGPython_CreateFrameRecognizer(const char *python_class_name,
- const char *session_dictionary_name) {
- return nullptr;
-}
-
-extern "C" void *
-LLDBSwigPython_GetRecognizedArguments(void *implementor,
- const lldb::StackFrameSP &frame_sp) {
- return nullptr;
-}
-
-extern "C" bool LLDBSWIGPythonRunScriptKeywordProcess(
- const char *python_function_name, const char *session_dictionary_name,
- lldb::ProcessSP &process, std::string &output) {
- return false;
-}
-
-extern "C" bool LLDBSWIGPythonRunScriptKeywordThread(
- const char *python_function_name, const char *session_dictionary_name,
- lldb::ThreadSP &thread, std::string &output) {
- return false;
-}
-
-extern "C" bool LLDBSWIGPythonRunScriptKeywordTarget(
- const char *python_function_name, const char *session_dictionary_name,
- lldb::TargetSP &target, std::string &output) {
- return false;
-}
-
-extern "C" bool LLDBSWIGPythonRunScriptKeywordFrame(
- const char *python_function_name, const char *session_dictionary_name,
- lldb::StackFrameSP &frame, std::string &output) {
- return false;
-}
-
-extern "C" bool LLDBSWIGPythonRunScriptKeywordValue(
- const char *python_function_name, const char *session_dictionary_name,
- lldb::ValueObjectSP &value, std::string &output) {
- return false;
-}
-
-extern "C" void *
-LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting,
- const lldb::TargetSP &target_sp) {
- return nullptr;
-}
-
-extern "C" void *LLDBSwigPythonCreateScriptedStopHook(
- lldb::TargetSP target_sp, const char *python_class_name,
- const char *session_dictionary_name,
- lldb_private::StructuredDataImpl *args_impl, Status &error) {
- return nullptr;
-}
-
-extern "C" bool
-LLDBSwigPythonStopHookCallHandleStop(void *implementor,
- lldb::ExecutionContextRefSP exc_ctx_sp,
- lldb::StreamSP stream) {
- return false;
-}
+++ /dev/null
-//===-- PythonTestSuite.cpp -------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-class PythonTestSuite : public testing::Test {
-public:
- void SetUp() override;
-
- void TearDown() override;
-
-private:
- PyGILState_STATE m_gil_state;
-};
+++ /dev/null
-add_lldb_unittest(SignalsTests
- UnixSignalsTest.cpp
-
- LINK_LIBS
- lldbTarget
- )
+++ /dev/null
-//===-- UnixSignalsTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-#include <string>
-
-#include "gtest/gtest.h"
-
-#include "lldb/Target/UnixSignals.h"
-#include "llvm/Support/FormatVariadic.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using llvm::None;
-
-class TestSignals : public UnixSignals {
-public:
- TestSignals() {
- m_signals.clear();
- AddSignal(2, "SIG2", false, true, true, "DESC2");
- AddSignal(4, "SIG4", true, false, true, "DESC4");
- AddSignal(8, "SIG8", true, true, true, "DESC8");
- AddSignal(16, "SIG16", true, false, false, "DESC16");
- }
-};
-
-void ExpectEqArrays(llvm::ArrayRef<int32_t> expected,
- llvm::ArrayRef<int32_t> observed, const char *file,
- int line) {
- std::string location = llvm::formatv("{0}:{1}", file, line);
- ASSERT_EQ(expected.size(), observed.size()) << location;
-
- for (size_t i = 0; i < observed.size(); ++i) {
- ASSERT_EQ(expected[i], observed[i])
- << "array index: " << i << "location:" << location;
- }
-}
-
-#define EXPECT_EQ_ARRAYS(expected, observed) \
- ExpectEqArrays((expected), (observed), __FILE__, __LINE__);
-
-TEST(UnixSignalsTest, Iteration) {
- TestSignals signals;
-
- EXPECT_EQ(4, signals.GetNumSignals());
- EXPECT_EQ(2, signals.GetFirstSignalNumber());
- EXPECT_EQ(4, signals.GetNextSignalNumber(2));
- EXPECT_EQ(8, signals.GetNextSignalNumber(4));
- EXPECT_EQ(16, signals.GetNextSignalNumber(8));
- EXPECT_EQ(LLDB_INVALID_SIGNAL_NUMBER, signals.GetNextSignalNumber(16));
-}
-
-TEST(UnixSignalsTest, GetInfo) {
- TestSignals signals;
-
- bool should_suppress = false, should_stop = false, should_notify = false;
- int32_t signo = 4;
- std::string name =
- signals.GetSignalInfo(signo, should_suppress, should_stop, should_notify);
- EXPECT_EQ("SIG4", name);
- EXPECT_EQ(true, should_suppress);
- EXPECT_EQ(false, should_stop);
- EXPECT_EQ(true, should_notify);
-
- EXPECT_EQ(true, signals.GetShouldSuppress(signo));
- EXPECT_EQ(false, signals.GetShouldStop(signo));
- EXPECT_EQ(true, signals.GetShouldNotify(signo));
- EXPECT_EQ(name, signals.GetSignalAsCString(signo));
-}
-
-TEST(UnixSignalsTest, VersionChange) {
- TestSignals signals;
-
- int32_t signo = 8;
- uint64_t ver = signals.GetVersion();
- EXPECT_GT(ver, 0ull);
- EXPECT_EQ(true, signals.GetShouldSuppress(signo));
- EXPECT_EQ(true, signals.GetShouldStop(signo));
- EXPECT_EQ(true, signals.GetShouldNotify(signo));
-
- EXPECT_EQ(signals.GetVersion(), ver);
-
- signals.SetShouldSuppress(signo, false);
- EXPECT_LT(ver, signals.GetVersion());
- ver = signals.GetVersion();
-
- signals.SetShouldStop(signo, true);
- EXPECT_LT(ver, signals.GetVersion());
- ver = signals.GetVersion();
-
- signals.SetShouldNotify(signo, false);
- EXPECT_LT(ver, signals.GetVersion());
- ver = signals.GetVersion();
-
- EXPECT_EQ(false, signals.GetShouldSuppress(signo));
- EXPECT_EQ(true, signals.GetShouldStop(signo));
- EXPECT_EQ(false, signals.GetShouldNotify(signo));
-
- EXPECT_EQ(ver, signals.GetVersion());
-}
-
-TEST(UnixSignalsTest, GetFilteredSignals) {
- TestSignals signals;
-
- auto all_signals = signals.GetFilteredSignals(None, None, None);
- std::vector<int32_t> expected = {2, 4, 8, 16};
- EXPECT_EQ_ARRAYS(expected, all_signals);
-
- auto supressed = signals.GetFilteredSignals(true, None, None);
- expected = {4, 8, 16};
- EXPECT_EQ_ARRAYS(expected, supressed);
-
- auto not_supressed = signals.GetFilteredSignals(false, None, None);
- expected = {2};
- EXPECT_EQ_ARRAYS(expected, not_supressed);
-
- auto stopped = signals.GetFilteredSignals(None, true, None);
- expected = {2, 8};
- EXPECT_EQ_ARRAYS(expected, stopped);
-
- auto not_stopped = signals.GetFilteredSignals(None, false, None);
- expected = {4, 16};
- EXPECT_EQ_ARRAYS(expected, not_stopped);
-
- auto notified = signals.GetFilteredSignals(None, None, true);
- expected = {2, 4, 8};
- EXPECT_EQ_ARRAYS(expected, notified);
-
- auto not_notified = signals.GetFilteredSignals(None, None, false);
- expected = {16};
- EXPECT_EQ_ARRAYS(expected, not_notified);
-
- auto signal4 = signals.GetFilteredSignals(true, false, true);
- expected = {4};
- EXPECT_EQ_ARRAYS(expected, signal4);
-}
+++ /dev/null
-add_lldb_unittest(SymbolTests
- LocateSymbolFileTest.cpp
- PostfixExpressionTest.cpp
- TestTypeSystem.cpp
- TestTypeSystemClang.cpp
- TestClangASTImporter.cpp
- TestDWARFCallFrameInfo.cpp
- TestType.cpp
- TestLineEntry.cpp
-
- LINK_LIBS
- lldbHost
- lldbSymbol
- lldbUtilityHelpers
- lldbPluginObjectFileELF
- lldbPluginObjectFileMachO
- lldbPluginSymbolFileDWARF
- lldbPluginSymbolFileSymtab
- lldbPluginTypeSystemClang
- LLVMTestingSupport
- )
-
-set(test_inputs
- inlined-functions.yaml
- )
-add_unittest_inputs(SymbolTests "${test_inputs}")
+++ /dev/null
---- !mach-o
-FileHeader:
- magic: 0xFEEDFACF
- cputype: 0x01000007
- cpusubtype: 0x00000003
- filetype: 0x00000001
- ncmds: 4
- sizeofcmds: 1160
- flags: 0x00002000
- reserved: 0x00000000
-LoadCommands:
- - cmd: LC_SEGMENT_64
- cmdsize: 1032
- segname: ''
- vmaddr: 0
- vmsize: 2022
- fileoff: 1192
- filesize: 2022
- maxprot: 7
- initprot: 7
- nsects: 6
- flags: 0
- Sections:
- - sectname: __text
- segname: __TEXT
- addr: 0x0000000000000000
- size: 224
- offset: 0x000004A8
- align: 4
- reloff: 0x00000C90
- nreloc: 1
- flags: 0x80000400
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - sectname: __debug_str
- segname: __DWARF
- addr: 0x00000000000000E0
- size: 223
- offset: 0x00000588
- align: 0
- reloff: 0x00000000
- nreloc: 0
- flags: 0x02000000
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - sectname: __debug_abbrev
- segname: __DWARF
- addr: 0x00000000000001BF
- size: 190
- offset: 0x00000667
- align: 0
- reloff: 0x00000000
- nreloc: 0
- flags: 0x02000000
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - sectname: __debug_info
- segname: __DWARF
- addr: 0x000000000000027D
- size: 583
- offset: 0x00000725
- align: 0
- reloff: 0x00000C98
- nreloc: 8
- flags: 0x02000000
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - sectname: __compact_unwind
- segname: __LD
- addr: 0x0000000000000670
- size: 64
- offset: 0x00000B18
- align: 3
- reloff: 0x00000CD8
- nreloc: 2
- flags: 0x02000000
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - sectname: __debug_line
- segname: __DWARF
- addr: 0x0000000000000718
- size: 206
- offset: 0x00000BC0
- align: 0
- reloff: 0x00000CE8
- nreloc: 1
- flags: 0x02000000
- reserved1: 0x00000000
- reserved2: 0x00000000
- reserved3: 0x00000000
- - cmd: LC_BUILD_VERSION
- cmdsize: 24
- platform: 1
- minos: 658944
- sdk: 658944
- ntools: 0
- - cmd: LC_SYMTAB
- cmdsize: 24
- symoff: 3312
- nsyms: 2
- stroff: 3344
- strsize: 20
- - cmd: LC_DYSYMTAB
- cmdsize: 80
- ilocalsym: 0
- nlocalsym: 0
- iextdefsym: 0
- nextdefsym: 2
- iundefsym: 2
- nundefsym: 0
- tocoff: 0
- ntoc: 0
- modtaboff: 0
- nmodtab: 0
- extrefsymoff: 0
- nextrefsyms: 0
- indirectsymoff: 0
- nindirectsyms: 0
- extreloff: 0
- nextrel: 0
- locreloff: 0
- nlocrel: 0
-LinkEditData:
- NameList:
- - n_strx: 7
- n_type: 0x0F
- n_sect: 1
- n_desc: 0
- n_value: 0
- - n_strx: 1
- n_type: 0x0F
- n_sect: 1
- n_desc: 0
- n_value: 32
- StringTable:
- - ''
- - _main
- - __Z4sum3iii
- - ''
-DWARF:
- debug_str:
- - 'Apple LLVM version 10.0.1 (clang-1001.0.46.3)'
- - inlined-functions.cpp
- - '/Users/aadsm/Projects/llvm-project/lldb/unittests/Symbol/Inputs'
- - sum3
- - _Z4sum3iii
- - _Z4sum2ii
- - sum2
- - int
- - a
- - b
- - result
- - _Z4sum4iiii
- - sum4
- - c
- - d
- - main
- - argc
- - argv
- - char
- - sum
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_producer
- Form: DW_FORM_strp
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_stmt_list
- Form: DW_FORM_sec_offset
- - Attribute: DW_AT_comp_dir
- Form: DW_FORM_strp
- - Attribute: DW_AT_low_pc
- Form: DW_FORM_addr
- - Attribute: DW_AT_high_pc
- Form: DW_FORM_data4
- - Code: 0x00000002
- Tag: DW_TAG_subprogram
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_low_pc
- Form: DW_FORM_addr
- - Attribute: DW_AT_high_pc
- Form: DW_FORM_data4
- - Attribute: DW_AT_frame_base
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_linkage_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Attribute: DW_AT_external
- Form: DW_FORM_flag_present
- - Code: 0x00000003
- Tag: DW_TAG_formal_parameter
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_location
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Code: 0x00000004
- Tag: DW_TAG_variable
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_location
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Code: 0x00000005
- Tag: DW_TAG_subprogram
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_linkage_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Attribute: DW_AT_external
- Form: DW_FORM_flag_present
- - Attribute: DW_AT_inline
- Form: DW_FORM_data1
- - Code: 0x00000006
- Tag: DW_TAG_formal_parameter
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Code: 0x00000007
- Tag: DW_TAG_variable
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Code: 0x00000008
- Tag: DW_TAG_base_type
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_encoding
- Form: DW_FORM_data1
- - Attribute: DW_AT_byte_size
- Form: DW_FORM_data1
- - Code: 0x00000009
- Tag: DW_TAG_subprogram
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_low_pc
- Form: DW_FORM_addr
- - Attribute: DW_AT_high_pc
- Form: DW_FORM_data4
- - Attribute: DW_AT_frame_base
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_name
- Form: DW_FORM_strp
- - Attribute: DW_AT_decl_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_decl_line
- Form: DW_FORM_data1
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- - Attribute: DW_AT_external
- Form: DW_FORM_flag_present
- - Code: 0x0000000A
- Tag: DW_TAG_inlined_subroutine
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_abstract_origin
- Form: DW_FORM_ref4
- - Attribute: DW_AT_low_pc
- Form: DW_FORM_addr
- - Attribute: DW_AT_high_pc
- Form: DW_FORM_data4
- - Attribute: DW_AT_call_file
- Form: DW_FORM_data1
- - Attribute: DW_AT_call_line
- Form: DW_FORM_data1
- - Code: 0x0000000B
- Tag: DW_TAG_formal_parameter
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_location
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_abstract_origin
- Form: DW_FORM_ref4
- - Code: 0x0000000C
- Tag: DW_TAG_variable
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_location
- Form: DW_FORM_exprloc
- - Attribute: DW_AT_abstract_origin
- Form: DW_FORM_ref4
- - Code: 0x0000000D
- Tag: DW_TAG_pointer_type
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_type
- Form: DW_FORM_ref4
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x0000000000000000
- - Value: 0x0000000000000004
- - Value: 0x000000000000002E
- - Value: 0x0000000000000000
- - Value: 0x0000000000000044
- - Value: 0x0000000000000000
- - Value: 0x00000000000000E0
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000000
- - Value: 0x000000000000001E
- - Value: 0x0000000000000001
- BlockData:
- - 0x56
- - Value: 0x0000000000000089
- - Value: 0x0000000000000084
- - Value: 0x0000000000000001
- - Value: 0x0000000000000006
- - Value: 0x00000000000000B2
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000003
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x7C
- - Value: 0x00000000000000A7
- - Value: 0x0000000000000001
- - Value: 0x0000000000000006
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000003
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x78
- - Value: 0x00000000000000A9
- - Value: 0x0000000000000001
- - Value: 0x0000000000000006
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000003
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x74
- - Value: 0x00000000000000C3
- - Value: 0x0000000000000001
- - Value: 0x0000000000000006
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000004
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x70
- - Value: 0x00000000000000AB
- - Value: 0x0000000000000001
- - Value: 0x0000000000000007
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000000
- - AbbrCode: 0x00000005
- Values:
- - Value: 0x0000000000000094
- - Value: 0x000000000000009E
- - Value: 0x0000000000000001
- - Value: 0x0000000000000001
- - Value: 0x00000000000000B2
- - Value: 0x0000000000000001
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000A7
- - Value: 0x0000000000000001
- - Value: 0x0000000000000001
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000A9
- - Value: 0x0000000000000001
- - Value: 0x0000000000000001
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000007
- Values:
- - Value: 0x00000000000000AB
- - Value: 0x0000000000000001
- - Value: 0x0000000000000002
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000000
- - AbbrCode: 0x00000008
- Values:
- - Value: 0x00000000000000A3
- - Value: 0x0000000000000005
- - Value: 0x0000000000000004
- - AbbrCode: 0x00000005
- Values:
- - Value: 0x00000000000000B2
- - Value: 0x00000000000000BE
- - Value: 0x0000000000000001
- - Value: 0x000000000000000B
- - Value: 0x00000000000000B2
- - Value: 0x0000000000000001
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000A7
- - Value: 0x0000000000000001
- - Value: 0x000000000000000B
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000A9
- - Value: 0x0000000000000001
- - Value: 0x000000000000000B
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000C3
- - Value: 0x0000000000000001
- - Value: 0x000000000000000B
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000006
- Values:
- - Value: 0x00000000000000C5
- - Value: 0x0000000000000001
- - Value: 0x000000000000000B
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000007
- Values:
- - Value: 0x00000000000000AB
- - Value: 0x0000000000000001
- - Value: 0x000000000000000C
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000000
- - AbbrCode: 0x00000009
- Values:
- - Value: 0x0000000000000020
- - Value: 0x00000000000000C0
- - Value: 0x0000000000000001
- BlockData:
- - 0x56
- - Value: 0x00000000000000C7
- - Value: 0x0000000000000001
- - Value: 0x0000000000000011
- - Value: 0x00000000000000B2
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000003
- Values:
- - Value: 0x0000000000000003
- BlockData:
- - 0x91
- - 0xB4
- - 0x7F
- - Value: 0x00000000000000CC
- - Value: 0x0000000000000001
- - Value: 0x0000000000000011
- - Value: 0x00000000000000B2
- - AbbrCode: 0x00000003
- Values:
- - Value: 0x0000000000000003
- BlockData:
- - 0x91
- - 0xA8
- - 0x7F
- - Value: 0x00000000000000D1
- - Value: 0x0000000000000001
- - Value: 0x0000000000000011
- - Value: 0x0000000000000235
- - AbbrCode: 0x00000004
- Values:
- - Value: 0x0000000000000003
- BlockData:
- - 0x91
- - 0xA4
- - 0x7F
- - Value: 0x00000000000000DB
- - Value: 0x0000000000000001
- - Value: 0x0000000000000013
- - Value: 0x00000000000000B2
- - AbbrCode: 0x0000000A
- Values:
- - Value: 0x0000000000000080
- - Value: 0x000000000000005A
- - Value: 0x0000000000000025
- - Value: 0x0000000000000001
- - Value: 0x0000000000000012
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x44
- - Value: 0x0000000000000090
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x40
- - Value: 0x000000000000009B
- - AbbrCode: 0x0000000C
- Values:
- - Value: 0x0000000000000003
- BlockData:
- - 0x91
- - 0xBC
- - 0x7F
- - Value: 0x00000000000000A6
- - AbbrCode: 0x00000000
- - AbbrCode: 0x0000000A
- Values:
- - Value: 0x00000000000000B9
- - Value: 0x000000000000007F
- - Value: 0x000000000000003C
- - Value: 0x0000000000000001
- - Value: 0x0000000000000013
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x64
- - Value: 0x00000000000000C9
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x60
- - Value: 0x00000000000000D4
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x5C
- - Value: 0x00000000000000DF
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x58
- - Value: 0x00000000000000EA
- - AbbrCode: 0x0000000C
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x54
- - Value: 0x00000000000000F5
- - AbbrCode: 0x0000000A
- Values:
- - Value: 0x0000000000000080
- - Value: 0x000000000000008B
- - Value: 0x000000000000000C
- - Value: 0x0000000000000001
- - Value: 0x000000000000000C
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x70
- - Value: 0x0000000000000090
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x6C
- - Value: 0x000000000000009B
- - AbbrCode: 0x0000000C
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x68
- - Value: 0x00000000000000A6
- - AbbrCode: 0x00000000
- - AbbrCode: 0x0000000A
- Values:
- - Value: 0x0000000000000080
- - Value: 0x00000000000000A3
- - Value: 0x0000000000000009
- - Value: 0x0000000000000001
- - Value: 0x000000000000000C
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x7C
- - Value: 0x0000000000000090
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x78
- - Value: 0x000000000000009B
- - AbbrCode: 0x0000000C
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x74
- - Value: 0x00000000000000A6
- - AbbrCode: 0x00000000
- - AbbrCode: 0x00000000
- - AbbrCode: 0x0000000A
- Values:
- - Value: 0x0000000000000080
- - Value: 0x00000000000000CC
- - Value: 0x0000000000000009
- - Value: 0x0000000000000001
- - Value: 0x0000000000000014
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x50
- - Value: 0x0000000000000090
- - AbbrCode: 0x0000000B
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x4C
- - Value: 0x000000000000009B
- - AbbrCode: 0x0000000C
- Values:
- - Value: 0x0000000000000002
- BlockData:
- - 0x91
- - 0x48
- - Value: 0x00000000000000A6
- - AbbrCode: 0x00000000
- - AbbrCode: 0x00000000
- - AbbrCode: 0x0000000D
- Values:
- - Value: 0x000000000000023A
- - AbbrCode: 0x0000000D
- Values:
- - Value: 0x000000000000023F
- - AbbrCode: 0x00000008
- Values:
- - Value: 0x00000000000000D6
- - Value: 0x0000000000000006
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000000
- debug_line:
- - Length: 202
- Version: 4
- PrologueLength: 45
- MinInstLength: 1
- MaxOpsPerInst: 1
- DefaultIsStmt: 1
- LineBase: 251
- LineRange: 14
- OpcodeBase: 13
- StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
- Files:
- - Name: inlined-functions.cpp
- DirIdx: 0
- ModTime: 0
- Length: 0
- Opcodes:
- - Opcode: DW_LNS_extended_op
- ExtLen: 9
- SubOpcode: DW_LNE_set_address
- Data: 0
- - Opcode: 0x17
- Data: 0
- - Opcode: DW_LNS_set_column
- Data: 18
- - Opcode: DW_LNS_set_prologue_end
- Data: 18
- - Opcode: 0xC9
- Data: 18
- - Opcode: DW_LNS_set_column
- Data: 20
- - Opcode: DW_LNS_negate_stmt
- Data: 20
- - Opcode: 0x3C
- Data: 20
- - Opcode: DW_LNS_set_column
- Data: 24
- - Opcode: 0x3C
- Data: 24
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 12
- - Opcode: DW_LNS_negate_stmt
- Data: 12
- - Opcode: 0x3D
- Data: 12
- - Opcode: DW_LNS_set_column
- Data: 5
- - Opcode: DW_LNS_negate_stmt
- Data: 5
- - Opcode: 0x3C
- Data: 5
- - Opcode: DW_LNS_set_column
- Data: 0
- - Opcode: DW_LNS_negate_stmt
- Data: 0
- - Opcode: DW_LNS_advance_line
- SData: 9
- Data: 0
- - Opcode: 0x4A
- Data: 0
- - Opcode: DW_LNS_set_column
- Data: 5
- - Opcode: DW_LNS_set_prologue_end
- Data: 5
- - Opcode: DW_LNS_const_add_pc
- Data: 5
- - Opcode: 0x59
- Data: 5
- - Opcode: DW_LNS_set_column
- Data: 18
- - Opcode: DW_LNS_advance_line
- SData: -16
- Data: 18
- - Opcode: DW_LNS_advance_pc
- Data: 36
- - Opcode: DW_LNS_copy
- Data: 36
- - Opcode: DW_LNS_set_column
- Data: 20
- - Opcode: DW_LNS_negate_stmt
- Data: 20
- - Opcode: 0x3C
- Data: 20
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 23
- - Opcode: DW_LNS_negate_stmt
- Data: 23
- - Opcode: DW_LNS_advance_line
- SData: 10
- Data: 23
- - Opcode: DW_LNS_const_add_pc
- Data: 23
- - Opcode: 0xD6
- Data: 23
- - Opcode: DW_LNS_set_column
- Data: 26
- - Opcode: DW_LNS_negate_stmt
- Data: 26
- - Opcode: 0x3C
- Data: 26
- - Opcode: DW_LNS_set_column
- Data: 18
- - Opcode: DW_LNS_negate_stmt
- Data: 18
- - Opcode: DW_LNS_advance_line
- SData: -10
- Data: 18
- - Opcode: 0x90
- Data: 18
- - Opcode: DW_LNS_set_column
- Data: 20
- - Opcode: DW_LNS_negate_stmt
- Data: 20
- - Opcode: 0x3C
- Data: 20
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 12
- - Opcode: DW_LNS_negate_stmt
- Data: 12
- - Opcode: 0x3D
- Data: 12
- - Opcode: DW_LNS_set_column
- Data: 36
- - Opcode: DW_LNS_advance_line
- SData: 9
- Data: 36
- - Opcode: 0x3C
- Data: 36
- - Opcode: DW_LNS_set_column
- Data: 39
- - Opcode: DW_LNS_negate_stmt
- Data: 39
- - Opcode: 0x3C
- Data: 39
- - Opcode: DW_LNS_set_column
- Data: 18
- - Opcode: DW_LNS_negate_stmt
- Data: 18
- - Opcode: DW_LNS_advance_line
- SData: -10
- Data: 18
- - Opcode: 0x90
- Data: 18
- - Opcode: DW_LNS_set_column
- Data: 20
- - Opcode: DW_LNS_negate_stmt
- Data: 20
- - Opcode: 0x3C
- Data: 20
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 29
- - Opcode: DW_LNS_negate_stmt
- Data: 29
- - Opcode: DW_LNS_advance_line
- SData: 10
- Data: 29
- - Opcode: 0x3C
- Data: 29
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: DW_LNS_negate_stmt
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 12
- - Opcode: DW_LNS_negate_stmt
- Data: 12
- - Opcode: 0x3D
- Data: 12
- - Opcode: 0x67
- Data: 12
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x41
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 18
- - Opcode: DW_LNS_advance_line
- SData: -17
- Data: 18
- - Opcode: DW_LNS_const_add_pc
- Data: 18
- - Opcode: 0x12
- Data: 18
- - Opcode: DW_LNS_set_column
- Data: 20
- - Opcode: DW_LNS_negate_stmt
- Data: 20
- - Opcode: 0x3C
- Data: 20
- - Opcode: DW_LNS_set_column
- Data: 9
- - Opcode: 0x3C
- Data: 9
- - Opcode: DW_LNS_set_column
- Data: 5
- - Opcode: DW_LNS_negate_stmt
- Data: 5
- - Opcode: DW_LNS_advance_line
- SData: 19
- Data: 5
- - Opcode: 0x3C
- Data: 5
- - Opcode: DW_LNS_advance_pc
- Data: 11
- - Opcode: DW_LNS_extended_op
- ExtLen: 1
- SubOpcode: DW_LNE_end_sequence
- Data: 11
-...
+++ /dev/null
-//===-- SymbolsTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/LocateSymbolFile.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/Reproducer.h"
-
-using namespace lldb_private;
-
-namespace {
-class SymbolsTest : public ::testing::Test {
-public:
- SubsystemRAII<repro::Reproducer, FileSystem, HostInfo> subsystems;
-};
-} // namespace
-
-TEST_F(
- SymbolsTest,
- TerminateLocateExecutableSymbolFileForUnknownExecutableAndUnknownSymbolFile) {
- ModuleSpec module_spec;
- FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
- FileSpec symbol_file_spec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
- EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
-}
-
-TEST_F(SymbolsTest,
- LocateExecutableSymbolFileForUnknownExecutableAndMissingSymbolFile) {
- ModuleSpec module_spec;
- // using a GUID here because the symbol file shouldn't actually exist on disk
- module_spec.GetSymbolFileSpec().SetFile(
- "4A524676-B24B-4F4E-968A-551D465EBAF1.so", FileSpec::Style::native);
- FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
- FileSpec symbol_file_spec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
- EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
-}
+++ /dev/null
-//===-- PostfixExpressionTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/PostfixExpression.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/raw_ostream.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::postfix;
-
-static std::string ToString(BinaryOpNode::OpType type) {
- switch (type) {
- case BinaryOpNode::Align:
- return "@";
- case BinaryOpNode::Minus:
- return "-";
- case BinaryOpNode::Plus:
- return "+";
- }
- llvm_unreachable("Fully covered switch!");
-}
-
-static std::string ToString(UnaryOpNode::OpType type) {
- switch (type) {
- case UnaryOpNode::Deref:
- return "^";
- }
- llvm_unreachable("Fully covered switch!");
-}
-
-struct ASTPrinter : public Visitor<std::string> {
-protected:
- std::string Visit(BinaryOpNode &binary, Node *&) override {
- return std::string(
- llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()),
- Dispatch(binary.Left()), Dispatch(binary.Right())));
- }
-
- std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; }
-
- std::string Visit(IntegerNode &integer, Node *&) override {
- return std::string(llvm::formatv("int({0})", integer.GetValue()));
- }
-
- std::string Visit(RegisterNode ®, Node *&) override {
- return std::string(llvm::formatv("reg({0})", reg.GetRegNum()));
- }
-
- std::string Visit(SymbolNode &symbol, Node *&) override {
- return std::string(symbol.GetName());
- }
-
- std::string Visit(UnaryOpNode &unary, Node *&) override {
- return std::string(llvm::formatv("{0}({1})", ToString(unary.GetOpType()),
- Dispatch(unary.Operand())));
- }
-
-public:
- static std::string Print(Node *node) {
- if (node)
- return ASTPrinter().Dispatch(node);
- return "nullptr";
- }
-};
-
-static std::string ParseOneAndStringify(llvm::StringRef expr) {
- llvm::BumpPtrAllocator alloc;
- return ASTPrinter::Print(ParseOneExpression(expr, alloc));
-}
-
-TEST(PostfixExpression, ParseOneExpression) {
- EXPECT_EQ("int(47)", ParseOneAndStringify("47"));
- EXPECT_EQ("$foo", ParseOneAndStringify("$foo"));
- EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +"));
- EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -"));
- EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @"));
- EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +"));
- EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +"));
- EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^"));
- EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^"));
- EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^"));
- EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -"));
- EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +"));
-
- EXPECT_EQ("nullptr", ParseOneAndStringify("+"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("^"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("1 +"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2"));
- EXPECT_EQ("nullptr", ParseOneAndStringify("1 2"));
- EXPECT_EQ("nullptr", ParseOneAndStringify(""));
-}
-
-static std::vector<std::pair<std::string, std::string>>
-ParseFPOAndStringify(llvm::StringRef prog) {
- llvm::BumpPtrAllocator alloc;
- std::vector<std::pair<llvm::StringRef, Node *>> parsed =
- ParseFPOProgram(prog, alloc);
- std::vector<std::pair<std::string, std::string>> result;
- for (const auto &p : parsed)
- result.emplace_back(p.first.str(), ASTPrinter::Print(p.second));
- return result;
-}
-
-TEST(PostfixExpression, ParseFPOProgram) {
- EXPECT_THAT(ParseFPOAndStringify("a 1 ="),
- testing::ElementsAre(std::make_pair("a", "int(1)")));
- EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="),
- testing::ElementsAre(std::make_pair("a", "int(1)"),
- std::make_pair("b", "+(int(2), int(3))")));
-
- EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty());
- EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty());
- EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty());
- EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty());
- EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty());
- EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty());
-}
-
-static std::string ParseAndGenerateDWARF(llvm::StringRef expr) {
- llvm::BumpPtrAllocator alloc;
- Node *ast = ParseOneExpression(expr, alloc);
- if (!ast)
- return "Parse failed.";
- if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * {
- if (symbol.GetName() == "INIT")
- return MakeNode<InitialValueNode>(alloc);
-
- uint32_t num;
- if (to_integer(symbol.GetName().drop_front(), num))
- return MakeNode<RegisterNode>(alloc, num);
- return nullptr;
- })) {
- return "Resolution failed.";
- }
-
- const size_t addr_size = 4;
- StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle);
- ToDWARF(*ast, dwarf);
-
- // print dwarf expression to comparable textual representation
- llvm::DataExtractor extractor(dwarf.GetString(), /*IsLittleEndian=*/true,
- addr_size);
-
- std::string result;
- llvm::raw_string_ostream os(result);
- llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32)
- .print(os, llvm::DIDumpOptions(), nullptr, nullptr);
- return std::move(os.str());
-}
-
-TEST(PostfixExpression, ToDWARF) {
- EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0"));
-
- EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1"));
-
- EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65"));
-
- EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT"));
-
- EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus",
- ParseAndGenerateDWARF("INIT INIT +"));
-
- EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus",
- ParseAndGenerateDWARF("R1 INIT +"));
-
- EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus",
- ParseAndGenerateDWARF("1 INIT ^ +"));
-
- EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus",
- ParseAndGenerateDWARF("4 5 +"));
-
- EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus",
- ParseAndGenerateDWARF("4 5 -"));
-
- EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^"));
-
- EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, "
- "DW_OP_not, DW_OP_and",
- ParseAndGenerateDWARF("R6 128 @"));
-}
+++ /dev/null
-//===-- TestClangASTImporter.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
-#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
-#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/Symbol/ClangTestUtils.h"
-#include "lldb/Core/Declaration.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "clang/AST/DeclCXX.h"
-
-using namespace clang;
-using namespace lldb;
-using namespace lldb_private;
-
-class TestClangASTImporter : public testing::Test {
-public:
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-};
-
-TEST_F(TestClangASTImporter, CanImportInvalidType) {
- ClangASTImporter importer;
- EXPECT_FALSE(importer.CanImport(CompilerType()));
-}
-
-TEST_F(TestClangASTImporter, ImportInvalidType) {
- ClangASTImporter importer;
- EXPECT_FALSE(importer.Import(CompilerType()));
-}
-
-TEST_F(TestClangASTImporter, CopyDeclTagDecl) {
- // Tests that the ClangASTImporter::CopyDecl can copy TagDecls.
- clang_utils::SourceASTWithRecord source;
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- clang::Decl *imported =
- importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
- ASSERT_NE(nullptr, imported);
-
- // Check that we got the correct decl by just comparing their qualified name.
- clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
- EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
- imported_tag_decl->getQualifiedNameAsString());
- // We did a minimal import of the tag decl.
- EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
-
- // Check that origin was set for the imported declaration.
- ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(imported);
- EXPECT_TRUE(origin.Valid());
- EXPECT_EQ(origin.ctx, &source.ast->getASTContext());
- EXPECT_EQ(origin.decl, source.record_decl);
-}
-
-TEST_F(TestClangASTImporter, CopyTypeTagDecl) {
- // Tests that the ClangASTImporter::CopyType can copy TagDecls types.
- clang_utils::SourceASTWithRecord source;
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- CompilerType imported = importer.CopyType(*target_ast, source.record_type);
- ASSERT_TRUE(imported.IsValid());
-
- // Check that we got the correct decl by just comparing their qualified name.
- clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
- EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
- imported_tag_decl->getQualifiedNameAsString());
- // We did a minimal import of the tag decl.
- EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
-
- // Check that origin was set for the imported declaration.
- ClangASTImporter::DeclOrigin origin =
- importer.GetDeclOrigin(imported_tag_decl);
- EXPECT_TRUE(origin.Valid());
- EXPECT_EQ(origin.ctx, &source.ast->getASTContext());
- EXPECT_EQ(origin.decl, source.record_decl);
-}
-
-TEST_F(TestClangASTImporter, CompleteFwdDeclWithOtherOrigin) {
- // Create an AST with a full type that is defined.
- clang_utils::SourceASTWithRecord source_with_definition;
-
- // Create an AST with a type thst is only a forward declaration with the
- // same name as the one in the other source.
- std::unique_ptr<TypeSystemClang> fwd_decl_source = clang_utils::createAST();
- CompilerType fwd_decl_type = clang_utils::createRecord(
- *fwd_decl_source, source_with_definition.record_decl->getName());
-
- // Create a target and import the forward decl.
- std::unique_ptr<TypeSystemClang> target = clang_utils::createAST();
- ClangASTImporter importer;
- CompilerType imported = importer.CopyType(*target, fwd_decl_type);
- ASSERT_TRUE(imported.IsValid());
- EXPECT_FALSE(imported.IsDefined());
-
- // Now complete the forward decl with the definition from the other source.
- // This should define the decl and give it the fields of the other origin.
- clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
- importer.CompleteTagDeclWithOrigin(imported_tag_decl,
- source_with_definition.record_decl);
- ASSERT_TRUE(imported.IsValid());
- EXPECT_TRUE(imported.IsDefined());
- EXPECT_EQ(1U, imported.GetNumFields());
-}
-
-TEST_F(TestClangASTImporter, DeportDeclTagDecl) {
- // Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.
- clang_utils::SourceASTWithRecord source;
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- clang::Decl *imported =
- importer.DeportDecl(&target_ast->getASTContext(), source.record_decl);
- ASSERT_NE(nullptr, imported);
-
- // Check that we got the correct decl by just comparing their qualified name.
- clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
- EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
- imported_tag_decl->getQualifiedNameAsString());
- // The record should be completed as we deported it.
- EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
-
- // Deporting doesn't update the origin map.
- EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
-}
-
-TEST_F(TestClangASTImporter, DeportTypeTagDecl) {
- // Tests that the ClangASTImporter::CopyType can deport TagDecl types.
- clang_utils::SourceASTWithRecord source;
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- CompilerType imported = importer.DeportType(*target_ast, source.record_type);
- ASSERT_TRUE(imported.IsValid());
-
- // Check that we got the correct decl by just comparing their qualified name.
- clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
- EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
- imported_tag_decl->getQualifiedNameAsString());
- // The record should be completed as we deported it.
- EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
-
- // Deporting doesn't update the origin map.
- EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
-}
-
-TEST_F(TestClangASTImporter, MetadataPropagation) {
- // Tests that AST metadata is propagated when copying declarations.
-
- clang_utils::SourceASTWithRecord source;
-
- const lldb::user_id_t metadata = 123456;
- source.ast->SetMetadataAsUserID(source.record_decl, metadata);
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- clang::Decl *imported =
- importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
- ASSERT_NE(nullptr, imported);
-
- // Check that we got the same Metadata.
- ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
- EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
-}
-
-TEST_F(TestClangASTImporter, MetadataPropagationIndirectImport) {
- // Tests that AST metadata is propagated when copying declarations when
- // importing one declaration into a temporary context and then to the
- // actual destination context.
-
- clang_utils::SourceASTWithRecord source;
-
- const lldb::user_id_t metadata = 123456;
- source.ast->SetMetadataAsUserID(source.record_decl, metadata);
-
- std::unique_ptr<TypeSystemClang> temporary_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- clang::Decl *temporary_imported =
- importer.CopyDecl(&temporary_ast->getASTContext(), source.record_decl);
- ASSERT_NE(nullptr, temporary_imported);
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
- clang::Decl *imported =
- importer.CopyDecl(&target_ast->getASTContext(), temporary_imported);
- ASSERT_NE(nullptr, imported);
-
- // Check that we got the same Metadata.
- ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
- EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
-}
-
-TEST_F(TestClangASTImporter, MetadataPropagationAfterCopying) {
- // Tests that AST metadata is propagated when copying declarations even
- // when the metadata was set after the declaration has already been copied.
-
- clang_utils::SourceASTWithRecord source;
- const lldb::user_id_t metadata = 123456;
-
- std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
-
- ClangASTImporter importer;
- clang::Decl *imported =
- importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
- ASSERT_NE(nullptr, imported);
-
- // The TagDecl has been imported. Now set the metadata of the source and
- // make sure the imported one will directly see it.
- source.ast->SetMetadataAsUserID(source.record_decl, metadata);
-
- // Check that we got the same Metadata.
- ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
- EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
-}
-
-TEST_F(TestClangASTImporter, RecordLayout) {
- // Test that it is possible to register RecordDecl layouts and then later
- // correctly retrieve them.
-
- clang_utils::SourceASTWithRecord source;
-
- ClangASTImporter importer;
- ClangASTImporter::LayoutInfo layout_info;
- layout_info.bit_size = 15;
- layout_info.alignment = 2;
- layout_info.field_offsets[source.field_decl] = 1;
- importer.SetRecordLayout(source.record_decl, layout_info);
-
- uint64_t bit_size;
- uint64_t alignment;
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
- importer.LayoutRecordType(source.record_decl, bit_size, alignment,
- field_offsets, base_offsets, vbase_offsets);
-
- EXPECT_EQ(15U, bit_size);
- EXPECT_EQ(2U, alignment);
- EXPECT_EQ(1U, field_offsets.size());
- EXPECT_EQ(1U, field_offsets[source.field_decl]);
- EXPECT_EQ(0U, base_offsets.size());
- EXPECT_EQ(0U, vbase_offsets.size());
-}
+++ /dev/null
-//===-- TestDWARFCallFrameInfo.cpp ----------------------------------------===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/Process/Utility/RegisterContext_x86.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/DWARFCallFrameInfo.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-class DWARFCallFrameInfoTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
- subsystems;
-
-protected:
- void TestBasic(DWARFCallFrameInfo::Type type, llvm::StringRef symbol);
-};
-
-namespace lldb_private {
-static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
- StreamString SS;
- row.Dump(SS, nullptr, nullptr, 0);
- return OS << SS.GetData();
-}
-} // namespace lldb_private
-
-static UnwindPlan::Row GetExpectedRow0() {
- UnwindPlan::Row row;
- row.SetOffset(0);
- row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8);
- row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
- return row;
-}
-
-static UnwindPlan::Row GetExpectedRow1() {
- UnwindPlan::Row row;
- row.SetOffset(1);
- row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
- row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
- row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
- return row;
-}
-
-static UnwindPlan::Row GetExpectedRow2() {
- UnwindPlan::Row row;
- row.SetOffset(4);
- row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16);
- row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
- row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
- return row;
-}
-
-void DWARFCallFrameInfoTest::TestBasic(DWARFCallFrameInfo::Type type,
- llvm::StringRef symbol) {
- auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_DYN
- Machine: EM_X86_64
- Entry: 0x0000000000000260
-Sections:
- - Name: .text
- Type: SHT_PROGBITS
- Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
- Address: 0x0000000000000260
- AddressAlign: 0x0000000000000010
- Content: 554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC3
-#0000000000000260 <eh_frame>:
-# 260: 55 push %rbp
-# 261: 48 89 e5 mov %rsp,%rbp
-# 264: 89 7d fc mov %edi,-0x4(%rbp)
-# 267: 8b 45 fc mov -0x4(%rbp),%eax
-# 26a: 5d pop %rbp
-# 26b: c3 retq
-# 26c: 0f 1f 40 00 nopl 0x0(%rax)
-#
-#0000000000000270 <debug_frame3>:
-# 270: 55 push %rbp
-# 271: 48 89 e5 mov %rsp,%rbp
-# 274: 89 7d fc mov %edi,-0x4(%rbp)
-# 277: 8b 45 fc mov -0x4(%rbp),%eax
-# 27a: 5d pop %rbp
-# 27b: c3 retq
-# 27c: 0f 1f 40 00 nopl 0x0(%rax)
-#
-#0000000000000280 <debug_frame4>:
-# 280: 55 push %rbp
-# 281: 48 89 e5 mov %rsp,%rbp
-# 284: 89 7d fc mov %edi,-0x4(%rbp)
-# 287: 8b 45 fc mov -0x4(%rbp),%eax
-# 28a: 5d pop %rbp
-# 28b: c3 retq
- - Name: .eh_frame
- Type: SHT_X86_64_UNWIND
- Flags: [ SHF_ALLOC ]
- Address: 0x0000000000000290
- AddressAlign: 0x0000000000000008
- Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000
-#00000000 0000000000000014 00000000 CIE
-# Version: 1
-# Augmentation: "zR"
-# Code alignment factor: 1
-# Data alignment factor: -8
-# Return address column: 16
-# Augmentation data: 1b
-#
-# DW_CFA_def_cfa: r7 (rsp) ofs 8
-# DW_CFA_offset: r16 (rip) at cfa-8
-# DW_CFA_nop
-# DW_CFA_nop
-#
-#00000018 000000000000001c 0000001c FDE cie=00000000 pc=ffffffffffffffd0..ffffffffffffffdc
-# DW_CFA_advance_loc: 1 to ffffffffffffffd1
-# DW_CFA_def_cfa_offset: 16
-# DW_CFA_offset: r6 (rbp) at cfa-16
-# DW_CFA_advance_loc: 3 to ffffffffffffffd4
-# DW_CFA_def_cfa_register: r6 (rbp)
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
- - Name: .debug_frame
- Type: SHT_PROGBITS
- AddressAlign: 0x0000000000000008
- Content: 14000000FFFFFFFF03000178100C070890010000000000001C0000000000000070020000000000000C00000000000000410E108602430D0614000000FFFFFFFF040008000178100C07089001000000001C0000003800000080020000000000000C00000000000000410E108602430D06
-#00000000 0000000000000014 ffffffff CIE
-# Version: 3
-# Augmentation: ""
-# Code alignment factor: 1
-# Data alignment factor: -8
-# Return address column: 16
-#
-# DW_CFA_def_cfa: r7 (rsp) ofs 8
-# DW_CFA_offset: r16 (rip) at cfa-8
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-#
-#00000018 000000000000001c 00000000 FDE cie=00000000 pc=0000000000000270..000000000000027c
-# DW_CFA_advance_loc: 1 to 0000000000000271
-# DW_CFA_def_cfa_offset: 16
-# DW_CFA_offset: r6 (rbp) at cfa-16
-# DW_CFA_advance_loc: 3 to 0000000000000274
-# DW_CFA_def_cfa_register: r6 (rbp)
-#
-#00000038 0000000000000014 ffffffff CIE
-# Version: 4
-# Augmentation: ""
-# Pointer Size: 8
-# Segment Size: 0
-# Code alignment factor: 1
-# Data alignment factor: -8
-# Return address column: 16
-#
-# DW_CFA_def_cfa: r7 (rsp) ofs 8
-# DW_CFA_offset: r16 (rip) at cfa-8
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-# DW_CFA_nop
-#
-#00000050 000000000000001c 00000038 FDE cie=00000038 pc=0000000000000280..000000000000028c
-# DW_CFA_advance_loc: 1 to 0000000000000281
-# DW_CFA_def_cfa_offset: 16
-# DW_CFA_offset: r6 (rbp) at cfa-16
-# DW_CFA_advance_loc: 3 to 0000000000000284
-# DW_CFA_def_cfa_register: r6 (rbp)
-Symbols:
- - Name: eh_frame
- Type: STT_FUNC
- Section: .text
- Value: 0x0000000000000260
- Size: 0x000000000000000C
- Binding: STB_GLOBAL
- - Name: debug_frame3
- Type: STT_FUNC
- Section: .text
- Value: 0x0000000000000270
- Size: 0x000000000000000C
- Binding: STB_GLOBAL
- - Name: debug_frame4
- Type: STT_FUNC
- Section: .text
- Value: 0x0000000000000280
- Size: 0x000000000000000C
- Binding: STB_GLOBAL
-...
-)");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
- auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
- SectionList *list = module_sp->GetSectionList();
- ASSERT_NE(nullptr, list);
-
- auto section_sp = list->FindSectionByType(type == DWARFCallFrameInfo::EH
- ? eSectionTypeEHFrame
- : eSectionTypeDWARFDebugFrame,
- false);
- ASSERT_NE(nullptr, section_sp);
-
- DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp, type);
-
- const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
- ConstString(symbol), eSymbolTypeAny);
- ASSERT_NE(nullptr, sym);
-
- UnwindPlan plan(eRegisterKindGeneric);
- ASSERT_TRUE(cfi.GetUnwindPlan(sym->GetAddress(), plan));
- ASSERT_EQ(3, plan.GetRowCount());
- EXPECT_EQ(GetExpectedRow0(), *plan.GetRowAtIndex(0));
- EXPECT_EQ(GetExpectedRow1(), *plan.GetRowAtIndex(1));
- EXPECT_EQ(GetExpectedRow2(), *plan.GetRowAtIndex(2));
-}
-
-TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
- TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame3");
-}
-
-TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
- TestBasic(DWARFCallFrameInfo::DWARF, "debug_frame4");
-}
-
-TEST_F(DWARFCallFrameInfoTest, Basic_eh) {
- TestBasic(DWARFCallFrameInfo::EH, "eh_frame");
-}
+++ /dev/null
-//===-- TestLineEntry.cpp -------------------------------------------------===//
-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include <iostream>
-
-#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
-#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/Module.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/CompileUnit.h"
-#include "lldb/Symbol/SymbolContext.h"
-
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-class LineEntryTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileMachO, SymbolFileDWARF,
- TypeSystemClang>
- subsystem;
-
-public:
- void SetUp() override;
-
-protected:
- llvm::Expected<LineEntry> GetLineEntryForLine(uint32_t line);
- llvm::Optional<TestFile> m_file;
- ModuleSP m_module_sp;
-};
-
-void LineEntryTest::SetUp() {
- auto ExpectedFile = TestFile::fromYamlFile("inlined-functions.yaml");
- ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
- m_file.emplace(std::move(*ExpectedFile));
- m_module_sp = std::make_shared<Module>(m_file->moduleSpec());
-}
-
-llvm::Expected<LineEntry> LineEntryTest::GetLineEntryForLine(uint32_t line) {
- // TODO: Handle SourceLocationSpec column information
- SymbolContextList sc_comp_units;
- SymbolContextList sc_line_entries;
- FileSpec file_spec("inlined-functions.cpp");
- m_module_sp->ResolveSymbolContextsForFileSpec(
- file_spec, line, /*check_inlines=*/true, lldb::eSymbolContextCompUnit,
- sc_comp_units);
- if (sc_comp_units.GetSize() == 0)
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "No comp unit found on the test object.");
-
- SourceLocationSpec location_spec(file_spec, line, /*column=*/llvm::None,
- /*check_inlines=*/true,
- /*exact_match=*/true);
-
- sc_comp_units[0].comp_unit->ResolveSymbolContext(
- location_spec, eSymbolContextLineEntry, sc_line_entries);
- if (sc_line_entries.GetSize() == 0)
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "No line entry found on the test object.");
- return sc_line_entries[0].line_entry;
-}
-
-TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNoInlines) {
- auto line_entry = GetLineEntryForLine(18);
- ASSERT_THAT_EXPECTED(line_entry, llvm::Succeeded());
- bool include_inlined_functions = false;
- auto range =
- line_entry->GetSameLineContiguousAddressRange(include_inlined_functions);
- ASSERT_EQ(range.GetByteSize(), (uint64_t)0x24);
-}
-
-TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeOneInline) {
- auto line_entry = GetLineEntryForLine(18);
- ASSERT_THAT_EXPECTED(line_entry, llvm::Succeeded());
- bool include_inlined_functions = true;
- auto range =
- line_entry->GetSameLineContiguousAddressRange(include_inlined_functions);
- ASSERT_EQ(range.GetByteSize(), (uint64_t)0x49);
-}
-
-TEST_F(LineEntryTest, GetSameLineContiguousAddressRangeNestedInline) {
- auto line_entry = GetLineEntryForLine(12);
- ASSERT_THAT_EXPECTED(line_entry, llvm::Succeeded());
- bool include_inlined_functions = true;
- auto range =
- line_entry->GetSameLineContiguousAddressRange(include_inlined_functions);
- ASSERT_EQ(range.GetByteSize(), (uint64_t)0x33);
-}
-
-/*
-# inlined-functions.cpp
-inline __attribute__((always_inline)) int sum2(int a, int b) {
- int result = a + b;
- return result;
-}
-
-int sum3(int a, int b, int c) {
- int result = a + b + c;
- return result;
-}
-
-inline __attribute__((always_inline)) int sum4(int a, int b, int c, int d) {
- int result = sum2(a, b) + sum2(c, d);
- result += 0;
- return result;
-}
-
-int main(int argc, char** argv) {
- sum3(3, 4, 5) + sum2(1, 2);
- int sum = sum4(1, 2, 3, 4);
- sum2(5, 6);
- return 0;
-}
-
-// g++ -c inlined-functions.cpp -o inlined-functions.o -g -Wno-unused-value
-// obj2yaml inlined-functions.o > inlined-functions.yaml
-
-# Dump of source line per address:
-# inlined-functions.cpp is src.cpp for space considerations.
-0x20: src.cpp:17
-0x21: src.cpp:17
-0x26: src.cpp:17
-0x27: src.cpp:17
-0x29: src.cpp:17
-0x2e: src.cpp:17
-0x2f: src.cpp:17
-0x31: src.cpp:17
-0x36: src.cpp:18
-0x37: src.cpp:18
-0x39: src.cpp:18
-0x3e: src.cpp:18
-0x3f: src.cpp:18
-0x41: src.cpp:18
-0x46: src.cpp:18
-0x47: src.cpp:18
-0x49: src.cpp:18
-0x4e: src.cpp:18
-0x4f: src.cpp:18
-0x51: src.cpp:18
-0x56: src.cpp:18
-0x57: src.cpp:18
-0x59: src.cpp:18
-0x5e: src.cpp:18 -> sum2@src.cpp:2
-0x5f: src.cpp:18 -> sum2@src.cpp:2
-0x61: src.cpp:18 -> sum2@src.cpp:2
-0x66: src.cpp:18 -> sum2@src.cpp:2
-0x67: src.cpp:18 -> sum2@src.cpp:2
-0x69: src.cpp:18 -> sum2@src.cpp:2
-0x6e: src.cpp:18 -> sum2@src.cpp:2
-0x6f: src.cpp:18 -> sum2@src.cpp:2
-0x71: src.cpp:18 -> sum2@src.cpp:2
-0x76: src.cpp:18 -> sum2@src.cpp:2
-0x77: src.cpp:18 -> sum2@src.cpp:2
-0x79: src.cpp:18 -> sum2@src.cpp:2
-0x7e: src.cpp:18 -> sum2@src.cpp:2
-0x7f: src.cpp:19 -> sum4@src.cpp:12
-0x81: src.cpp:19 -> sum4@src.cpp:12
-0x86: src.cpp:19 -> sum4@src.cpp:12
-0x87: src.cpp:19 -> sum4@src.cpp:12
-0x89: src.cpp:19 -> sum4@src.cpp:12
-0x8e: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0x8f: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0x91: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0x96: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:3
-0x97: src.cpp:19 -> sum4@src.cpp:12
-0x99: src.cpp:19 -> sum4@src.cpp:12
-0x9e: src.cpp:19 -> sum4@src.cpp:12
-0x9f: src.cpp:19 -> sum4@src.cpp:12
-0xa1: src.cpp:19 -> sum4@src.cpp:12
-0xa6: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0xa7: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0xa9: src.cpp:19 -> sum4@src.cpp:12 -> sum2@src.cpp:2
-0xae: src.cpp:19 -> sum4@src.cpp:12
-0xaf: src.cpp:19 -> sum4@src.cpp:12
-0xb1: src.cpp:19 -> sum4@src.cpp:12
-0xb6: src.cpp:19 -> sum4@src.cpp:13
-0xb7: src.cpp:19 -> sum4@src.cpp:13
-0xb9: src.cpp:19 -> sum4@src.cpp:14
-0xbe: src.cpp:19
-0xbf: src.cpp:19
-0xc1: src.cpp:19
-0xc6: src.cpp:19
-0xc7: src.cpp:19
-0xc9: src.cpp:19
-0xce: src.cpp:20 -> sum2@src.cpp:2
-0xcf: src.cpp:20 -> sum2@src.cpp:2
-0xd1: src.cpp:20 -> sum2@src.cpp:2
-0xd6: src.cpp:21
-0xd7: src.cpp:21
-0xd9: src.cpp:21
-0xde: src.cpp:21
-*/
+++ /dev/null
-//===-- TestType.cpp ------------------------------------------------------===//
-//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Symbol/Type.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace {
-void TestGetTypeScopeAndBasenameHelper(const char *full_type,
- bool expected_is_scoped,
- const char *expected_scope,
- const char *expected_name) {
- llvm::StringRef scope, name;
- lldb::TypeClass type_class;
- bool is_scoped =
- Type::GetTypeScopeAndBasename(full_type, scope, name, type_class);
- EXPECT_EQ(is_scoped, expected_is_scoped);
- if (expected_is_scoped) {
- EXPECT_EQ(scope, expected_scope);
- EXPECT_EQ(name, expected_name);
- }
-}
-}
-
-TEST(Type, GetTypeScopeAndBasename) {
- TestGetTypeScopeAndBasenameHelper("int", false, "", "");
- TestGetTypeScopeAndBasenameHelper("std::string", true, "std::", "string");
- TestGetTypeScopeAndBasenameHelper("std::set<int>", true, "std::", "set<int>");
- TestGetTypeScopeAndBasenameHelper("std::set<int, std::less<int>>", true,
- "std::", "set<int, std::less<int>>");
- TestGetTypeScopeAndBasenameHelper("std::string::iterator", true,
- "std::string::", "iterator");
- TestGetTypeScopeAndBasenameHelper("std::set<int>::iterator", true,
- "std::set<int>::", "iterator");
- TestGetTypeScopeAndBasenameHelper(
- "std::set<int, std::less<int>>::iterator", true,
- "std::set<int, std::less<int>>::", "iterator");
- TestGetTypeScopeAndBasenameHelper(
- "std::set<int, std::less<int>>::iterator<bool>", true,
- "std::set<int, std::less<int>>::", "iterator<bool>");
-}
-
-TEST(Type, CompilerContextPattern) {
- std::vector<CompilerContext> mms = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::Struct, ConstString("S")}};
- EXPECT_TRUE(contextMatches(mms, mms));
- std::vector<CompilerContext> mmc = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::Class, ConstString("S")}};
- EXPECT_FALSE(contextMatches(mms, mmc));
- std::vector<CompilerContext> ms = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Struct, ConstString("S")}};
- std::vector<CompilerContext> mas = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::AnyModule, ConstString("*")},
- {CompilerContextKind::Struct, ConstString("S")}};
- EXPECT_TRUE(contextMatches(mms, mas));
- EXPECT_TRUE(contextMatches(ms, mas));
- EXPECT_FALSE(contextMatches(mas, ms));
- std::vector<CompilerContext> mmms = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::Module, ConstString("C")},
- {CompilerContextKind::Struct, ConstString("S")}};
- EXPECT_TRUE(contextMatches(mmms, mas));
- std::vector<CompilerContext> mme = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::Enum, ConstString("S")}};
- std::vector<CompilerContext> mma = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::AnyType, ConstString("S")}};
- EXPECT_TRUE(contextMatches(mme, mma));
- EXPECT_TRUE(contextMatches(mms, mma));
- std::vector<CompilerContext> mme2 = {
- {CompilerContextKind::Module, ConstString("A")},
- {CompilerContextKind::Module, ConstString("B")},
- {CompilerContextKind::Enum, ConstString("S2")}};
- EXPECT_FALSE(contextMatches(mme2, mma));
-}
+++ /dev/null
-//===-- TestTypeSystem.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestingSupport/SubsystemRAII.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystem.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestTypeSystemMap : public testing::Test {
-public:
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-};
-
-TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithInvalidModule) {
- // GetTypeSystemForLanguage called with an invalid Module.
- TypeSystemMap map;
- Module module{ModuleSpec()};
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module,
- /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, &module,
- /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, &module,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
-}
-
-TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoModule) {
- // GetTypeSystemForLanguage called with no Module.
- TypeSystemMap map;
- Module *module = nullptr;
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module,
- /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, module, /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, module,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
-}
-
-TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoTarget) {
- // GetTypeSystemForLanguage called with no Target.
- TypeSystemMap map;
- Target *target = nullptr;
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target,
- /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist"));
-
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, target, /*can_create=*/true),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
- EXPECT_THAT_EXPECTED(
- map.GetTypeSystemForLanguage(eLanguageTypeC, target,
- /*can_create=*/false),
- llvm::FailedWithMessage("TypeSystem for language c doesn't exist"));
-}
+++ /dev/null
-//===-- TestTypeSystemClang.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/Symbol/ClangTestUtils.h"
-#include "lldb/Core/Declaration.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/ExprCXX.h"
-#include "gtest/gtest.h"
-
-using namespace clang;
-using namespace lldb;
-using namespace lldb_private;
-
-class TestTypeSystemClang : public testing::Test {
-public:
- SubsystemRAII<FileSystem, HostInfo> subsystems;
-
- void SetUp() override {
- m_ast.reset(
- new TypeSystemClang("test ASTContext", HostInfo::GetTargetTriple()));
- }
-
- void TearDown() override { m_ast.reset(); }
-
-protected:
- std::unique_ptr<TypeSystemClang> m_ast;
-
- QualType GetBasicQualType(BasicType type) const {
- return ClangUtil::GetQualType(m_ast->GetBasicTypeFromAST(type));
- }
-
- QualType GetBasicQualType(const char *name) const {
- return ClangUtil::GetQualType(
- m_ast->GetBuiltinTypeByName(ConstString(name)));
- }
-};
-
-TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) {
- clang::ASTContext &context = m_ast->getASTContext();
-
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeBool), context.BoolTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeChar), context.CharTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeChar16),
- context.Char16Ty));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeChar32),
- context.Char32Ty));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeDouble),
- context.DoubleTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeDoubleComplex),
- context.DoubleComplexTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeFloat), context.FloatTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeFloatComplex),
- context.FloatComplexTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeHalf), context.HalfTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeInt), context.IntTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeInt128),
- context.Int128Ty));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeLong), context.LongTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeLongDouble),
- context.LongDoubleTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex),
- context.LongDoubleComplexTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeLongLong),
- context.LongLongTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeNullPtr),
- context.NullPtrTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCClass),
- context.getObjCClassType()));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCID),
- context.getObjCIdType()));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeObjCSel),
- context.getObjCSelType()));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeShort), context.ShortTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeSignedChar),
- context.SignedCharTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedChar),
- context.UnsignedCharTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedInt),
- context.UnsignedIntTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128),
- context.UnsignedInt128Ty));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedLong),
- context.UnsignedLongTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong),
- context.UnsignedLongLongTy));
- EXPECT_TRUE(context.hasSameType(GetBasicQualType(eBasicTypeUnsignedShort),
- context.UnsignedShortTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeVoid), context.VoidTy));
- EXPECT_TRUE(
- context.hasSameType(GetBasicQualType(eBasicTypeWChar), context.WCharTy));
-}
-
-TEST_F(TestTypeSystemClang, TestGetBasicTypeFromName) {
- EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar),
- GetBasicQualType("signed char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar),
- GetBasicQualType("unsigned char"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar),
- GetBasicQualType("signed wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar),
- GetBasicQualType("unsigned wchar_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort),
- GetBasicQualType("unsigned short"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort),
- GetBasicQualType("unsigned short int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt),
- GetBasicQualType("unsigned int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt),
- GetBasicQualType("unsigned"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong),
- GetBasicQualType("unsigned long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong),
- GetBasicQualType("unsigned long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong),
- GetBasicQualType("long long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong),
- GetBasicQualType("long long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong),
- GetBasicQualType("unsigned long long"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong),
- GetBasicQualType("unsigned long long int"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128),
- GetBasicQualType("__uint128_t"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble),
- GetBasicQualType("long double"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL"));
- EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr"));
-}
-
-void VerifyEncodingAndBitSize(TypeSystemClang &clang_context,
- lldb::Encoding encoding, unsigned int bit_size) {
- clang::ASTContext &context = clang_context.getASTContext();
-
- CompilerType type =
- clang_context.GetBuiltinTypeForEncodingAndBitSize(encoding, bit_size);
- EXPECT_TRUE(type.IsValid());
-
- QualType qtype = ClangUtil::GetQualType(type);
- EXPECT_FALSE(qtype.isNull());
- if (qtype.isNull())
- return;
-
- uint64_t actual_size = context.getTypeSize(qtype);
- EXPECT_EQ(bit_size, actual_size);
-
- const clang::Type *type_ptr = qtype.getTypePtr();
- EXPECT_NE(nullptr, type_ptr);
- if (!type_ptr)
- return;
-
- EXPECT_TRUE(type_ptr->isBuiltinType());
- switch (encoding) {
- case eEncodingSint:
- EXPECT_TRUE(type_ptr->isSignedIntegerType());
- break;
- case eEncodingUint:
- EXPECT_TRUE(type_ptr->isUnsignedIntegerType());
- break;
- case eEncodingIEEE754:
- EXPECT_TRUE(type_ptr->isFloatingType());
- break;
- default:
- FAIL() << "Unexpected encoding";
- break;
- }
-}
-
-TEST_F(TestTypeSystemClang, TestBuiltinTypeForEncodingAndBitSize) {
- // Make sure we can get types of every possible size in every possible
- // encoding.
- // We can't make any guarantee about which specific type we get, because the
- // standard
- // isn't that specific. We only need to make sure the compiler hands us some
- // type that
- // is both a builtin type and matches the requested bit size.
- VerifyEncodingAndBitSize(*m_ast, eEncodingSint, 8);
- VerifyEncodingAndBitSize(*m_ast, eEncodingSint, 16);
- VerifyEncodingAndBitSize(*m_ast, eEncodingSint, 32);
- VerifyEncodingAndBitSize(*m_ast, eEncodingSint, 64);
- VerifyEncodingAndBitSize(*m_ast, eEncodingSint, 128);
-
- VerifyEncodingAndBitSize(*m_ast, eEncodingUint, 8);
- VerifyEncodingAndBitSize(*m_ast, eEncodingUint, 16);
- VerifyEncodingAndBitSize(*m_ast, eEncodingUint, 32);
- VerifyEncodingAndBitSize(*m_ast, eEncodingUint, 64);
- VerifyEncodingAndBitSize(*m_ast, eEncodingUint, 128);
-
- VerifyEncodingAndBitSize(*m_ast, eEncodingIEEE754, 32);
- VerifyEncodingAndBitSize(*m_ast, eEncodingIEEE754, 64);
-}
-
-TEST_F(TestTypeSystemClang, TestDisplayName) {
- TypeSystemClang ast("some name", llvm::Triple());
- EXPECT_EQ("some name", ast.getDisplayName());
-}
-
-TEST_F(TestTypeSystemClang, TestDisplayNameEmpty) {
- TypeSystemClang ast("", llvm::Triple());
- EXPECT_EQ("", ast.getDisplayName());
-}
-
-TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeInvalid) {
- EXPECT_FALSE(m_ast->GetEnumerationIntegerType(CompilerType()).IsValid());
-}
-
-TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeUnexpectedType) {
- CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
- CompilerType t = m_ast->GetEnumerationIntegerType(int_type);
- EXPECT_FALSE(t.IsValid());
-}
-
-TEST_F(TestTypeSystemClang, TestGetEnumIntegerTypeBasicTypes) {
- // All possible underlying integer types of enums.
- const std::vector<lldb::BasicType> types_to_test = {
- eBasicTypeInt, eBasicTypeUnsignedInt, eBasicTypeLong,
- eBasicTypeUnsignedLong, eBasicTypeLongLong, eBasicTypeUnsignedLongLong,
- };
-
- for (bool scoped : {true, false}) {
- SCOPED_TRACE("scoped: " + std::to_string(scoped));
- for (lldb::BasicType basic_type : types_to_test) {
- SCOPED_TRACE(std::to_string(basic_type));
-
- TypeSystemClang ast("enum_ast", HostInfo::GetTargetTriple());
- CompilerType basic_compiler_type = ast.GetBasicType(basic_type);
- EXPECT_TRUE(basic_compiler_type.IsValid());
-
- CompilerType enum_type = ast.CreateEnumerationType(
- "my_enum", ast.GetTranslationUnitDecl(), OptionalClangModuleID(),
- Declaration(), basic_compiler_type, scoped);
-
- CompilerType t = ast.GetEnumerationIntegerType(enum_type);
- // Check that the type we put in at the start is found again.
- EXPECT_EQ(basic_compiler_type.GetTypeName(), t.GetTypeName());
- }
- }
-}
-
-TEST_F(TestTypeSystemClang, TestOwningModule) {
- TypeSystemClang ast("module_ast", HostInfo::GetTargetTriple());
- CompilerType basic_compiler_type = ast.GetBasicType(BasicType::eBasicTypeInt);
- CompilerType enum_type = ast.CreateEnumerationType(
- "my_enum", ast.GetTranslationUnitDecl(), OptionalClangModuleID(100),
- Declaration(), basic_compiler_type, false);
- auto *ed = TypeSystemClang::GetAsEnumDecl(enum_type);
- EXPECT_FALSE(!ed);
- EXPECT_EQ(ed->getOwningModuleID(), 100u);
-
- CompilerType record_type = ast.CreateRecordType(
- nullptr, OptionalClangModuleID(200), lldb::eAccessPublic, "FooRecord",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- auto *rd = TypeSystemClang::GetAsRecordDecl(record_type);
- EXPECT_FALSE(!rd);
- EXPECT_EQ(rd->getOwningModuleID(), 200u);
-
- CompilerType class_type =
- ast.CreateObjCClass("objc_class", ast.GetTranslationUnitDecl(),
- OptionalClangModuleID(300), false, false);
- auto *cd = TypeSystemClang::GetAsObjCInterfaceDecl(class_type);
- EXPECT_FALSE(!cd);
- EXPECT_EQ(cd->getOwningModuleID(), 300u);
-}
-
-TEST_F(TestTypeSystemClang, TestIsClangType) {
- clang::ASTContext &context = m_ast->getASTContext();
- lldb::opaque_compiler_type_t bool_ctype =
- TypeSystemClang::GetOpaqueCompilerType(&context, lldb::eBasicTypeBool);
- CompilerType bool_type(m_ast.get(), bool_ctype);
- CompilerType record_type = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(100), lldb::eAccessPublic, "FooRecord",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- // Clang builtin type and record type should pass
- EXPECT_TRUE(ClangUtil::IsClangType(bool_type));
- EXPECT_TRUE(ClangUtil::IsClangType(record_type));
-
- // Default constructed type should fail
- EXPECT_FALSE(ClangUtil::IsClangType(CompilerType()));
-}
-
-TEST_F(TestTypeSystemClang, TestRemoveFastQualifiers) {
- CompilerType record_type = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "FooRecord",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- QualType qt;
-
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_EQ(0u, qt.getLocalFastQualifiers());
- record_type = record_type.AddConstModifier();
- record_type = record_type.AddVolatileModifier();
- record_type = record_type.AddRestrictModifier();
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_NE(0u, qt.getLocalFastQualifiers());
- record_type = ClangUtil::RemoveFastQualifiers(record_type);
- qt = ClangUtil::GetQualType(record_type);
- EXPECT_EQ(0u, qt.getLocalFastQualifiers());
-}
-
-TEST_F(TestTypeSystemClang, TestConvertAccessTypeToAccessSpecifier) {
- EXPECT_EQ(AS_none,
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(eAccessNone));
- EXPECT_EQ(AS_none, TypeSystemClang::ConvertAccessTypeToAccessSpecifier(
- eAccessPackage));
- EXPECT_EQ(AS_public,
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(eAccessPublic));
- EXPECT_EQ(AS_private, TypeSystemClang::ConvertAccessTypeToAccessSpecifier(
- eAccessPrivate));
- EXPECT_EQ(AS_protected, TypeSystemClang::ConvertAccessTypeToAccessSpecifier(
- eAccessProtected));
-}
-
-TEST_F(TestTypeSystemClang, TestUnifyAccessSpecifiers) {
- // Unifying two of the same type should return the same type
- EXPECT_EQ(AS_public,
- TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_public));
- EXPECT_EQ(AS_private,
- TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_private));
- EXPECT_EQ(AS_protected,
- TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_protected));
-
- // Otherwise the result should be the strictest of the two.
- EXPECT_EQ(AS_private,
- TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_public));
- EXPECT_EQ(AS_private,
- TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_protected));
- EXPECT_EQ(AS_private,
- TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_private));
- EXPECT_EQ(AS_private,
- TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_private));
- EXPECT_EQ(AS_protected,
- TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_public));
- EXPECT_EQ(AS_protected,
- TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_protected));
-
- // None is stricter than everything (by convention)
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_public));
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_protected));
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_none, AS_private));
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_public, AS_none));
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_protected, AS_none));
- EXPECT_EQ(AS_none,
- TypeSystemClang::UnifyAccessSpecifiers(AS_private, AS_none));
-}
-
-TEST_F(TestTypeSystemClang, TestRecordHasFields) {
- CompilerType int_type = m_ast->GetBasicType(eBasicTypeInt);
-
- // Test that a record with no fields returns false
- CompilerType empty_base = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyBase",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- TypeSystemClang::StartTagDeclarationDefinition(empty_base);
- TypeSystemClang::CompleteTagDeclarationDefinition(empty_base);
-
- RecordDecl *empty_base_decl = TypeSystemClang::GetAsRecordDecl(empty_base);
- EXPECT_NE(nullptr, empty_base_decl);
- EXPECT_FALSE(TypeSystemClang::RecordHasFields(empty_base_decl));
-
- // Test that a record with direct fields returns true
- CompilerType non_empty_base = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "NonEmptyBase",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- TypeSystemClang::StartTagDeclarationDefinition(non_empty_base);
- FieldDecl *non_empty_base_field_decl = m_ast->AddFieldToRecordType(
- non_empty_base, "MyField", int_type, eAccessPublic, 0);
- TypeSystemClang::CompleteTagDeclarationDefinition(non_empty_base);
- RecordDecl *non_empty_base_decl =
- TypeSystemClang::GetAsRecordDecl(non_empty_base);
- EXPECT_NE(nullptr, non_empty_base_decl);
- EXPECT_NE(nullptr, non_empty_base_field_decl);
- EXPECT_TRUE(TypeSystemClang::RecordHasFields(non_empty_base_decl));
-
- std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
-
- // Test that a record with no direct fields, but fields in a base returns true
- CompilerType empty_derived = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- TypeSystemClang::StartTagDeclarationDefinition(empty_derived);
- std::unique_ptr<clang::CXXBaseSpecifier> non_empty_base_spec =
- m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(),
- lldb::eAccessPublic, false, false);
- bases.push_back(std::move(non_empty_base_spec));
- bool result = m_ast->TransferBaseClasses(empty_derived.GetOpaqueQualType(),
- std::move(bases));
- TypeSystemClang::CompleteTagDeclarationDefinition(empty_derived);
- EXPECT_TRUE(result);
- CXXRecordDecl *empty_derived_non_empty_base_cxx_decl =
- m_ast->GetAsCXXRecordDecl(empty_derived.GetOpaqueQualType());
- RecordDecl *empty_derived_non_empty_base_decl =
- TypeSystemClang::GetAsRecordDecl(empty_derived);
- EXPECT_EQ(1u, TypeSystemClang::GetNumBaseClasses(
- empty_derived_non_empty_base_cxx_decl, false));
- EXPECT_TRUE(
- TypeSystemClang::RecordHasFields(empty_derived_non_empty_base_decl));
-
- // Test that a record with no direct fields, but fields in a virtual base
- // returns true
- CompilerType empty_derived2 = m_ast->CreateRecordType(
- nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived2",
- clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr);
- TypeSystemClang::StartTagDeclarationDefinition(empty_derived2);
- std::unique_ptr<CXXBaseSpecifier> non_empty_vbase_spec =
- m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(),
- lldb::eAccessPublic, true, false);
- bases.push_back(std::move(non_empty_vbase_spec));
- result = m_ast->TransferBaseClasses(empty_derived2.GetOpaqueQualType(),
- std::move(bases));
- TypeSystemClang::CompleteTagDeclarationDefinition(empty_derived2);
- EXPECT_TRUE(result);
- CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl =
- m_ast->GetAsCXXRecordDecl(empty_derived2.GetOpaqueQualType());
- RecordDecl *empty_derived_non_empty_vbase_decl =
- TypeSystemClang::GetAsRecordDecl(empty_derived2);
- EXPECT_EQ(1u, TypeSystemClang::GetNumBaseClasses(
- empty_derived_non_empty_vbase_cxx_decl, false));
- EXPECT_TRUE(
- TypeSystemClang::RecordHasFields(empty_derived_non_empty_vbase_decl));
-}
-
-TEST_F(TestTypeSystemClang, TemplateArguments) {
- TypeSystemClang::TemplateParameterInfos infos;
- infos.names.push_back("T");
- infos.args.push_back(TemplateArgument(m_ast->getASTContext().IntTy));
- infos.names.push_back("I");
- llvm::APSInt arg(llvm::APInt(8, 47));
- infos.args.push_back(TemplateArgument(m_ast->getASTContext(), arg,
- m_ast->getASTContext().IntTy));
-
- // template<typename T, int I> struct foo;
- ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl(
- m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic,
- "foo", TTK_Struct, infos);
- ASSERT_NE(decl, nullptr);
-
- // foo<int, 47>
- ClassTemplateSpecializationDecl *spec_decl =
- m_ast->CreateClassTemplateSpecializationDecl(
- m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), decl,
- TTK_Struct, infos);
- ASSERT_NE(spec_decl, nullptr);
- CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl);
- ASSERT_TRUE(type);
- m_ast->StartTagDeclarationDefinition(type);
- m_ast->CompleteTagDeclarationDefinition(type);
-
- // typedef foo<int, 47> foo_def;
- CompilerType typedef_type = type.CreateTypedef(
- "foo_def", m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), 0);
-
- CompilerType auto_type(
- m_ast.get(),
- m_ast->getASTContext()
- .getAutoType(ClangUtil::GetCanonicalQualType(typedef_type),
- clang::AutoTypeKeyword::Auto, false)
- .getAsOpaquePtr());
-
- CompilerType int_type(m_ast.get(),
- m_ast->getASTContext().IntTy.getAsOpaquePtr());
- for (CompilerType t : {type, typedef_type, auto_type}) {
- SCOPED_TRACE(t.GetTypeName().AsCString());
-
- EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 0),
- eTemplateArgumentKindType);
- EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 0),
- int_type);
- EXPECT_EQ(llvm::None,
- m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 0));
-
- EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 1),
- eTemplateArgumentKindIntegral);
- EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 1),
- CompilerType());
- auto result = m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 1);
- ASSERT_NE(llvm::None, result);
- EXPECT_EQ(arg, result->value);
- EXPECT_EQ(int_type, result->type);
- }
-}
-
-class TestCreateClassTemplateDecl : public TestTypeSystemClang {
-protected:
- /// The class templates created so far by the Expect* functions below.
- llvm::DenseSet<ClassTemplateDecl *> m_created_templates;
-
- /// Utility function for creating a class template.
- ClassTemplateDecl *
- CreateClassTemplate(const TypeSystemClang::TemplateParameterInfos &infos) {
- ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl(
- m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic,
- "foo", TTK_Struct, infos);
- return decl;
- }
-
- /// Creates a new class template with the given template parameters.
- /// Asserts that a new ClassTemplateDecl is created.
- /// \param description The gtest scope string that should describe the input.
- /// \param infos The template parameters that the class template should have.
- /// \returns The created ClassTemplateDecl.
- ClassTemplateDecl *
- ExpectNewTemplate(std::string description,
- const TypeSystemClang::TemplateParameterInfos &infos) {
- SCOPED_TRACE(description);
- ClassTemplateDecl *first_template = CreateClassTemplate(infos);
- // A new template should have been created.
- EXPECT_FALSE(m_created_templates.contains(first_template))
- << "Didn't create new class template but reused this existing decl:\n"
- << ClangUtil::DumpDecl(first_template);
- m_created_templates.insert(first_template);
-
- // Creating a new template with the same arguments should always return
- // the template created above.
- ClassTemplateDecl *second_template = CreateClassTemplate(infos);
- EXPECT_EQ(first_template, second_template)
- << "Second attempt to create class template didn't reuse first decl:\n"
- << ClangUtil::DumpDecl(first_template) << "\nInstead created/reused:\n"
- << ClangUtil::DumpDecl(second_template);
- return first_template;
- }
-
- /// Tries to create a new class template but asserts that an existing class
- /// template in the current AST is reused (in contract so a new class
- /// template being created).
- /// \param description The gtest scope string that should describe the input.
- /// \param infos The template parameters that the class template should have.
- void
- ExpectReusedTemplate(std::string description,
- const TypeSystemClang::TemplateParameterInfos &infos,
- ClassTemplateDecl *expected) {
- SCOPED_TRACE(description);
- ClassTemplateDecl *td = CreateClassTemplate(infos);
- EXPECT_EQ(td, expected)
- << "Created/reused class template is:\n"
- << ClangUtil::DumpDecl(td) << "\nExpected to reuse:\n"
- << ClangUtil::DumpDecl(expected);
- }
-};
-
-TEST_F(TestCreateClassTemplateDecl, FindExistingTemplates) {
- // This tests the logic in TypeSystemClang::CreateClassTemplateDecl that
- // decides whether an existing ClassTemplateDecl in the AST can be reused.
- // The behaviour should follow the C++ rules for redeclaring templates
- // (e.g., parameter names can be changed/omitted.)
-
- // This describes a class template *instantiation* from which we will infer
- // the structure of the class template.
- TypeSystemClang::TemplateParameterInfos infos;
-
- // Test an empty template parameter list: <>
- ExpectNewTemplate("<>", infos);
-
- // Test that <typename T> with T = int creates a new template.
- infos.names = {"T"};
- infos.args = {TemplateArgument(m_ast->getASTContext().IntTy)};
- ClassTemplateDecl *single_type_arg = ExpectNewTemplate("<typename T>", infos);
-
- // Test that changing the parameter name doesn't create a new class template.
- infos.names = {"A"};
- ExpectReusedTemplate("<typename A> (A = int)", infos, single_type_arg);
-
- // Test that changing the used type doesn't create a new class template.
- infos.args = {TemplateArgument(m_ast->getASTContext().FloatTy)};
- ExpectReusedTemplate("<typename A> (A = float)", infos, single_type_arg);
-
- // Test that <typename A, signed char I> creates a new template with A = int
- // and I = 47;
- infos.names.push_back("I");
- infos.args.push_back(TemplateArgument(m_ast->getASTContext(),
- llvm::APSInt(llvm::APInt(8, 47)),
- m_ast->getASTContext().SignedCharTy));
- ClassTemplateDecl *type_and_char_value =
- ExpectNewTemplate("<typename A, signed char I> (I = 47)", infos);
-
- // Change the value of the I parameter to 123. The previously created
- // class template should still be reused.
- infos.args.pop_back();
- infos.args.push_back(TemplateArgument(m_ast->getASTContext(),
- llvm::APSInt(llvm::APInt(8, 123)),
- m_ast->getASTContext().SignedCharTy));
- ExpectReusedTemplate("<typename A, signed char I> (I = 123)", infos,
- type_and_char_value);
-
- // Change the type of the I parameter to int so we have <typename A, int I>.
- // The class template from above can't be reused.
- infos.args.pop_back();
- infos.args.push_back(TemplateArgument(m_ast->getASTContext(),
- llvm::APSInt(llvm::APInt(32, 47)),
- m_ast->getASTContext().IntTy));
- ExpectNewTemplate("<typename A, int I> (I = 123)", infos);
-
- // Test a second type parameter will also cause a new template to be created.
- // We now have <typename A, int I, typename B>.
- infos.names.push_back("B");
- infos.args.push_back(TemplateArgument(m_ast->getASTContext().IntTy));
- ClassTemplateDecl *type_and_char_value_and_type =
- ExpectNewTemplate("<typename A, int I, typename B>", infos);
-
- // Remove all the names from the parameters which shouldn't influence the
- // way the templates get merged.
- infos.names = {"", "", ""};
- ExpectReusedTemplate("<typename, int, typename>", infos,
- type_and_char_value_and_type);
-}
-
-TEST_F(TestCreateClassTemplateDecl, FindExistingTemplatesWithParameterPack) {
- // The same as FindExistingTemplates but for templates with parameter packs.
-
- TypeSystemClang::TemplateParameterInfos infos;
- infos.packed_args =
- std::make_unique<TypeSystemClang::TemplateParameterInfos>();
- infos.packed_args->names = {"", ""};
- infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy),
- TemplateArgument(m_ast->getASTContext().IntTy)};
- ClassTemplateDecl *type_pack =
- ExpectNewTemplate("<typename ...> (int, int)", infos);
-
- // Special case: An instantiation for a parameter pack with no values fits
- // to whatever class template we find. There isn't enough information to
- // do an actual comparison here.
- infos.packed_args =
- std::make_unique<TypeSystemClang::TemplateParameterInfos>();
- ExpectReusedTemplate("<...> (no values in pack)", infos, type_pack);
-
- // Change the type content of pack type values.
- infos.packed_args->names = {"", ""};
- infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy),
- TemplateArgument(m_ast->getASTContext().LongTy)};
- ExpectReusedTemplate("<typename ...> (int, long)", infos, type_pack);
-
- // Change the number of pack values.
- infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy)};
- ExpectReusedTemplate("<typename ...> (int)", infos, type_pack);
-
- // The names of the pack values shouldn't matter.
- infos.packed_args->names = {"A", "B"};
- ExpectReusedTemplate("<typename ...> (int)", infos, type_pack);
-
- // Changing the kind of template argument will create a new template.
- infos.packed_args->args = {TemplateArgument(m_ast->getASTContext(),
- llvm::APSInt(llvm::APInt(32, 1)),
- m_ast->getASTContext().IntTy)};
- ClassTemplateDecl *int_pack = ExpectNewTemplate("<int ...> (int = 1)", infos);
-
- // Changing the value of integral parameters will not create a new template.
- infos.packed_args->args = {TemplateArgument(
- m_ast->getASTContext(), llvm::APSInt(llvm::APInt(32, 123)),
- m_ast->getASTContext().IntTy)};
- ExpectReusedTemplate("<int ...> (int = 123)", infos, int_pack);
-
- // Changing the integral type will create a new template.
- infos.packed_args->args = {TemplateArgument(m_ast->getASTContext(),
- llvm::APSInt(llvm::APInt(64, 1)),
- m_ast->getASTContext().LongTy)};
- ExpectNewTemplate("<long ...> (long = 1)", infos);
-
- // Prependinding a non-pack parameter will create a new template.
- infos.names = {"T"};
- infos.args = {TemplateArgument(m_ast->getASTContext().IntTy)};
- ExpectNewTemplate("<typename T, long...> (T = int, long = 1)", infos);
-}
-
-TEST_F(TestTypeSystemClang, OnlyPackName) {
- TypeSystemClang::TemplateParameterInfos infos;
- infos.pack_name = "A";
- EXPECT_FALSE(infos.IsValid());
-}
-
-static QualType makeConstInt(clang::ASTContext &ctxt) {
- QualType result(ctxt.IntTy);
- result.addConst();
- return result;
-}
-
-TEST_F(TestTypeSystemClang, TestGetTypeClassDeclType) {
- clang::ASTContext &ctxt = m_ast->getASTContext();
- auto *nullptr_expr = new (ctxt) CXXNullPtrLiteralExpr(ctxt.NullPtrTy, SourceLocation());
- QualType t = ctxt.getDecltypeType(nullptr_expr, makeConstInt(ctxt));
- EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr()));
-}
-
-TEST_F(TestTypeSystemClang, TestGetTypeClassTypeOf) {
- clang::ASTContext &ctxt = m_ast->getASTContext();
- QualType t = ctxt.getTypeOfType(makeConstInt(ctxt));
- EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr()));
-}
-
-TEST_F(TestTypeSystemClang, TestGetTypeClassTypeOfExpr) {
- clang::ASTContext &ctxt = m_ast->getASTContext();
- auto *nullptr_expr = new (ctxt) CXXNullPtrLiteralExpr(ctxt.NullPtrTy, SourceLocation());
- QualType t = ctxt.getTypeOfExprType(nullptr_expr);
- EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr()));
-}
-
-TEST_F(TestTypeSystemClang, TestGetTypeClassNested) {
- clang::ASTContext &ctxt = m_ast->getASTContext();
- QualType t_base = ctxt.getTypeOfType(makeConstInt(ctxt));
- QualType t = ctxt.getTypeOfType(t_base);
- EXPECT_EQ(lldb::eTypeClassBuiltin, m_ast->GetTypeClass(t.getAsOpaquePtr()));
-}
-
-TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) {
- // Tests creating a function template.
-
- CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
- clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl();
-
- // Prepare the declarations/types we need for the template.
- CompilerType clang_type =
- m_ast->CreateFunctionType(int_type, nullptr, 0U, false, 0U);
- FunctionDecl *func = m_ast->CreateFunctionDeclaration(
- TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
- false);
- TypeSystemClang::TemplateParameterInfos empty_params;
-
- // Create the actual function template.
- clang::FunctionTemplateDecl *func_template =
- m_ast->CreateFunctionTemplateDecl(TU, OptionalClangModuleID(), func,
- empty_params);
-
- EXPECT_EQ(TU, func_template->getDeclContext());
- EXPECT_EQ("foo", func_template->getName());
- EXPECT_EQ(clang::AccessSpecifier::AS_none, func_template->getAccess());
-}
-
-TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) {
- // Tests creating a function template inside a record.
-
- CompilerType int_type = m_ast->GetBasicType(lldb::eBasicTypeInt);
- clang::TranslationUnitDecl *TU = m_ast->GetTranslationUnitDecl();
-
- // Create a record we can put the function template int.
- CompilerType record_type =
- clang_utils::createRecordWithField(*m_ast, "record", int_type, "field");
- clang::TagDecl *record = ClangUtil::GetAsTagDecl(record_type);
-
- // Prepare the declarations/types we need for the template.
- CompilerType clang_type =
- m_ast->CreateFunctionType(int_type, nullptr, 0U, false, 0U);
- // We create the FunctionDecl for the template in the TU DeclContext because:
- // 1. FunctionDecls can't be in a Record (only CXXMethodDecls can).
- // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine.
- FunctionDecl *func = m_ast->CreateFunctionDeclaration(
- TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None,
- false);
- TypeSystemClang::TemplateParameterInfos empty_params;
-
- // Create the actual function template.
- clang::FunctionTemplateDecl *func_template =
- m_ast->CreateFunctionTemplateDecl(record, OptionalClangModuleID(), func,
- empty_params);
-
- EXPECT_EQ(record, func_template->getDeclContext());
- EXPECT_EQ("foo", func_template->getName());
- EXPECT_EQ(clang::AccessSpecifier::AS_public, func_template->getAccess());
-}
-
-TEST_F(TestTypeSystemClang, TestDeletingImplicitCopyCstrDueToMoveCStr) {
- // We need to simulate this behavior in our AST that we construct as we don't
- // have a Sema instance that can do this for us:
- // C++11 [class.copy]p7, p18:
- // If the class definition declares a move constructor or move assignment
- // operator, an implicitly declared copy constructor or copy assignment
- // operator is defined as deleted.
-
- // Create a record and start defining it.
- llvm::StringRef class_name = "S";
- CompilerType t = clang_utils::createRecord(*m_ast, class_name);
- m_ast->StartTagDeclarationDefinition(t);
-
- // Create a move constructor that will delete the implicit copy constructor.
- CompilerType return_type = m_ast->GetBasicType(lldb::eBasicTypeVoid);
- CompilerType param_type = t.GetRValueReferenceType();
- CompilerType function_type =
- m_ast->CreateFunctionType(return_type, ¶m_type, /*num_params*/ 1,
- /*variadic=*/false, /*quals*/ 0U);
- bool is_virtual = false;
- bool is_static = false;
- bool is_inline = false;
- bool is_explicit = true;
- bool is_attr_used = false;
- bool is_artificial = false;
- m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
- lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
- is_explicit, is_attr_used, is_artificial);
-
- // Complete the definition and check the created record.
- m_ast->CompleteTagDeclarationDefinition(t);
- auto *record = llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(t));
- // We can't call defaultedCopyConstructorIsDeleted() as this requires that
- // the Decl passes through Sema which will actually compute this field.
- // Instead we check that there is no copy constructor declared by the user
- // which only leaves a non-deleted defaulted copy constructor as an option
- // that our record will have no simple copy constructor.
- EXPECT_FALSE(record->hasUserDeclaredCopyConstructor());
- EXPECT_FALSE(record->hasSimpleCopyConstructor());
-}
-
-TEST_F(TestTypeSystemClang, TestNotDeletingUserCopyCstrDueToMoveCStr) {
- // Tests that we don't delete the a user-defined copy constructor when
- // a move constructor is provided.
- // See also the TestDeletingImplicitCopyCstrDueToMoveCStr test.
- llvm::StringRef class_name = "S";
- CompilerType t = clang_utils::createRecord(*m_ast, class_name);
- m_ast->StartTagDeclarationDefinition(t);
-
- CompilerType return_type = m_ast->GetBasicType(lldb::eBasicTypeVoid);
- bool is_virtual = false;
- bool is_static = false;
- bool is_inline = false;
- bool is_explicit = true;
- bool is_attr_used = false;
- bool is_artificial = false;
- // Create a move constructor.
- {
- CompilerType param_type = t.GetRValueReferenceType();
- CompilerType function_type =
- m_ast->CreateFunctionType(return_type, ¶m_type, /*num_params*/ 1,
- /*variadic=*/false, /*quals*/ 0U);
- m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
- lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
- is_explicit, is_attr_used, is_artificial);
- }
- // Create a copy constructor.
- {
- CompilerType param_type = t.GetLValueReferenceType().AddConstModifier();
- CompilerType function_type =
- m_ast->CreateFunctionType(return_type, ¶m_type, /*num_params*/ 1,
- /*variadic=*/false, /*quals*/ 0U);
- m_ast->AddMethodToCXXRecordType(
- t.GetOpaqueQualType(), class_name, nullptr, function_type,
- lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
- is_explicit, is_attr_used, is_artificial);
- }
-
- // Complete the definition and check the created record.
- m_ast->CompleteTagDeclarationDefinition(t);
- auto *record = llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(t));
- EXPECT_TRUE(record->hasUserDeclaredCopyConstructor());
-}
-
-TEST_F(TestTypeSystemClang, AddMethodToObjCObjectType) {
- // Create an interface decl and mark it as having external storage.
- CompilerType c = m_ast->CreateObjCClass("A", m_ast->GetTranslationUnitDecl(),
- OptionalClangModuleID(),
- /*IsForwardDecl*/ false,
- /*IsInternal*/ false);
- ObjCInterfaceDecl *interface = m_ast->GetAsObjCInterfaceDecl(c);
- m_ast->SetHasExternalStorage(c.GetOpaqueQualType(), true);
- EXPECT_TRUE(interface->hasExternalLexicalStorage());
-
- // Add a method to the interface.
- std::vector<CompilerType> args;
- CompilerType func_type =
- m_ast->CreateFunctionType(m_ast->GetBasicType(lldb::eBasicTypeInt),
- args.data(), args.size(), /*variadic*/ false,
- /*quals*/ 0, clang::CallingConv::CC_C);
- bool variadic = false;
- bool artificial = false;
- bool objc_direct = false;
- clang::ObjCMethodDecl *method = TypeSystemClang::AddMethodToObjCObjectType(
- c, "-[A foo]", func_type, lldb::eAccessPublic, artificial, variadic,
- objc_direct);
- ASSERT_NE(method, nullptr);
-
- // The interface decl should still have external lexical storage.
- EXPECT_TRUE(interface->hasExternalLexicalStorage());
-
- // Test some properties of the created ObjCMethodDecl.
- EXPECT_FALSE(method->isVariadic());
- EXPECT_TRUE(method->isImplicit());
- EXPECT_FALSE(method->isDirectMethod());
- EXPECT_EQ(method->getDeclName().getObjCSelector().getAsString(), "foo");
-}
-
-TEST(TestScratchTypeSystemClang, InferSubASTFromLangOpts) {
- LangOptions lang_opts;
- EXPECT_EQ(
- ScratchTypeSystemClang::DefaultAST,
- ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts));
-
- lang_opts.Modules = true;
- EXPECT_EQ(
- ScratchTypeSystemClang::IsolatedASTKind::CppModules,
- ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts));
-}
-
-TEST_F(TestTypeSystemClang, GetExeModuleWhenMissingSymbolFile) {
- CompilerType compiler_type = m_ast->GetBasicTypeFromAST(lldb::eBasicTypeInt);
- lldb_private::Type t(0, nullptr, ConstString("MyType"), llvm::None, nullptr,
- 0, {}, {}, compiler_type,
- lldb_private::Type::ResolveState::Full);
- // Test that getting the execution module when no type system is present
- // is handled gracefully.
- ModuleSP module = t.GetExeModule();
- EXPECT_EQ(module.get(), nullptr);
-}
-
+++ /dev/null
-add_subdirectory(DWARF)
-add_subdirectory(NativePDB)
-if (LLVM_ENABLE_DIA_SDK)
- add_subdirectory(PDB)
-endif()
+++ /dev/null
-add_lldb_unittest(SymbolFileDWARFTests
- DWARFASTParserClangTests.cpp
- DWARFDIETest.cpp
- DWARFUnitTest.cpp
- SymbolFileDWARFTests.cpp
- XcodeSDKModuleTests.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbPluginObjectFilePECOFF
- lldbPluginSymbolFileDWARF
- lldbPluginSymbolFilePDB
- lldbPluginTypeSystemClang
- lldbPluginPlatformMacOSX
- lldbUtilityHelpers
- lldbSymbolHelpers
- LINK_COMPONENTS
- Support
- DebugInfoPDB
- )
-
-set(test_inputs
- test-dwarf.exe)
-
-add_unittest_inputs(SymbolFileDWARFTests "${test_inputs}")
+++ /dev/null
-//===-- DWARFASTParserClangTests.cpp --------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
-#include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-namespace {
-class DWARFASTParserClangTests : public testing::Test {};
-
-class DWARFASTParserClangStub : public DWARFASTParserClang {
-public:
- using DWARFASTParserClang::DWARFASTParserClang;
- using DWARFASTParserClang::LinkDeclContextToDIE;
-
- std::vector<const clang::DeclContext *> GetDeclContextToDIEMapKeys() {
- std::vector<const clang::DeclContext *> keys;
- for (const auto &it : m_decl_ctx_to_die)
- keys.push_back(it.first);
- return keys;
- }
-};
-} // namespace
-
-// If your implementation needs to dereference the dummy pointers we are
-// defining here, causing this test to fail, feel free to delete it.
-TEST_F(DWARFASTParserClangTests,
- EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries) {
-
- /// Auxiliary debug info.
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- - Code: 0x00000002
- Tag: DW_TAG_base_type
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_encoding
- Form: DW_FORM_data1
- - Attribute: DW_AT_byte_size
- Form: DW_FORM_data1
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x000000000000000C
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000004
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000008
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000005 # DW_ATE_signed
- - Value: 0x0000000000000008
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000008 # DW_ATE_unsigned_char
- - Value: 0x0000000000000001
- - AbbrCode: 0x00000000
-)";
-
- YAMLModuleTester t(yamldata);
- ASSERT_TRUE((bool)t.GetDwarfUnit());
-
- TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
- DWARFASTParserClangStub ast_parser(ast_ctx);
-
- DWARFUnit *unit = t.GetDwarfUnit();
- const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
- const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild();
- const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling();
- const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling();
- const DWARFDebugInfoEntry *die_child3 = die_child2->GetSibling();
- std::vector<DWARFDIE> dies = {
- DWARFDIE(unit, die_child0), DWARFDIE(unit, die_child1),
- DWARFDIE(unit, die_child2), DWARFDIE(unit, die_child3)};
- std::vector<clang::DeclContext *> decl_ctxs = {
- (clang::DeclContext *)1LL, (clang::DeclContext *)2LL,
- (clang::DeclContext *)2LL, (clang::DeclContext *)3LL};
- for (int i = 0; i < 4; ++i)
- ast_parser.LinkDeclContextToDIE(decl_ctxs[i], dies[i]);
- ast_parser.EnsureAllDIEsInDeclContextHaveBeenParsed(
- CompilerDeclContext(nullptr, decl_ctxs[1]));
-
- EXPECT_THAT(ast_parser.GetDeclContextToDIEMapKeys(),
- testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3]));
-}
-
+++ /dev/null
-//===-- DWARFDIETest.cpp ----------------------------------------------=---===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "llvm/ADT/STLExtras.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(DWARFDIETest, ChildIteration) {
- // Tests DWARFDIE::child_iterator.
-
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- - Code: 0x00000002
- Tag: DW_TAG_base_type
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_encoding
- Form: DW_FORM_data1
- - Attribute: DW_AT_byte_size
- Form: DW_FORM_data1
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x000000000000000C
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000004
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000007 # DW_ATE_unsigned
- - Value: 0x0000000000000008
- - AbbrCode: 0x00000002
- Values:
- - Value: 0x0000000000000005 # DW_ATE_signed
- - Value: 0x0000000000000008
- - AbbrCode: 0x00000000
-)";
-
- YAMLModuleTester t(yamldata);
- ASSERT_TRUE((bool)t.GetDwarfUnit());
-
- DWARFUnit *unit = t.GetDwarfUnit();
- const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
-
- // Create a DWARFDIE that has three DW_TAG_base_type children.
- DWARFDIE top_die(unit, die_first);
-
- // Create the iterator range that has the three tags as elements.
- llvm::iterator_range<DWARFDIE::child_iterator> children = top_die.children();
-
- // Compare begin() to the first child DIE.
- DWARFDIE::child_iterator child_iter = children.begin();
- ASSERT_NE(child_iter, children.end());
- const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild();
- EXPECT_EQ((*child_iter).GetDIE(), die_child0);
-
- // Step to the second child DIE.
- ++child_iter;
- ASSERT_NE(child_iter, children.end());
- const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling();
- EXPECT_EQ((*child_iter).GetDIE(), die_child1);
-
- // Step to the third child DIE.
- ++child_iter;
- ASSERT_NE(child_iter, children.end());
- const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling();
- EXPECT_EQ((*child_iter).GetDIE(), die_child2);
-
- // Step to the end of the range.
- ++child_iter;
- EXPECT_EQ(child_iter, children.end());
-
- // Take one of the DW_TAG_base_type DIEs (which has no children) and make
- // sure the children range is now empty.
- DWARFDIE no_children_die(unit, die_child0);
- EXPECT_TRUE(no_children_die.children().empty());
-}
+++ /dev/null
-//===-- DWARFUnitTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(DWARFUnitTest, NullUnitDie) {
- // Make sure we don't crash parsing a null unit DIE.
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000000
-)";
-
- YAMLModuleTester t(yamldata);
- ASSERT_TRUE((bool)t.GetDwarfUnit());
-
- DWARFUnit *unit = t.GetDwarfUnit();
- const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
- ASSERT_NE(die_first, nullptr);
- EXPECT_TRUE(die_first->IsNULL());
-}
-
-TEST(DWARFUnitTest, MissingSentinel) {
- // Make sure we don't crash if the debug info is missing a null DIE sentinel.
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_yes
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- debug_info:
- - Version: 4
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x000000000000000C
-)";
-
- YAMLModuleTester t(yamldata);
- ASSERT_TRUE((bool)t.GetDwarfUnit());
-
- DWARFUnit *unit = t.GetDwarfUnit();
- const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE();
- ASSERT_NE(die_first, nullptr);
- EXPECT_EQ(die_first->GetFirstChild(), nullptr);
- EXPECT_EQ(die_first->GetSibling(), nullptr);
-}
+++ /dev/null
-// Compile with "cl /c /Zi /GR- test.cpp"
-// Link with "link test.obj /debug /nodefaultlib /entry:main /out:test.exe"
-
-int __cdecl _purecall(void) { return 0; }
-
-int main(int argc, char **argv) { return 0; }
+++ /dev/null
-//===-- SymbolFileDWARFTests.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
-#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
-#include "Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDebugAranges.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/CompileUnit.h"
-#include "lldb/Symbol/LineTable.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataEncoder.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/StreamString.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class SymbolFileDWARFTests : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFilePECOFF, SymbolFileDWARF,
- TypeSystemClang, SymbolFilePDB>
- subsystems;
-
-public:
- void SetUp() override {
- m_dwarf_test_exe = GetInputFilePath("test-dwarf.exe");
- }
-
-protected:
- std::string m_dwarf_test_exe;
-};
-
-TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) {
- // Test that when we have Dwarf debug info, SymbolFileDWARF is used.
- FileSpec fspec(m_dwarf_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
- ASSERT_NE(nullptr, symfile);
- EXPECT_EQ(symfile->GetPluginName(), SymbolFileDWARF::GetPluginNameStatic());
-
- uint32_t expected_abilities = SymbolFile::kAllAbilities;
- EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) {
- // Test that if we have a .debug_abbrev that contains ordered abbreviation
- // codes that start at 1, that we get O(1) access.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_yes);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(2); // Abbrev code 2
- encoder.PutULEB128(DW_TAG_subprogram);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- EXPECT_FALSE(bool(error));
- // Make sure we have O(1) access to each abbreviation by making sure the
- // index offset is 1 and not UINT32_MAX
- EXPECT_EQ(abbrev_set.GetIndexOffset(), 1u);
-
- auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(1);
- EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
- EXPECT_TRUE(abbrev1->HasChildren());
- EXPECT_EQ(abbrev1->NumAttributes(), 1u);
- auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(2);
- EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
- EXPECT_FALSE(abbrev2->HasChildren());
- EXPECT_EQ(abbrev2->NumAttributes(), 1u);
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) {
- // Test that if we have a .debug_abbrev that contains ordered abbreviation
- // codes that start at 5, that we get O(1) access.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(5); // Abbrev code 5
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_yes);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(6); // Abbrev code 6
- encoder.PutULEB128(DW_TAG_subprogram);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- EXPECT_FALSE(bool(error));
- // Make sure we have O(1) access to each abbreviation by making sure the
- // index offset is 5 and not UINT32_MAX
- EXPECT_EQ(abbrev_set.GetIndexOffset(), 5u);
-
- auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(5);
- EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
- EXPECT_TRUE(abbrev1->HasChildren());
- EXPECT_EQ(abbrev1->NumAttributes(), 1u);
- auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(6);
- EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
- EXPECT_FALSE(abbrev2->HasChildren());
- EXPECT_EQ(abbrev2->NumAttributes(), 1u);
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) {
- // Test that if we have a .debug_abbrev that contains unordered abbreviation
- // codes, that we can access the information correctly.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(2); // Abbrev code 2
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_yes);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(DW_TAG_subprogram);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- EXPECT_FALSE(bool(error));
- // Make sure we don't have O(1) access to each abbreviation by making sure
- // the index offset is UINT32_MAX
- EXPECT_EQ(abbrev_set.GetIndexOffset(), UINT32_MAX);
-
- auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(2);
- EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit);
- EXPECT_TRUE(abbrev1->HasChildren());
- EXPECT_EQ(abbrev1->NumAttributes(), 1u);
- auto abbrev2 = abbrev_set.GetAbbreviationDeclaration(1);
- EXPECT_EQ(abbrev2->Tag(), DW_TAG_subprogram);
- EXPECT_FALSE(abbrev2->HasChildren());
- EXPECT_EQ(abbrev2->NumAttributes(), 1u);
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) {
- // Test that we detect when an abbreviation has a NULL tag and that we get
- // an error when decoding.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(0); // Invalid NULL tag here!
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- // Verify we get an error
- EXPECT_TRUE(bool(error));
- EXPECT_EQ("abbrev decl requires non-null tag.",
- llvm::toString(std::move(error)));
-
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) {
- // Test that we detect when an abbreviation has a NULL attribute and a non
- // NULL form and that we get an error when decoding.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(0); // Invalid NULL DW_AT
- encoder.PutULEB128(DW_FORM_strp); // With a valid form
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- // Verify we get an error
- EXPECT_TRUE(bool(error));
- EXPECT_EQ("malformed abbreviation declaration attribute",
- llvm::toString(std::move(error)));
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) {
- // Test that we detect when an abbreviation has a valid attribute and a
- // NULL form and that we get an error when decoding.
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(DW_AT_name); // Valid attribute
- encoder.PutULEB128(0); // NULL form
- encoder.PutULEB128(0);
- encoder.PutULEB128(0);
-
- encoder.PutULEB128(0); // Abbrev code 0 (termination)
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- // Verify we get an error
- EXPECT_TRUE(bool(error));
- EXPECT_EQ("malformed abbreviation declaration attribute",
- llvm::toString(std::move(error)));
-}
-
-TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) {
- // Test that we detect when an abbreviation has a valid attribute and a
- // form, but is missing the NULL attribute and form that terminates an
- // abbreviation
-
- const auto byte_order = eByteOrderLittle;
- const uint8_t addr_size = 4;
- StreamString encoder(Stream::eBinary, addr_size, byte_order);
- encoder.PutULEB128(1); // Abbrev code 1
- encoder.PutULEB128(DW_TAG_compile_unit);
- encoder.PutHex8(DW_CHILDREN_no);
- encoder.PutULEB128(DW_AT_name);
- encoder.PutULEB128(DW_FORM_strp);
- // Don't add the NULL DW_AT and NULL DW_FORM terminator
-
- DWARFDataExtractor data;
- data.SetData(encoder.GetData(), encoder.GetSize(), byte_order);
- DWARFAbbreviationDeclarationSet abbrev_set;
- lldb::offset_t data_offset = 0;
- llvm::Error error = abbrev_set.extract(data, &data_offset);
- // Verify we get an error
- EXPECT_TRUE(bool(error));
- EXPECT_EQ("abbreviation declaration attribute list not terminated with a "
- "null entry", llvm::toString(std::move(error)));
-}
-
-TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) {
- // This `.debug_aranges` table header is a valid 32bit big-endian section
- // according to the DWARFv5 spec:6.2.1, but contains segment selectors which
- // are not supported by lldb, and should be gracefully rejected
- const unsigned char binary_data[] = {
- 0, 0, 0, 41, // unit_length (length field not including this field itself)
- 0, 2, // DWARF version number (half)
- 0, 0, 0, 0, // offset into the .debug_info_table (ignored for the purposes
- // of this test
- 4, // address size
- 1, // segment size
- // alignment for the first tuple which "begins at an offset that is a
- // multiple of the size of a single tuple". Tuples are nine bytes in this
- // example.
- 0, 0, 0, 0, 0, 0,
- // BEGIN TUPLES
- 1, 0, 0, 0, 4, 0, 0, 0,
- 1, // a 1byte object starting at address 4 in segment 1
- 0, 0, 0, 0, 4, 0, 0, 0,
- 1, // a 1byte object starting at address 4 in segment 0
- // END TUPLES
- 0, 0, 0, 0, 0, 0, 0, 0, 0 // terminator
- };
- DWARFDataExtractor data;
- data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,
- lldb::ByteOrder::eByteOrderBig);
- DWARFDebugArangeSet debug_aranges;
- offset_t off = 0;
- llvm::Error error = debug_aranges.extract(data, &off);
- EXPECT_TRUE(bool(error));
- EXPECT_EQ("segmented arange entries are not supported",
- llvm::toString(std::move(error)));
- EXPECT_EQ(off, 12U); // Parser should read no further than the segment size
-}
-
-TEST_F(SymbolFileDWARFTests, ParseArangesWithMultipleTerminators) {
- // This .debug_aranges set has multiple terminator entries which appear in
- // binaries produced by popular linux compilers and linker combinations. We
- // must be able to parse all the way through the data for each
- // DWARFDebugArangeSet. Previously the DWARFDebugArangeSet::extract()
- // function would stop parsing as soon as we ran into a terminator even
- // though the length field stated that there was more data that follows. This
- // would cause the next DWARFDebugArangeSet to be parsed immediately
- // following the first terminator and it would attempt to decode the
- // DWARFDebugArangeSet header using the remaining segment + address pairs
- // from the remaining bytes.
- unsigned char binary_data[] = {
- 0, 0, 0, 0, // unit_length that will be set correctly after this
- 0, 2, // DWARF version number (uint16_t)
- 0, 0, 0, 0, // CU offset (ignored for the purposes of this test)
- 4, // address size
- 0, // segment size
- 0, 0, 0, 0, // alignment for the first tuple
- // BEGIN TUPLES
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator
- 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator
- 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010)
- // END TUPLES
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator
- };
- // Set the big endian length correctly.
- const offset_t binary_data_size = sizeof(binary_data);
- binary_data[3] = (uint8_t)binary_data_size - 4;
- DWARFDataExtractor data;
- data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,
- lldb::ByteOrder::eByteOrderBig);
- DWARFDebugArangeSet set;
- offset_t off = 0;
- llvm::Error error = set.extract(data, &off);
- // Multiple terminators are not fatal as they do appear in binaries.
- EXPECT_FALSE(bool(error));
- // Parser should read all terminators to the end of the length specified.
- EXPECT_EQ(off, binary_data_size);
- ASSERT_EQ(set.NumDescriptors(), 2U);
- ASSERT_EQ(set.GetDescriptorRef(0).address, (dw_addr_t)0x1000);
- ASSERT_EQ(set.GetDescriptorRef(0).length, (dw_addr_t)0x100);
- ASSERT_EQ(set.GetDescriptorRef(1).address, (dw_addr_t)0x2000);
- ASSERT_EQ(set.GetDescriptorRef(1).length, (dw_addr_t)0x10);
-}
-
-TEST_F(SymbolFileDWARFTests, ParseArangesIgnoreEmpty) {
- // This .debug_aranges set has some address ranges which have zero length
- // and we ensure that these are ignored by our DWARFDebugArangeSet parser
- // and not included in the descriptors that are returned.
- unsigned char binary_data[] = {
- 0, 0, 0, 0, // unit_length that will be set correctly after this
- 0, 2, // DWARF version number (uint16_t)
- 0, 0, 0, 0, // CU offset (ignored for the purposes of this test)
- 4, // address size
- 0, // segment size
- 0, 0, 0, 0, // alignment for the first tuple
- // BEGIN TUPLES
- 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)
- 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, // [0x1100-0x1100)
- 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010)
- 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // [0x2010-0x2010)
- // END TUPLES
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator
- };
- // Set the big endian length correctly.
- const offset_t binary_data_size = sizeof(binary_data);
- binary_data[3] = (uint8_t)binary_data_size - 4;
- DWARFDataExtractor data;
- data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,
- lldb::ByteOrder::eByteOrderBig);
- DWARFDebugArangeSet set;
- offset_t off = 0;
- llvm::Error error = set.extract(data, &off);
- // Multiple terminators are not fatal as they do appear in binaries.
- EXPECT_FALSE(bool(error));
- // Parser should read all terminators to the end of the length specified.
- // Previously the DWARFDebugArangeSet would stop at the first terminator
- // entry and leave the offset in the middle of the current
- // DWARFDebugArangeSet data, and that would cause the next extracted
- // DWARFDebugArangeSet to fail.
- EXPECT_EQ(off, binary_data_size);
- ASSERT_EQ(set.NumDescriptors(), 2U);
- ASSERT_EQ(set.GetDescriptorRef(0).address, (dw_addr_t)0x1000);
- ASSERT_EQ(set.GetDescriptorRef(0).length, (dw_addr_t)0x100);
- ASSERT_EQ(set.GetDescriptorRef(1).address, (dw_addr_t)0x2000);
- ASSERT_EQ(set.GetDescriptorRef(1).length, (dw_addr_t)0x10);
-}
-
-TEST_F(SymbolFileDWARFTests, ParseAranges) {
- // Test we can successfully parse a DWARFDebugAranges. The initial error
- // checking code had a bug where it would always return an empty address
- // ranges for everything in .debug_aranges and no error.
- unsigned char binary_data[] = {
- 0, 0, 0, 0, // unit_length that will be set correctly after this
- 2, 0, // DWARF version number
- 255, 0, 0, 0, // offset into the .debug_info_table
- 8, // address size
- 0, // segment size
- 0, 0, 0, 0, // pad bytes
- // BEGIN TUPLES
- // First tuple: [0x1000-0x1100)
- 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x1000
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100
- // Second tuple: [0x2000-0x2100)
- 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x2000
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100
- // Terminating tuple
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator
- };
- // Set the little endian length correctly.
- binary_data[0] = sizeof(binary_data) - 4;
- DWARFDataExtractor data;
- data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,
- lldb::ByteOrder::eByteOrderLittle);
- DWARFDebugAranges debug_aranges;
- debug_aranges.extract(data);
- EXPECT_EQ(debug_aranges.GetNumRanges(), 2u);
- EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u);
- EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u);
- EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u);
- EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 255u);
- EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET);
-}
-
-TEST_F(SymbolFileDWARFTests, ParseArangesSkipErrors) {
- // Test we can successfully parse a DWARFDebugAranges that contains some
- // valid DWARFDebugArangeSet objects and some with errors as long as their
- // length is set correctly. This helps LLDB ensure that it can parse newer
- // .debug_aranges version that LLDB currently doesn't support, or ignore
- // errors in individual DWARFDebugArangeSet objects as long as the length
- // is set correctly.
- const unsigned char binary_data[] = {
- // This DWARFDebugArangeSet is well formed and has a single address range
- // for [0x1000-0x1100) with a CU offset of 0x00000000.
- 0, 0, 0, 28, // unit_length that will be set correctly after this
- 0, 2, // DWARF version number (uint16_t)
- 0, 0, 0, 0, // CU offset = 0x00000000
- 4, // address size
- 0, // segment size
- 0, 0, 0, 0, // alignment for the first tuple
- 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator
- // This DWARFDebugArangeSet has the correct length, but an invalid
- // version. We need to be able to skip this correctly and ignore it.
- 0, 0, 0, 20, // unit_length that will be set correctly after this
- 0, 44, // invalid DWARF version number (uint16_t)
- 0, 0, 1, 0, // CU offset = 0x00000100
- 4, // address size
- 0, // segment size
- 0, 0, 0, 0, // alignment for the first tuple
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator
- // This DWARFDebugArangeSet is well formed and has a single address range
- // for [0x2000-0x2100) with a CU offset of 0x00000000.
- 0, 0, 0, 28, // unit_length that will be set correctly after this
- 0, 2, // DWARF version number (uint16_t)
- 0, 0, 2, 0, // CU offset = 0x00000200
- 4, // address size
- 0, // segment size
- 0, 0, 0, 0, // alignment for the first tuple
- 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x2000-0x2100)
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator
- };
-
- DWARFDataExtractor data;
- data.SetData(static_cast<const void *>(binary_data), sizeof binary_data,
- lldb::ByteOrder::eByteOrderBig);
- DWARFDebugAranges debug_aranges;
- debug_aranges.extract(data);
- EXPECT_EQ(debug_aranges.GetNumRanges(), 2u);
- EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x1000), 0u);
- EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 0u);
- EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET);
- EXPECT_EQ(debug_aranges.FindAddress(0x2000), 0x200u);
- EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 0x200u);
- EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET);
-}
+++ /dev/null
-//===-- XcodeSDKModuleTests.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
-#include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "lldb/Core/PluginManager.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-#ifdef __APPLE__
-namespace {
-class XcodeSDKModuleTests : public testing::Test {
- SubsystemRAII<HostInfoBase, PlatformMacOSX> subsystems;
-};
-} // namespace
-
-
-TEST_F(XcodeSDKModuleTests, TestModuleGetXcodeSDK) {
- const char *yamldata = R"(
---- !ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_EXEC
- Machine: EM_386
-DWARF:
- debug_str:
- - MacOSX10.9.sdk
- debug_abbrev:
- - Table:
- - Code: 0x00000001
- Tag: DW_TAG_compile_unit
- Children: DW_CHILDREN_no
- Attributes:
- - Attribute: DW_AT_language
- Form: DW_FORM_data2
- - Attribute: DW_AT_APPLE_sdk
- Form: DW_FORM_strp
- debug_info:
- - Version: 2
- AddrSize: 8
- Entries:
- - AbbrCode: 0x00000001
- Values:
- - Value: 0x000000000000000C
- - Value: 0x0000000000000000
- - AbbrCode: 0x00000000
-...
-)";
-
- YAMLModuleTester t(yamldata);
- DWARFUnit *dwarf_unit = t.GetDwarfUnit();
- auto *dwarf_cu = llvm::cast<DWARFCompileUnit>(dwarf_unit);
- ASSERT_TRUE(static_cast<bool>(dwarf_cu));
- SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF();
- CompUnitSP comp_unit = sym_file.GetCompileUnitAtIndex(0);
- ASSERT_TRUE(static_cast<bool>(comp_unit.get()));
- ModuleSP module = t.GetModule();
- ASSERT_EQ(module->GetSourceMappingList().GetSize(), 0u);
- XcodeSDK sdk = sym_file.ParseXcodeSDK(*comp_unit);
- ASSERT_EQ(sdk.GetType(), XcodeSDK::Type::MacOSX);
- ASSERT_EQ(module->GetSourceMappingList().GetSize(), 1u);
-}
-#endif
+++ /dev/null
-add_lldb_unittest(SymbolFileNativePDBTests
- PdbFPOProgramToDWARFExpressionTests.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbPluginSymbolFileNativePDB
- lldbUtilityHelpers
- LINK_COMPONENTS
- Support
- DebugInfoPDB
- )
+++ /dev/null
-//===-- PDBFPOProgramToDWARFExpressionTests.cpp ---------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h"
-
-#include "lldb/Core/StreamBuffer.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::npdb;
-
-/// Valid programs tests
-
-static void
-CheckValidProgramTranslation(llvm::StringRef fpo_program,
- llvm::StringRef target_register_name,
- llvm::StringRef expected_dwarf_expression) {
- // program translation
- StreamBuffer<32> stream(Stream::eBinary, 4, eByteOrderLittle);
- ASSERT_TRUE(TranslateFPOProgramToDWARFExpression(
- fpo_program, target_register_name, llvm::Triple::x86, stream));
-
- // print dwarf expression to comparable textual representation
- llvm::DataExtractor extractor({stream.GetData(), stream.GetSize()},
- /*IsLittleEndian=*/true, /*AddressSize=*/4);
-
- std::string result;
- llvm::raw_string_ostream os(result);
- llvm::DWARFExpression(extractor, /*AddressSize=*/4, llvm::dwarf::DWARF32)
- .print(os, llvm::DIDumpOptions(), nullptr, nullptr);
-
- // actual check
- ASSERT_EQ(expected_dwarf_expression, os.str());
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentRegisterRef) {
- CheckValidProgramTranslation("$T0 $ebp = ", "$T0", "DW_OP_breg6 +0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, MultipleIndependentAssignments) {
- CheckValidProgramTranslation("$T1 1 = $T0 0 =", "$T0", "DW_OP_consts +0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, MultipleDependentAssignments) {
- CheckValidProgramTranslation(
- "$T1 $ebp 4 + = $T0 $T1 8 - 128 @ = ", "$T0",
- "DW_OP_breg6 +0, DW_OP_consts +4, DW_OP_plus, DW_OP_consts +8, "
- "DW_OP_minus, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, DW_OP_not, "
- "DW_OP_and");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, DependencyChain) {
- CheckValidProgramTranslation("$T1 0 = $T0 $T1 = $ebp $T0 =", "$ebp",
- "DW_OP_consts +0");
-}
-
-/// Invalid programs tests
-static void
-CheckInvalidProgramTranslation(llvm::StringRef fpo_program,
- llvm::StringRef target_register_name) {
- // initial setup
- ArchSpec arch_spec("i686-pc-windows");
- llvm::Triple::ArchType arch_type = arch_spec.GetMachine();
- ByteOrder byte_order = arch_spec.GetByteOrder();
- uint32_t address_size = arch_spec.GetAddressByteSize();
-
- // program translation
- StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
- EXPECT_FALSE(TranslateFPOProgramToDWARFExpression(
- fpo_program, target_register_name, arch_type, stream));
- EXPECT_EQ((size_t)0, stream.GetSize());
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, InvalidAssignmentSingle) {
- CheckInvalidProgramTranslation("$T0 0", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, InvalidAssignmentMultiple) {
- CheckInvalidProgramTranslation("$T1 0 = $T0 0", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, UnknownOp) {
- CheckInvalidProgramTranslation("$T0 $ebp 0 & = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, InvalidOpBinary) {
- CheckInvalidProgramTranslation("$T0 0 + = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, InvalidOpUnary) {
- CheckInvalidProgramTranslation("$T0 ^ = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, MissingTargetRegister) {
- CheckInvalidProgramTranslation("$T1 0 = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, UnresolvedRegisterReference) {
- CheckInvalidProgramTranslation("$T0 $abc = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests,
- UnresolvedRegisterAssignmentReference) {
- CheckInvalidProgramTranslation("$T2 0 = $T0 $T1 = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests,
- UnresolvedCyclicRegisterAssignmentReference) {
- CheckInvalidProgramTranslation("$T1 $T0 = $T0 $T1 = ", "$T0");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests,
- UnresolvedDependentCyclicRegisterAssignmentReference) {
- CheckInvalidProgramTranslation("$T1 $T0 = $T0 $T1 = $T2 $T1 =", "$T2");
-}
-
-TEST(PDBFPOProgramToDWARFExpressionTests, UnsupportedRASearch) {
- CheckInvalidProgramTranslation("$T0 .raSearch = ", "$T0");
-}
+++ /dev/null
-add_lldb_unittest(SymbolFilePDBTests
- SymbolFilePDBTests.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbPluginObjectFilePECOFF
- lldbPluginSymbolFileDWARF
- lldbPluginSymbolFilePDB
- lldbPluginTypeSystemClang
- lldbUtilityHelpers
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- DebugInfoPDB
- )
-
-set(test_inputs
- test-pdb.exe
- test-pdb.pdb
- test-pdb-types.exe
- test-pdb-types.pdb)
-
-add_unittest_inputs(SymbolFilePDBTests "${test_inputs}")
+++ /dev/null
-// Compile with "cl /c /Zi /GR- test-pdb-alt.cpp"
-// Link with "link test-pdb.obj test-pdb-alt.obj /debug /nodefaultlib
-// /entry:main /out:test-pdb.exe"
-
-#include "test-pdb.h"
-
-int bar(int n) { return n - 1; }
+++ /dev/null
-#ifndef TEST_PDB_NESTED_H
-#define TEST_PDB_NESTED_H
-
-inline int baz(int n) { return n + 1; }
-
-#endif
+++ /dev/null
-// Compile with "cl /c /Zi /GR- /EHsc test-pdb-types.cpp"
-// Link with "link test-pdb-types.obj /debug /nodefaultlib /entry:main
-// /out:test-pdb-types.exe"
-
-using namespace std;
-
-// Sizes of builtin types
-static const int sizeof_char = sizeof(char);
-static const int sizeof_uchar = sizeof(unsigned char);
-static const int sizeof_short = sizeof(short);
-static const int sizeof_ushort = sizeof(unsigned short);
-static const int sizeof_int = sizeof(int);
-static const int sizeof_uint = sizeof(unsigned int);
-static const int sizeof_long = sizeof(long);
-static const int sizeof_ulong = sizeof(unsigned long);
-static const int sizeof_longlong = sizeof(long long);
-static const int sizeof_ulonglong = sizeof(unsigned long long);
-static const int sizeof_int64 = sizeof(__int64);
-static const int sizeof_uint64 = sizeof(unsigned __int64);
-static const int sizeof_float = sizeof(float);
-static const int sizeof_double = sizeof(double);
-static const int sizeof_bool = sizeof(bool);
-static const int sizeof_wchar = sizeof(wchar_t);
-
-enum Enum {
- EValue1 = 1,
- EValue2 = 2,
-};
-
-enum ShortEnum : short { ESValue1 = 1, ESValue2 = 2 };
-
-namespace NS {
-class NSClass {
- float f;
- double d;
-};
-} // namespace NS
-
-class Class {
-public:
- class NestedClass {
- Enum e;
- };
- ShortEnum se;
-};
-
-int test_func(int a, int b) { return a + b; }
-
-typedef Class ClassTypedef;
-typedef NS::NSClass NSClassTypedef;
-typedef int (*FuncPointerTypedef)();
-typedef int (*VariadicFuncPointerTypedef)(char, ...);
-FuncPointerTypedef GlobalFunc;
-VariadicFuncPointerTypedef GlobalVariadicFunc;
-int GlobalArray[10];
-
-static const int sizeof_NSClass = sizeof(NS::NSClass);
-static const int sizeof_Class = sizeof(Class);
-static const int sizeof_NestedClass = sizeof(Class::NestedClass);
-static const int sizeof_Enum = sizeof(Enum);
-static const int sizeof_ShortEnum = sizeof(ShortEnum);
-static const int sizeof_ClassTypedef = sizeof(ClassTypedef);
-static const int sizeof_NSClassTypedef = sizeof(NSClassTypedef);
-static const int sizeof_FuncPointerTypedef = sizeof(FuncPointerTypedef);
-static const int sizeof_VariadicFuncPointerTypedef =
- sizeof(VariadicFuncPointerTypedef);
-static const int sizeof_GlobalArray = sizeof(GlobalArray);
-
-int main(int argc, char **argv) {
- ShortEnum e1;
- Enum e2;
- Class c1;
- Class::NestedClass c2;
- NS::NSClass c3;
-
- ClassTypedef t1;
- NSClassTypedef t2;
- return test_func(1, 2);
-}
+++ /dev/null
-// Compile with "cl /c /Zi /GR- test-pdb.cpp"
-// Link with "link test-pdb.obj /debug /nodefaultlib /entry:main
-// /out:test-pdb.exe"
-
-#include "test-pdb.h"
-
-int __cdecl _purecall(void) { return 0; }
-
-int main(int argc, char **argv) { return foo(argc) + bar(argc); }
+++ /dev/null
-#ifndef TEST_PDB_H
-#define TEST_PDB_H
-
-#include "test-pdb-nested.h"
-
-int bar(int n);
-
-inline int foo(int n) { return baz(n) + 1; }
-
-#endif
+++ /dev/null
-//===-- PythonDataObjectsTests.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Address.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/CompileUnit.h"
-#include "lldb/Symbol/LineTable.h"
-#include "lldb/Symbol/TypeMap.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/FileSpec.h"
-
-#if defined(_WIN32)
-#include "lldb/Host/windows/windows.h"
-#include <objbase.h>
-#endif
-
-#include <algorithm>
-
-using namespace lldb_private;
-
-class SymbolFilePDBTests : public testing::Test {
-public:
- void SetUp() override {
-// Initialize and TearDown the plugin every time, so we get a brand new
-// AST every time so that modifications to the AST from each test don't
-// leak into the next test.
-#if defined(_WIN32)
- ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
-#endif
-
- FileSystem::Initialize();
- HostInfo::Initialize();
- ObjectFilePECOFF::Initialize();
- SymbolFileDWARF::Initialize();
- TypeSystemClang::Initialize();
- SymbolFilePDB::Initialize();
-
- m_pdb_test_exe = GetInputFilePath("test-pdb.exe");
- m_types_test_exe = GetInputFilePath("test-pdb-types.exe");
- }
-
- void TearDown() override {
- SymbolFilePDB::Terminate();
- TypeSystemClang::Initialize();
- SymbolFileDWARF::Terminate();
- ObjectFilePECOFF::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
-
-#if defined(_WIN32)
- ::CoUninitialize();
-#endif
- }
-
-protected:
- std::string m_pdb_test_exe;
- std::string m_types_test_exe;
-
- bool FileSpecMatchesAsBaseOrFull(const FileSpec &left,
- const FileSpec &right) const {
- // If the filenames don't match, the paths can't be equal
- if (!left.FileEquals(right))
- return false;
- // If BOTH have a directory, also compare the directories.
- if (left.GetDirectory() && right.GetDirectory())
- return left.DirectoryEquals(right);
-
- // If one has a directory but not the other, they match.
- return true;
- }
-
- void VerifyLineEntry(lldb::ModuleSP module, const SymbolContext &sc,
- const FileSpec &spec, LineTable <, uint32_t line,
- lldb::addr_t addr) {
- LineEntry entry;
- Address address;
- EXPECT_TRUE(module->ResolveFileAddress(addr, address));
-
- EXPECT_TRUE(lt.FindLineEntryByAddress(address, entry));
- EXPECT_EQ(line, entry.line);
- EXPECT_EQ(address, entry.range.GetBaseAddress());
-
- EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file));
- }
-
- bool ContainsCompileUnit(const SymbolContextList &sc_list,
- const FileSpec &spec) const {
- for (size_t i = 0; i < sc_list.GetSize(); ++i) {
- const SymbolContext &sc = sc_list[i];
- if (FileSpecMatchesAsBaseOrFull(sc.comp_unit->GetPrimaryFile(), spec))
- return true;
- }
- return false;
- }
-
- uint64_t GetGlobalConstantInteger(llvm::pdb::IPDBSession &session,
- llvm::StringRef var) const {
- auto global = session.getGlobalScope();
- auto results =
- global->findChildren(llvm::pdb::PDB_SymType::Data, var,
- llvm::pdb::PDB_NameSearchFlags::NS_Default);
- uint32_t count = results->getChildCount();
- if (count == 0)
- return -1;
-
- auto item = results->getChildAtIndex(0);
- auto symbol = llvm::dyn_cast<llvm::pdb::PDBSymbolData>(item.get());
- if (!symbol)
- return -1;
- llvm::pdb::Variant value = symbol->getValue();
- switch (value.Type) {
- case llvm::pdb::PDB_VariantType::Int16:
- return value.Value.Int16;
- case llvm::pdb::PDB_VariantType::Int32:
- return value.Value.Int32;
- case llvm::pdb::PDB_VariantType::UInt16:
- return value.Value.UInt16;
- case llvm::pdb::PDB_VariantType::UInt32:
- return value.Value.UInt32;
- default:
- return 0;
- }
- }
-};
-
-TEST_F(SymbolFilePDBTests, TestAbilitiesForPDB) {
- // Test that when we have PDB debug info, SymbolFilePDB is used.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
- EXPECT_NE(nullptr, symfile);
- EXPECT_EQ(symfile->GetPluginName(), SymbolFilePDB::GetPluginNameStatic());
-
- uint32_t expected_abilities = SymbolFile::kAllAbilities;
- EXPECT_EQ(expected_abilities, symfile->CalculateAbilities());
-}
-
-TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) {
- // Test that attempting to call ResolveSymbolContext with only a basename
- // finds all full paths
- // with the same basename
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec header_spec("test-pdb.cpp");
- SymbolContextList sc_list;
- SourceLocationSpec location_spec(header_spec, /*line=*/0);
- uint32_t result_count = symfile->ResolveSymbolContext(
- location_spec, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(1u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
-}
-
-TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) {
- // Test that attempting to call ResolveSymbolContext with a full path only
- // finds the one source
- // file that matches the full path.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec header_spec(
- R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec");
- SymbolContextList sc_list;
- SourceLocationSpec location_spec(header_spec, /*line=*/0);
- uint32_t result_count = symfile->ResolveSymbolContext(
- location_spec, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_GE(1u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec));
-}
-
-TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithInlines) {
- // Test that when looking up a header file via ResolveSymbolContext (i.e. a
- // file that was not by itself
- // compiled, but only contributes to the combined code of other source files),
- // a SymbolContext is returned
- // for each compiland which has line contributions from the requested header.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec header_specs[] = {FileSpec("test-pdb.h"),
- FileSpec("test-pdb-nested.h")};
- FileSpec main_cpp_spec("test-pdb.cpp");
- FileSpec alt_cpp_spec("test-pdb-alt.cpp");
- for (const auto &hspec : header_specs) {
- SymbolContextList sc_list;
- SourceLocationSpec location_spec(hspec, /*line=*/0, /*column=*/llvm::None,
- /*check_inlines=*/true);
- uint32_t result_count = symfile->ResolveSymbolContext(
- location_spec, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(2u, result_count);
- EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec));
- EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec));
- }
-}
-
-TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) {
- // Test that when looking up a header file via ResolveSymbolContext (i.e. a
- // file that was not by itself
- // compiled, but only contributes to the combined code of other source files),
- // that if check_inlines
- // is false, no SymbolContexts are returned.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec header_specs[] = {FileSpec("test-pdb.h"),
- FileSpec("test-pdb-nested.h")};
- for (const auto &hspec : header_specs) {
- SymbolContextList sc_list;
- SourceLocationSpec location_spec(hspec, /*line=*/0);
- uint32_t result_count = symfile->ResolveSymbolContext(
- location_spec, lldb::eSymbolContextCompUnit, sc_list);
- EXPECT_EQ(0u, result_count);
- }
-}
-
-TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) {
- // Test that when calling ResolveSymbolContext with a line number of 0, all
- // line entries from
- // the specified files are returned.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec source_file("test-pdb.cpp");
- FileSpec header1("test-pdb.h");
- FileSpec header2("test-pdb-nested.h");
- uint32_t cus = symfile->GetNumCompileUnits();
- EXPECT_EQ(2u, cus);
-
- SymbolContextList sc_list;
- lldb::SymbolContextItem scope =
- lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
-
- SourceLocationSpec location_spec(
- source_file, /*line=*/0, /*column=*/llvm::None, /*check_inlines=*/true);
- uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
- EXPECT_EQ(1u, count);
- SymbolContext sc;
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- LineTable *lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination (per function)
- EXPECT_EQ(16u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
- VerifyLineEntry(module, sc, source_file, *lt, 8, 0x401043);
- VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
-
- VerifyLineEntry(module, sc, source_file, *lt, 13, 0x401050);
- VerifyLineEntry(module, sc, source_file, *lt, 14, 0x401054);
- VerifyLineEntry(module, sc, source_file, *lt, 15, 0x401070);
-
- VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
- VerifyLineEntry(module, sc, header1, *lt, 10, 0x401093);
- VerifyLineEntry(module, sc, header1, *lt, 11, 0x4010a2);
-
- VerifyLineEntry(module, sc, header2, *lt, 5, 0x401080);
- VerifyLineEntry(module, sc, header2, *lt, 6, 0x401083);
- VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
-}
-
-TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) {
- // Test that when calling ResolveSymbolContext with a specific line number,
- // only line entries
- // which match the requested line are returned.
- FileSpec fspec(m_pdb_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFile *symfile = module->GetSymbolFile();
-
- FileSpec source_file("test-pdb.cpp");
- FileSpec header1("test-pdb.h");
- FileSpec header2("test-pdb-nested.h");
- uint32_t cus = symfile->GetNumCompileUnits();
- EXPECT_EQ(2u, cus);
-
- SymbolContextList sc_list;
- lldb::SymbolContextItem scope =
- lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry;
-
- // First test with line 7, and verify that only line 7 entries are added.
- SourceLocationSpec location_spec(
- source_file, /*line=*/7, /*column=*/llvm::None, /*check_inlines=*/true);
- uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
- EXPECT_EQ(1u, count);
- SymbolContext sc;
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- LineTable *lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination
- EXPECT_EQ(3u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 7, 0x401040);
- VerifyLineEntry(module, sc, header2, *lt, 7, 0x401089);
-
- sc_list.Clear();
- // Then test with line 9, and verify that only line 9 entries are added.
- location_spec = SourceLocationSpec(
- source_file, /*line=*/9, /*column=*/llvm::None, /*check_inlines=*/true);
- count = symfile->ResolveSymbolContext(location_spec, scope, sc_list);
- EXPECT_EQ(1u, count);
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
-
- lt = sc.comp_unit->GetLineTable();
- EXPECT_NE(nullptr, lt);
- count = lt->GetSize();
- // We expect one extra entry for termination
- EXPECT_EQ(3u, count);
-
- VerifyLineEntry(module, sc, source_file, *lt, 9, 0x401045);
- VerifyLineEntry(module, sc, header1, *lt, 9, 0x401090);
-}
-
-TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
- searched_files, results);
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("Class"), udt_type->GetName());
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
- EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"),
- udt_type->GetByteSize(nullptr));
-}
-
-TEST_F(SymbolFilePDBTests, TestNestedClassTypes) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
-
- auto clang_ast_ctx_or_err =
- symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
- ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
-
- auto clang_ast_ctx =
- llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
- EXPECT_NE(nullptr, clang_ast_ctx);
-
- symfile->FindTypes(ConstString("Class"), CompilerDeclContext(), 0,
- searched_files, results);
- EXPECT_EQ(1u, results.GetSize());
-
- auto Class = results.GetTypeAtIndex(0);
- EXPECT_TRUE(Class);
- EXPECT_TRUE(Class->IsValidType());
-
- auto ClassCompilerType = Class->GetFullCompilerType();
- EXPECT_TRUE(ClassCompilerType.IsValid());
-
- auto ClassDeclCtx = clang_ast_ctx->GetDeclContextForType(ClassCompilerType);
- EXPECT_NE(nullptr, ClassDeclCtx);
-
- // There are two symbols for nested classes: one belonging to enclosing class
- // and one is global. We process correctly this case and create the same
- // compiler type for both, but `FindTypes` may return more than one type
- // (with the same compiler type) because the symbols have different IDs.
-
- TypeMap more_results;
- auto ClassCompilerDeclCtx = CompilerDeclContext(clang_ast_ctx, ClassDeclCtx);
- symfile->FindTypes(ConstString("NestedClass"), ClassCompilerDeclCtx, 0,
- searched_files, more_results);
- EXPECT_LE(1u, more_results.GetSize());
-
- lldb::TypeSP udt_type = more_results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("NestedClass"), udt_type->GetName());
-
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
-
- EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"),
- udt_type->GetByteSize(nullptr));
-}
-
-TEST_F(SymbolFilePDBTests, TestClassInNamespace) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
-
- auto clang_ast_ctx_or_err =
- symfile->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
- ASSERT_THAT_EXPECTED(clang_ast_ctx_or_err, llvm::Succeeded());
-
- auto clang_ast_ctx =
- llvm::dyn_cast_or_null<TypeSystemClang>(&clang_ast_ctx_or_err.get());
- EXPECT_NE(nullptr, clang_ast_ctx);
-
- clang::ASTContext &ast_ctx = clang_ast_ctx->getASTContext();
-
- auto tu = ast_ctx.getTranslationUnitDecl();
- EXPECT_NE(nullptr, tu);
-
- symfile->ParseDeclsForContext(CompilerDeclContext(
- clang_ast_ctx, static_cast<clang::DeclContext *>(tu)));
-
- auto ns_namespace = symfile->FindNamespace(ConstString("NS"), CompilerDeclContext());
- EXPECT_TRUE(ns_namespace.IsValid());
-
- symfile->FindTypes(ConstString("NSClass"), ns_namespace, 0, searched_files,
- results);
- EXPECT_EQ(1u, results.GetSize());
-
- lldb::TypeSP udt_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString("NSClass"), udt_type->GetName());
-
- CompilerType compiler_type = udt_type->GetForwardCompilerType();
- EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType()));
-
- EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"),
- udt_type->GetByteSize(nullptr));
-}
-
-TEST_F(SymbolFilePDBTests, TestEnumTypes) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- llvm::DenseSet<SymbolFile *> searched_files;
- const char *EnumsToCheck[] = {"Enum", "ShortEnum"};
- for (auto Enum : EnumsToCheck) {
- TypeMap results;
- symfile->FindTypes(ConstString(Enum), CompilerDeclContext(), 0,
- searched_files, results);
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP enum_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString(Enum), enum_type->GetName());
- CompilerType compiler_type = enum_type->GetFullCompilerType();
- EXPECT_TRUE(TypeSystemClang::IsEnumType(compiler_type.GetOpaqueQualType()));
- clang::EnumDecl *enum_decl = TypeSystemClang::GetAsEnumDecl(compiler_type);
- EXPECT_NE(nullptr, enum_decl);
- EXPECT_EQ(2, std::distance(enum_decl->enumerator_begin(),
- enum_decl->enumerator_end()));
-
- std::string sizeof_var = "sizeof_";
- sizeof_var.append(Enum);
- EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
- enum_type->GetByteSize(nullptr));
- }
-}
-
-TEST_F(SymbolFilePDBTests, TestArrayTypes) {
- // In order to get this test working, we need to support lookup by symbol
- // name. Because array
- // types themselves do not have names, only the symbols have names (i.e. the
- // name of the array).
-}
-
-TEST_F(SymbolFilePDBTests, TestFunctionTypes) {
- // In order to get this test working, we need to support lookup by symbol
- // name. Because array
- // types themselves do not have names, only the symbols have names (i.e. the
- // name of the array).
-}
-
-TEST_F(SymbolFilePDBTests, TestTypedefs) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::pdb::IPDBSession &session = symfile->GetPDBSession();
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
-
- const char *TypedefsToCheck[] = {"ClassTypedef", "NSClassTypedef",
- "FuncPointerTypedef",
- "VariadicFuncPointerTypedef"};
- for (auto Typedef : TypedefsToCheck) {
- TypeMap results;
- symfile->FindTypes(ConstString(Typedef), CompilerDeclContext(), 0,
- searched_files, results);
- EXPECT_EQ(1u, results.GetSize());
- lldb::TypeSP typedef_type = results.GetTypeAtIndex(0);
- EXPECT_EQ(ConstString(Typedef), typedef_type->GetName());
- CompilerType compiler_type = typedef_type->GetFullCompilerType();
- TypeSystemClang *clang_type_system =
- llvm::dyn_cast_or_null<TypeSystemClang>(compiler_type.GetTypeSystem());
- EXPECT_TRUE(
- clang_type_system->IsTypedefType(compiler_type.GetOpaqueQualType()));
-
- std::string sizeof_var = "sizeof_";
- sizeof_var.append(Typedef);
- EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var),
- typedef_type->GetByteSize(nullptr));
- }
-}
-
-TEST_F(SymbolFilePDBTests, TestRegexNameMatch) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- TypeMap results;
-
- symfile->FindTypesByRegex(RegularExpression(".*"), 0, results);
- EXPECT_GT(results.GetSize(), 1u);
-
- // We expect no exception thrown if the given regex can't be compiled
- results.Clear();
- symfile->FindTypesByRegex(RegularExpression("**"), 0, results);
- EXPECT_EQ(0u, results.GetSize());
-}
-
-TEST_F(SymbolFilePDBTests, TestMaxMatches) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- const ConstString name("ClassTypedef");
- symfile->FindTypes(name, CompilerDeclContext(), 0, searched_files, results);
- // Try to limit ourselves from 1 to 10 results, otherwise we could
- // be doing this thousands of times. The idea is just to make sure
- // that for a variety of values, the number of limited results
- // always comes out to the number we are expecting.
- uint32_t num_results = results.GetSize();
- uint32_t iterations = std::min(num_results, 10u);
- for (uint32_t i = 1; i <= iterations; ++i) {
- TypeMap more_results;
- symfile->FindTypes(name, CompilerDeclContext(), i, searched_files,
- more_results);
- uint32_t num_limited_results = more_results.GetSize();
- EXPECT_EQ(i, num_limited_results);
- }
-}
-
-TEST_F(SymbolFilePDBTests, TestNullName) {
- FileSpec fspec(m_types_test_exe);
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolFilePDB *symfile =
- static_cast<SymbolFilePDB *>(module->GetSymbolFile());
- llvm::DenseSet<SymbolFile *> searched_files;
- TypeMap results;
- symfile->FindTypes(ConstString(), CompilerDeclContext(), 0, searched_files,
- results);
- EXPECT_EQ(0u, results.GetSize());
-}
-
-TEST_F(SymbolFilePDBTests, TestFindSymbolsWithNameAndType) {
- FileSpec fspec(m_pdb_test_exe.c_str());
- ArchSpec aspec("i686-pc-windows");
- lldb::ModuleSP module = std::make_shared<Module>(fspec, aspec);
-
- SymbolContextList sc_list;
- module->FindSymbolsWithNameAndType(ConstString("?foo@@YAHH@Z"),
- lldb::eSymbolTypeAny, sc_list);
- EXPECT_EQ(1u, sc_list.GetSize());
-
- SymbolContext sc;
- EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc));
- EXPECT_STREQ("int foo(int)",
- sc.GetFunctionName(Mangled::ePreferDemangled).AsCString());
-}
+++ /dev/null
-//===-- ABITest.cpp -------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/ABI.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(MCBasedABI, MapRegisterName) {
- auto map = [](std::string name) {
- MCBasedABI::MapRegisterName(name, "foo", "bar");
- return name;
- };
- EXPECT_EQ("bar", map("foo"));
- EXPECT_EQ("bar0", map("foo0"));
- EXPECT_EQ("bar47", map("foo47"));
- EXPECT_EQ("foo47x", map("foo47x"));
- EXPECT_EQ("fooo47", map("fooo47"));
- EXPECT_EQ("bar47", map("bar47"));
-}
-
+++ /dev/null
-add_lldb_unittest(TargetTests
- ABITest.cpp
- ExecutionContextTest.cpp
- MemoryRegionInfoTest.cpp
- ModuleCacheTest.cpp
- PathMappingListTest.cpp
- RemoteAwarePlatformTest.cpp
- StackFrameRecognizerTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbPluginObjectFileELF
- lldbPluginPlatformLinux
- lldbPluginSymbolFileSymtab
- lldbTarget
- lldbSymbol
- lldbUtility
- lldbUtilityHelpers
- LINK_COMPONENTS
- Support
- )
-
-add_unittest_inputs(TargetTests TestModule.so)
+++ /dev/null
-//===-- ExecutionContextTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/ExecutionContext.h"
-#include "Plugins/Platform/Linux/PlatformLinux.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Target/Platform.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/Endian.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/lldb-enumerations.h"
-#include "lldb/lldb-forward.h"
-#include "lldb/lldb-private-enumerations.h"
-#include "lldb/lldb-private.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace lldb;
-
-namespace {
-class ExecutionContextTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
- FileSystem::Initialize();
- HostInfo::Initialize();
- platform_linux::PlatformLinux::Initialize();
- }
- void TearDown() override {
- platform_linux::PlatformLinux::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- Reproducer::Terminate();
- }
-};
-
-class DummyProcess : public Process {
-public:
- using Process::Process;
-
- bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
- return true;
- }
- Status DoDestroy() override { return {}; }
- void RefreshStateAfterStop() override {}
- size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Status &error) override {
- return 0;
- }
- bool DoUpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override {
- return false;
- }
- ConstString GetPluginName() override { return ConstString("Dummy"); }
- uint32_t GetPluginVersion() override { return 0; }
-};
-} // namespace
-
-TEST_F(ExecutionContextTest, GetByteOrder) {
- ExecutionContext exe_ctx(nullptr, nullptr, nullptr);
- EXPECT_EQ(endian::InlHostByteOrder(), exe_ctx.GetByteOrder());
-}
-
-TEST_F(ExecutionContextTest, GetByteOrderTarget) {
- ArchSpec arch("powerpc64-pc-linux");
-
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp;
- PlatformSP platform_sp;
- Status error = debugger_sp->GetTargetList().CreateTarget(
- *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
- ASSERT_TRUE(target_sp);
- ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
- ASSERT_TRUE(platform_sp);
-
- ExecutionContext target_ctx(target_sp, false);
- EXPECT_EQ(target_sp->GetArchitecture().GetByteOrder(),
- target_ctx.GetByteOrder());
-}
-
-TEST_F(ExecutionContextTest, GetByteOrderProcess) {
- ArchSpec arch("powerpc64-pc-linux");
-
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp;
- PlatformSP platform_sp;
- Status error = debugger_sp->GetTargetList().CreateTarget(
- *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
- ASSERT_TRUE(target_sp);
- ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
- ASSERT_TRUE(platform_sp);
-
- ListenerSP listener_sp(Listener::MakeListener("dummy"));
- ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- ExecutionContext process_ctx(process_sp);
- EXPECT_EQ(process_sp->GetByteOrder(), process_ctx.GetByteOrder());
-}
+++ /dev/null
-// Compile with $CC -nostdlib -shared TestModule.c -o TestModule.so
-// The actual contents of the test module is not important here. I am using this
-// because it
-// produces an extremely tiny (but still perfectly valid) module.
-
-void boom(void) {
- char *BOOM;
- *BOOM = 47;
-}
+++ /dev/null
-//===-- MemoryRegionInfoTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(MemoryRegionInfoTest, Formatv) {
- EXPECT_EQ("yes", llvm::formatv("{0}", MemoryRegionInfo::eYes).str());
- EXPECT_EQ("no", llvm::formatv("{0}", MemoryRegionInfo::eNo).str());
- EXPECT_EQ("don't know", llvm::formatv("{0}", MemoryRegionInfo::eDontKnow).str());
-}
+++ /dev/null
-#include "gtest/gtest.h"
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/SymbolContext.h"
-#include "lldb/Target/ModuleCache.h"
-
-using namespace lldb_private;
-using namespace lldb;
-
-namespace {
-
-class ModuleCacheTest : public testing::Test {
- SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
- subsystems;
-
-public:
- void SetUp() override;
-
-protected:
- FileSpec s_cache_dir;
- std::string s_test_executable;
-
- void TryGetAndPut(const FileSpec &cache_dir, const char *hostname,
- bool expect_download);
-};
-}
-
-static const char dummy_hostname[] = "dummy_hostname";
-static const char dummy_remote_dir[] = "bin";
-static const char module_name[] = "TestModule.so";
-static const char module_uuid[] =
- "F4E7E991-9B61-6AD4-0073-561AC3D9FA10-C043A476";
-static const size_t module_size = 5602;
-
-static FileSpec GetDummyRemotePath() {
- FileSpec fs("/", FileSpec::Style::posix);
- fs.AppendPathComponent(dummy_remote_dir);
- fs.AppendPathComponent(module_name);
- return fs;
-}
-
-static FileSpec GetUuidView(FileSpec spec) {
- spec.AppendPathComponent(".cache");
- spec.AppendPathComponent(module_uuid);
- spec.AppendPathComponent(module_name);
- return spec;
-}
-
-static FileSpec GetSysrootView(FileSpec spec, const char *hostname) {
- spec.AppendPathComponent(hostname);
- spec.AppendPathComponent(dummy_remote_dir);
- spec.AppendPathComponent(module_name);
- return spec;
-}
-
-void ModuleCacheTest::SetUp() {
- s_cache_dir = HostInfo::GetProcessTempDir();
- s_test_executable = GetInputFilePath(module_name);
-}
-
-static void VerifyDiskState(const FileSpec &cache_dir, const char *hostname) {
- FileSpec uuid_view = GetUuidView(cache_dir);
- EXPECT_TRUE(FileSystem::Instance().Exists(uuid_view))
- << "uuid_view is: " << uuid_view.GetCString();
- EXPECT_EQ(module_size, FileSystem::Instance().GetByteSize(uuid_view));
-
- FileSpec sysroot_view = GetSysrootView(cache_dir, hostname);
- EXPECT_TRUE(FileSystem::Instance().Exists(sysroot_view))
- << "sysroot_view is: " << sysroot_view.GetCString();
- EXPECT_EQ(module_size, FileSystem::Instance().GetByteSize(sysroot_view));
-}
-
-void ModuleCacheTest::TryGetAndPut(const FileSpec &cache_dir,
- const char *hostname, bool expect_download) {
- ModuleCache mc;
- ModuleSpec module_spec;
- module_spec.GetFileSpec() = GetDummyRemotePath();
- module_spec.GetUUID().SetFromStringRef(module_uuid);
- module_spec.SetObjectSize(module_size);
- ModuleSP module_sp;
- bool did_create;
- bool download_called = false;
-
- Status error = mc.GetAndPut(
- cache_dir, hostname, module_spec,
- [&download_called, this](const ModuleSpec &module_spec,
- const FileSpec &tmp_download_file_spec) {
- download_called = true;
- EXPECT_STREQ(GetDummyRemotePath().GetCString(),
- module_spec.GetFileSpec().GetCString());
- std::error_code ec = llvm::sys::fs::copy_file(
- s_test_executable, tmp_download_file_spec.GetCString());
- EXPECT_FALSE(ec);
- return Status();
- },
- [](const ModuleSP &module_sp, const FileSpec &tmp_download_file_spec) {
- return Status("Not supported.");
- },
- module_sp, &did_create);
- EXPECT_EQ(expect_download, download_called);
-
- EXPECT_TRUE(error.Success()) << "Error was: " << error.AsCString();
- EXPECT_TRUE(did_create);
- ASSERT_TRUE(bool(module_sp));
-
- SymbolContextList sc_list;
- module_sp->FindFunctionSymbols(ConstString("boom"), eFunctionNameTypeFull,
- sc_list);
- EXPECT_EQ(1u, sc_list.GetSize());
- EXPECT_STREQ(GetDummyRemotePath().GetCString(),
- module_sp->GetPlatformFileSpec().GetCString());
- EXPECT_STREQ(module_uuid, module_sp->GetUUID().GetAsString().c_str());
-}
-
-TEST_F(ModuleCacheTest, GetAndPut) {
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPut");
-
- const bool expect_download = true;
- TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
- VerifyDiskState(test_cache_dir, dummy_hostname);
-}
-
-TEST_F(ModuleCacheTest, GetAndPutUuidExists) {
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPutUuidExists");
-
- FileSpec uuid_view = GetUuidView(test_cache_dir);
- std::error_code ec =
- llvm::sys::fs::create_directories(uuid_view.GetDirectory().GetCString());
- ASSERT_FALSE(ec);
- ec = llvm::sys::fs::copy_file(s_test_executable, uuid_view.GetCString());
- ASSERT_FALSE(ec);
-
- const bool expect_download = false;
- TryGetAndPut(test_cache_dir, dummy_hostname, expect_download);
- VerifyDiskState(test_cache_dir, dummy_hostname);
-}
-
-TEST_F(ModuleCacheTest, GetAndPutStrangeHostname) {
- FileSpec test_cache_dir = s_cache_dir;
- test_cache_dir.AppendPathComponent("GetAndPutStrangeHostname");
-
- const bool expect_download = true;
- TryGetAndPut(test_cache_dir, "tab\tcolon:asterisk*", expect_download);
- VerifyDiskState(test_cache_dir, "tab_colon_asterisk_");
-}
+++ /dev/null
-//===-- PathMappingListTest.cpp -------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/PathMappingList.h"
-#include "lldb/Utility/FileSpec.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "gtest/gtest.h"
-#include <utility>
-
-using namespace lldb_private;
-
-namespace {
-struct Matches {
- FileSpec original;
- FileSpec remapped;
- Matches(const char *o, const char *r) : original(o), remapped(r) {}
- Matches(const char *o, llvm::sys::path::Style style, const char *r)
- : original(o, style), remapped(r) {}
-};
-} // namespace
-
-static void TestPathMappings(const PathMappingList &map,
- llvm::ArrayRef<Matches> matches,
- llvm::ArrayRef<ConstString> fails) {
- ConstString actual_remapped;
- for (const auto &fail : fails) {
- SCOPED_TRACE(fail.GetCString());
- EXPECT_FALSE(map.RemapPath(fail, actual_remapped))
- << "actual_remapped: " << actual_remapped.GetCString();
- }
- for (const auto &match : matches) {
- SCOPED_TRACE(match.original.GetPath() + " -> " + match.remapped.GetPath());
- std::string orig_normalized = match.original.GetPath();
- EXPECT_TRUE(
- map.RemapPath(ConstString(match.original.GetPath()), actual_remapped));
- EXPECT_EQ(FileSpec(actual_remapped.GetStringRef()), match.remapped);
- FileSpec unmapped_spec;
- EXPECT_TRUE(map.ReverseRemapPath(match.remapped, unmapped_spec));
- std::string unmapped_path = unmapped_spec.GetPath();
- EXPECT_EQ(unmapped_path, orig_normalized);
- }
-}
-
-TEST(PathMappingListTest, RelativeTests) {
- Matches matches[] = {
- {".", "/tmp"},
- {"./", "/tmp"},
- {"./////", "/tmp"},
- {"./foo.c", "/tmp/foo.c"},
- {"foo.c", "/tmp/foo.c"},
- {"./bar/foo.c", "/tmp/bar/foo.c"},
- {"bar/foo.c", "/tmp/bar/foo.c"},
- };
- ConstString fails[] = {
-#ifdef _WIN32
- ConstString("C:\\"),
- ConstString("C:\\a"),
-#else
- ConstString("/a"),
- ConstString("/"),
-#endif
- };
- PathMappingList map;
- map.Append(ConstString("."), ConstString("/tmp"), false);
- TestPathMappings(map, matches, fails);
- PathMappingList map2;
- map2.Append(ConstString(""), ConstString("/tmp"), false);
- TestPathMappings(map, matches, fails);
-}
-
-TEST(PathMappingListTest, AbsoluteTests) {
- PathMappingList map;
- map.Append(ConstString("/old"), ConstString("/new"), false);
- Matches matches[] = {
- {"/old", "/new"},
- {"/old/", "/new"},
- {"/old/foo/.", "/new/foo"},
- {"/old/foo.c", "/new/foo.c"},
- {"/old/foo.c/.", "/new/foo.c"},
- {"/old/./foo.c", "/new/foo.c"},
- };
- ConstString fails[] = {
- ConstString("/foo"),
- ConstString("/"),
- ConstString("foo.c"),
- ConstString("./foo.c"),
- ConstString("../foo.c"),
- ConstString("../bar/foo.c"),
- };
- TestPathMappings(map, matches, fails);
-}
-
-TEST(PathMappingListTest, RemapRoot) {
- PathMappingList map;
- map.Append(ConstString("/"), ConstString("/new"), false);
- Matches matches[] = {
- {"/old", "/new/old"},
- {"/old/", "/new/old"},
- {"/old/foo/.", "/new/old/foo"},
- {"/old/foo.c", "/new/old/foo.c"},
- {"/old/foo.c/.", "/new/old/foo.c"},
- {"/old/./foo.c", "/new/old/foo.c"},
- };
- ConstString fails[] = {
- ConstString("foo.c"),
- ConstString("./foo.c"),
- ConstString("../foo.c"),
- ConstString("../bar/foo.c"),
- };
- TestPathMappings(map, matches, fails);
-}
-
-#ifndef _WIN32
-TEST(PathMappingListTest, CrossPlatformTests) {
- PathMappingList map;
- map.Append(ConstString(R"(C:\old)"), ConstString("/new"), false);
- Matches matches[] = {
- {R"(C:\old)", llvm::sys::path::Style::windows, "/new"},
- {R"(C:\old\)", llvm::sys::path::Style::windows, "/new"},
- {R"(C:\old\foo\.)", llvm::sys::path::Style::windows, "/new/foo"},
- {R"(C:\old\foo.c)", llvm::sys::path::Style::windows, "/new/foo.c"},
- {R"(C:\old\foo.c\.)", llvm::sys::path::Style::windows, "/new/foo.c"},
- {R"(C:\old\.\foo.c)", llvm::sys::path::Style::windows, "/new/foo.c"},
- };
- ConstString fails[] = {
- ConstString("/foo"),
- ConstString("/"),
- ConstString("foo.c"),
- ConstString("./foo.c"),
- ConstString("../foo.c"),
- ConstString("../bar/foo.c"),
- };
- TestPathMappings(map, matches, fails);
-}
-#endif
+++ /dev/null
-//===-- RemoteAwarePlatformTest.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/RemoteAwarePlatform.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Target/Platform.h"
-#include "lldb/Target/Process.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb;
-using namespace testing;
-
-class RemoteAwarePlatformTester : public RemoteAwarePlatform {
-public:
- using RemoteAwarePlatform::RemoteAwarePlatform;
-
- MOCK_METHOD0(GetDescription, const char *());
- MOCK_METHOD0(GetPluginVersion, uint32_t());
- MOCK_METHOD0(GetPluginName, ConstString());
- MOCK_METHOD2(GetSupportedArchitectureAtIndex, bool(uint32_t, ArchSpec &));
- MOCK_METHOD4(Attach,
- ProcessSP(ProcessAttachInfo &, Debugger &, Target *, Status &));
- MOCK_METHOD0(CalculateTrapHandlerSymbolNames, void());
-
- void SetRemotePlatform(lldb::PlatformSP platform) {
- m_remote_platform_sp = platform;
- }
-};
-
-class TargetPlatformTester : public Platform {
-public:
- using Platform::Platform;
-
- MOCK_METHOD0(GetDescription, const char *());
- MOCK_METHOD0(GetPluginVersion, uint32_t());
- MOCK_METHOD0(GetPluginName, ConstString());
- MOCK_METHOD2(GetSupportedArchitectureAtIndex, bool(uint32_t, ArchSpec &));
- MOCK_METHOD4(Attach,
- ProcessSP(ProcessAttachInfo &, Debugger &, Target *, Status &));
- MOCK_METHOD0(CalculateTrapHandlerSymbolNames, void());
- MOCK_METHOD0(GetUserIDResolver, UserIDResolver &());
-
- MOCK_METHOD2(ResolveExecutable,
- std::pair<Status, ModuleSP>(const ModuleSpec &,
- const FileSpecList *));
- Status
- ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) /*override*/ {
- auto pair = ResolveExecutable(module_spec, module_search_paths_ptr);
- exe_module_sp = pair.second;
- return pair.first;
- }
-};
-
-namespace {
-class RemoteAwarePlatformTest : public testing::Test {
-public:
- static void SetUpTestCase() { FileSystem::Initialize(); }
- static void TearDownTestCase() { FileSystem::Terminate(); }
-};
-} // namespace
-
-TEST_F(RemoteAwarePlatformTest, TestResolveExecutabelOnClientByPlatform) {
- ModuleSpec executable_spec;
- ModuleSP expected_executable(new Module(executable_spec));
-
- auto platform_sp = std::make_shared<TargetPlatformTester>(false);
- EXPECT_CALL(*platform_sp, ResolveExecutable(_, _))
- .WillRepeatedly(Return(std::make_pair(Status(), expected_executable)));
-
- RemoteAwarePlatformTester platform(false);
- EXPECT_CALL(platform, GetSupportedArchitectureAtIndex(_, _))
- .WillRepeatedly(Return(false));
-
- platform.SetRemotePlatform(platform_sp);
-
- ModuleSP resolved_sp;
- lldb_private::Status status =
- platform.ResolveExecutable(executable_spec, resolved_sp, nullptr);
-
- ASSERT_TRUE(status.Success());
- EXPECT_EQ(expected_executable.get(), resolved_sp.get());
-}
+++ /dev/null
-//===-- StackFrameRecognizerTest.cpp --------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/StackFrameRecognizer.h"
-#include "Plugins/Platform/Linux/PlatformLinux.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/lldb-enumerations.h"
-#include "lldb/lldb-forward.h"
-#include "lldb/lldb-private-enumerations.h"
-#include "lldb/lldb-private.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace lldb;
-
-namespace {
-class StackFrameRecognizerTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
- FileSystem::Initialize();
- HostInfo::Initialize();
-
- // Pretend Linux is the host platform.
- platform_linux::PlatformLinux::Initialize();
- ArchSpec arch("powerpc64-pc-linux");
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
- }
-
- void TearDown() override {
- platform_linux::PlatformLinux::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- Reproducer::Terminate();
- }
-};
-
-class DummyStackFrameRecognizer : public StackFrameRecognizer {
-public:
- std::string GetName() override { return "Dummy StackFrame Recognizer"; }
-};
-
-void RegisterDummyStackFrameRecognizer(StackFrameRecognizerManager &manager) {
- RegularExpressionSP module_regex_sp = nullptr;
- RegularExpressionSP symbol_regex_sp(new RegularExpression("boom"));
-
- StackFrameRecognizerSP dummy_recognizer_sp(new DummyStackFrameRecognizer());
-
- manager.AddRecognizer(dummy_recognizer_sp, module_regex_sp, symbol_regex_sp,
- false);
-}
-
-} // namespace
-
-TEST_F(StackFrameRecognizerTest, NullModuleRegex) {
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- StackFrameRecognizerManager manager;
-
- RegisterDummyStackFrameRecognizer(manager);
-
- bool any_printed = false;
- manager.ForEach([&any_printed](uint32_t recognizer_id, std::string name,
- std::string function,
- llvm::ArrayRef<ConstString> symbols,
- bool regexp) { any_printed = true; });
-
- EXPECT_TRUE(any_printed);
-}
+++ /dev/null
-set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
-add_lldb_library(lldbUtilityHelpers
- MockTildeExpressionResolver.cpp
- TestUtilities.cpp
-
- LINK_LIBS
- lldbUtility
- gtest
-
- LINK_COMPONENTS
- Support
- ObjectYAML
- )
-
-add_subdirectory(Symbol)
+++ /dev/null
-//===-- NativeProcessTestUtils.cpp ------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_HOST_NATIVEPROCESSTESTUTILS_H
-
-#include "lldb/Host/common/NativeProcessProtocol.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-
-using namespace lldb_private;
-using namespace lldb;
-using namespace testing;
-
-namespace lldb_private {
-
-class MockDelegate : public NativeProcessProtocol::NativeDelegate {
-public:
- MOCK_METHOD1(InitializeDelegate, void(NativeProcessProtocol *Process));
- MOCK_METHOD2(ProcessStateChanged,
- void(NativeProcessProtocol *Process, StateType State));
- MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process));
- MOCK_METHOD2(NewSubprocessImpl,
- void(NativeProcessProtocol *parent_process,
- std::unique_ptr<NativeProcessProtocol> &child_process));
- // This is a hack to avoid MOCK_METHOD2 incompatibility with std::unique_ptr
- // passed as value.
- void NewSubprocess(NativeProcessProtocol *parent_process,
- std::unique_ptr<NativeProcessProtocol> child_process) {
- NewSubprocessImpl(parent_process, child_process);
- }
-};
-
-// NB: This class doesn't use the override keyword to avoid
-// -Winconsistent-missing-override warnings from the compiler. The
-// inconsistency comes from the overriding definitions in the MOCK_*** macros.
-template <typename T> class MockProcess : public T {
-public:
- MockProcess(NativeProcessProtocol::NativeDelegate &Delegate,
- const ArchSpec &Arch, lldb::pid_t Pid = 1)
- : T(Pid, -1, Delegate), Arch(Arch) {}
-
- MOCK_METHOD1(Resume, Status(const ResumeActionList &ResumeActions));
- MOCK_METHOD0(Halt, Status());
- MOCK_METHOD0(Detach, Status());
- MOCK_METHOD1(Signal, Status(int Signo));
- MOCK_METHOD0(Kill, Status());
- MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t());
- MOCK_METHOD0(UpdateThreads, size_t());
- MOCK_CONST_METHOD0(GetAuxvData,
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>());
- MOCK_METHOD2(GetLoadedModuleFileSpec,
- Status(const char *ModulePath, FileSpec &Spec));
- MOCK_METHOD2(GetFileLoadAddress,
- Status(const llvm::StringRef &FileName, addr_t &Addr));
-
- const ArchSpec &GetArchitecture() const /*override*/ { return Arch; }
- Status SetBreakpoint(lldb::addr_t Addr, uint32_t Size,
- bool Hardware) /*override*/ {
- if (Hardware)
- return this->SetHardwareBreakpoint(Addr, Size);
- else
- return this->SetSoftwareBreakpoint(Addr, Size);
- }
-
- // Redirect base class Read/Write Memory methods to functions whose signatures
- // are more mock-friendly.
- Status ReadMemory(addr_t Addr, void *Buf, size_t Size,
- size_t &BytesRead) /*override*/ {
- auto ExpectedMemory = this->ReadMemory(Addr, Size);
- if (!ExpectedMemory) {
- BytesRead = 0;
- return Status(ExpectedMemory.takeError());
- }
- BytesRead = ExpectedMemory->size();
- assert(BytesRead <= Size);
- std::memcpy(Buf, ExpectedMemory->data(), BytesRead);
- return Status();
- }
-
- Status WriteMemory(addr_t Addr, const void *Buf, size_t Size,
- size_t &BytesWritten) /*override*/ {
- auto ExpectedBytes = this->WriteMemory(
- Addr, llvm::makeArrayRef(static_cast<const uint8_t *>(Buf), Size));
- if (!ExpectedBytes) {
- BytesWritten = 0;
- return Status(ExpectedBytes.takeError());
- }
- BytesWritten = *ExpectedBytes;
- return Status();
- }
-
- MOCK_METHOD2(ReadMemory,
- llvm::Expected<std::vector<uint8_t>>(addr_t Addr, size_t Size));
- MOCK_METHOD2(WriteMemory,
- llvm::Expected<size_t>(addr_t Addr,
- llvm::ArrayRef<uint8_t> Data));
-
- using T::GetSoftwareBreakpointTrapOpcode;
- llvm::Expected<std::vector<uint8_t>> ReadMemoryWithoutTrap(addr_t Addr,
- size_t Size) {
- std::vector<uint8_t> Data(Size, 0);
- size_t BytesRead;
- Status ST =
- T::ReadMemoryWithoutTrap(Addr, Data.data(), Data.size(), BytesRead);
- if (ST.Fail())
- return ST.ToError();
- Data.resize(BytesRead);
- return std::move(Data);
- }
-
-private:
- ArchSpec Arch;
-};
-
-class FakeMemory {
-public:
- FakeMemory(llvm::ArrayRef<uint8_t> Data, addr_t start_addr = 0)
- : Data(Data), m_start_addr(start_addr) {}
-
- FakeMemory(const void *Data, size_t data_size, addr_t start_addr = 0)
- : Data((const uint8_t *)Data, ((const uint8_t *)Data) + data_size),
- m_start_addr(start_addr) {}
-
- llvm::Expected<std::vector<uint8_t>> Read(addr_t Addr, size_t Size) {
- Addr -= m_start_addr;
- if (Addr >= Data.size())
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Address out of range.");
- Size = std::min(Size, Data.size() - (size_t)Addr);
- auto Begin = std::next(Data.begin(), Addr);
- return std::vector<uint8_t>(Begin, std::next(Begin, Size));
- }
-
- llvm::Expected<size_t> Write(addr_t Addr, llvm::ArrayRef<uint8_t> Chunk) {
- Addr -= m_start_addr;
- if (Addr >= Data.size())
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "Address out of range.");
- size_t Size = std::min(Chunk.size(), Data.size() - (size_t)Addr);
- std::copy_n(Chunk.begin(), Size, &Data[Addr]);
- return Size;
- }
-
-private:
- std::vector<uint8_t> Data;
- addr_t m_start_addr;
-};
-} // namespace lldb_private
-
-#endif
+++ /dev/null
-//===-- MockTildeExpressionResolver.cpp -----------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "MockTildeExpressionResolver.h"
-#include "llvm/Support/Path.h"
-
-using namespace lldb_private;
-using namespace llvm;
-
-MockTildeExpressionResolver::MockTildeExpressionResolver(StringRef CurrentUser,
- StringRef HomeDir)
- : CurrentUser(CurrentUser) {
- UserDirectories.insert(std::make_pair(CurrentUser, HomeDir));
-}
-
-void MockTildeExpressionResolver::AddKnownUser(StringRef User,
- StringRef HomeDir) {
- assert(UserDirectories.find(User) == UserDirectories.end());
- UserDirectories.insert(std::make_pair(User, HomeDir));
-}
-
-void MockTildeExpressionResolver::Clear() {
- CurrentUser = StringRef();
- UserDirectories.clear();
-}
-
-void MockTildeExpressionResolver::SetCurrentUser(StringRef User) {
- assert(UserDirectories.find(User) != UserDirectories.end());
- CurrentUser = User;
-}
-
-bool MockTildeExpressionResolver::ResolveExact(StringRef Expr,
- SmallVectorImpl<char> &Output) {
- Output.clear();
-
- assert(!llvm::any_of(
- Expr, [](char c) { return llvm::sys::path::is_separator(c); }));
- assert(Expr.empty() || Expr[0] == '~');
- Expr = Expr.drop_front();
- if (Expr.empty()) {
- auto Dir = UserDirectories[CurrentUser];
- Output.append(Dir.begin(), Dir.end());
- return true;
- }
-
- for (const auto &User : UserDirectories) {
- if (User.getKey() != Expr)
- continue;
- Output.append(User.getValue().begin(), User.getValue().end());
- return true;
- }
- return false;
-}
-
-bool MockTildeExpressionResolver::ResolvePartial(StringRef Expr,
- StringSet<> &Output) {
- Output.clear();
-
- assert(!llvm::any_of(
- Expr, [](char c) { return llvm::sys::path::is_separator(c); }));
- assert(Expr.empty() || Expr[0] == '~');
- Expr = Expr.drop_front();
-
- SmallString<16> QualifiedName("~");
- for (const auto &User : UserDirectories) {
- if (!User.getKey().startswith(Expr))
- continue;
- QualifiedName.resize(1);
- QualifiedName.append(User.getKey().begin(), User.getKey().end());
- Output.insert(QualifiedName);
- }
-
- return !Output.empty();
-}
+++ /dev/null
-//===-- MockTildeExpressionResolver.h ---------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_MOCKTILDEEXPRESSIONRESOLVER_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_MOCKTILDEEXPRESSIONRESOLVER_H
-
-#include "lldb/Utility/TildeExpressionResolver.h"
-
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
-
-namespace lldb_private {
-class MockTildeExpressionResolver : public TildeExpressionResolver {
- llvm::StringRef CurrentUser;
- llvm::StringMap<llvm::StringRef> UserDirectories;
-
-public:
- MockTildeExpressionResolver(llvm::StringRef CurrentUser,
- llvm::StringRef HomeDir);
-
- void AddKnownUser(llvm::StringRef User, llvm::StringRef HomeDir);
- void Clear();
- void SetCurrentUser(llvm::StringRef User);
-
- bool ResolveExact(llvm::StringRef Expr,
- llvm::SmallVectorImpl<char> &Output) override;
- bool ResolvePartial(llvm::StringRef Expr, llvm::StringSet<> &Output) override;
-};
-} // namespace lldb_private
-
-#endif
+++ /dev/null
-//===- SubsystemRAII.h ------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SUBSYSTEMRAII_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_SUBSYSTEMRAII_H
-
-#include "llvm/Support/Error.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-#include <type_traits>
-
-namespace lldb_private {
-
-namespace detail {
-/// Initializes and deinitializes a single subsystem.
-/// @see SubsystemRAII
-template <typename T> struct SubsystemRAIICase {
-
- /// Calls ::Initialize if it has a void return type.
- template <typename U = T>
- typename std::enable_if<
- std::is_same<decltype(U::Initialize()), void>::value>::type
- CallInitialize() {
- T::Initialize();
- }
-
- /// Calls ::Initialize if it has a llvm::Error return type and checks
- /// the Error instance for success.
- template <typename U = T>
- typename std::enable_if<
- std::is_same<decltype(U::Initialize()), llvm::Error>::value>::type
- CallInitialize() {
- ASSERT_THAT_ERROR(T::Initialize(), llvm::Succeeded());
- }
-
- SubsystemRAIICase() { CallInitialize(); }
- ~SubsystemRAIICase() { T::Terminate(); }
-};
-} // namespace detail
-
-template <typename... T> class SubsystemRAII {};
-
-/// RAII for initializing and deinitializing LLDB subsystems.
-///
-/// This RAII takes care of calling the Initialize and Terminate functions for
-/// the subsystems specified by its template arguments. The ::Initialize
-/// functions are called on construction for each subsystem template parameter
-/// in the order in which they are passed as template parameters.
-/// The ::Terminate functions are called in the reverse order at destruction
-/// time.
-///
-/// If the ::Initialize function returns an llvm::Error this function handles
-/// the Error instance (by checking that there is no error).
-///
-/// Constructing this RAII in a scope like this:
-///
-/// @code{.cpp}
-/// {
-/// SubsystemRAII<FileSystem, HostInfo, Socket> Subsystems;
-/// DoingTestWork();
-/// }
-/// @endcode
-///
-/// is equivalent to the following code:
-///
-/// @code{.cpp}
-/// {
-/// FileSystem::Initialize();
-/// HostInfo::Initialize();
-/// ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded());
-///
-/// DoingTestWork();
-///
-/// Socket::Terminate();
-/// FileSystem::Terminate();
-/// HostInfo::Terminate();
-/// }
-/// @endcode
-template <typename T, typename... Ts> class SubsystemRAII<T, Ts...> {
- detail::SubsystemRAIICase<T> CurrentSubsystem;
- SubsystemRAII<Ts...> RemainingSubsystems;
-};
-} // namespace lldb_private
-
-#endif // LLDB_UNITTESTS_TESTINGSUPPORT_SUBSYSTEMRAII_H
+++ /dev/null
-set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
-add_lldb_library(lldbSymbolHelpers
- YAMLModuleTester.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbPluginExpressionParserClang
- lldbPluginObjectFileELF
- lldbPluginSymbolFileDWARF
- lldbPluginTypeSystemClang
- lldbUtilityHelpers
- LLVMTestingSupport
-
- LINK_COMPONENTS
- ObjectYAML
- )
+++ /dev/null
-//===- ClangTestUtils.h -----------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H
-
-#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "lldb/Host/HostInfo.h"
-
-namespace lldb_private {
-namespace clang_utils {
-inline clang::DeclarationName getDeclarationName(TypeSystemClang &ast,
- llvm::StringRef name) {
- clang::IdentifierInfo &II = ast.getASTContext().Idents.get(name);
- return ast.getASTContext().DeclarationNames.getIdentifier(&II);
-}
-
-inline std::unique_ptr<TypeSystemClang> createAST() {
- return std::make_unique<TypeSystemClang>("test ASTContext",
- HostInfo::GetTargetTriple());
-}
-
-inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) {
- return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(),
- OptionalClangModuleID(),
- lldb::AccessType::eAccessPublic, name, 0,
- lldb::LanguageType::eLanguageTypeC);
-}
-
-/// Create a record with the given name and a field with the given type
-/// and name.
-inline CompilerType createRecordWithField(TypeSystemClang &ast,
- llvm::StringRef record_name,
- CompilerType field_type,
- llvm::StringRef field_name) {
- CompilerType t = createRecord(ast, record_name);
-
- TypeSystemClang::StartTagDeclarationDefinition(t);
- ast.AddFieldToRecordType(t, field_name, field_type,
- lldb::AccessType::eAccessPublic, 7);
- TypeSystemClang::CompleteTagDeclarationDefinition(t);
-
- return t;
-}
-
-/// Constructs a TypeSystemClang that contains a single RecordDecl that contains
-/// a single FieldDecl. Utility class as this setup is a common starting point
-/// for unit test that exercise the ASTImporter.
-struct SourceASTWithRecord {
- std::unique_ptr<TypeSystemClang> ast;
- CompilerType record_type;
- clang::RecordDecl *record_decl = nullptr;
- clang::FieldDecl *field_decl = nullptr;
- SourceASTWithRecord() {
- ast = createAST();
- record_type = createRecordWithField(
- *ast, "Source", ast->GetBasicType(lldb::BasicType::eBasicTypeChar),
- "a_field");
- record_decl =
- llvm::cast<clang::RecordDecl>(ClangUtil::GetAsTagDecl(record_type));
- field_decl = *record_decl->fields().begin();
- assert(field_decl);
- }
-};
-
-} // namespace clang_utils
-} // namespace lldb_private
-
-#endif
+++ /dev/null
-//===-- YAMLModuleTester.cpp ----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestingSupport/Symbol/YAMLModuleTester.h"
-#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "lldb/Core/Section.h"
-#include "llvm/ObjectYAML/DWARFEmitter.h"
-
-using namespace lldb_private;
-
-YAMLModuleTester::YAMLModuleTester(llvm::StringRef yaml_data) {
- llvm::Expected<TestFile> File = TestFile::fromYaml(yaml_data);
- EXPECT_THAT_EXPECTED(File, llvm::Succeeded());
- m_file = std::move(*File);
-
- m_module_sp = std::make_shared<Module>(m_file->moduleSpec());
- auto &symfile = *llvm::cast<SymbolFileDWARF>(m_module_sp->GetSymbolFile());
-
- m_dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0);
-}
+++ /dev/null
-//===- YAMLModuleTester.h ---------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_YAMLMODULETESTER_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_YAMLMODULETESTER_H
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
-#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Host/HostInfo.h"
-
-namespace lldb_private {
-
-/// Helper class that can construct a module from YAML and evaluate
-/// DWARF expressions on it.
-class YAMLModuleTester {
-protected:
- SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF,
- SymbolFileDWARF>
- subsystems;
- llvm::Optional<TestFile> m_file;
- lldb::ModuleSP m_module_sp;
- DWARFUnit *m_dwarf_unit;
-
-public:
- /// Parse the debug info sections from the YAML description.
- YAMLModuleTester(llvm::StringRef yaml_data);
- DWARFUnit *GetDwarfUnit() const { return m_dwarf_unit; }
- lldb::ModuleSP GetModule() const { return m_module_sp; }
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_YAMLMODULETESTER_H
+++ /dev/null
-//===-- TestUtilities.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestUtilities.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ObjectYAML/yaml2obj.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/YAMLTraits.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-extern const char *TestMainArgv0;
-
-std::string lldb_private::GetInputFilePath(const llvm::Twine &name) {
- llvm::SmallString<128> result = llvm::sys::path::parent_path(TestMainArgv0);
- llvm::sys::fs::make_absolute(result);
- llvm::sys::path::append(result, "Inputs", name);
- return std::string(result.str());
-}
-
-llvm::Expected<TestFile> TestFile::fromYaml(llvm::StringRef Yaml) {
- std::string Buffer;
- llvm::raw_string_ostream OS(Buffer);
- llvm::yaml::Input YIn(Yaml);
- if (!llvm::yaml::convertYAML(YIn, OS, [](const llvm::Twine &Msg) {}))
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "convertYAML() failed");
- return TestFile(std::move(Buffer));
-}
-
-llvm::Expected<TestFile> TestFile::fromYamlFile(const llvm::Twine &Name) {
- auto BufferOrError =
- llvm::MemoryBuffer::getFile(GetInputFilePath(Name), /*IsText=*/false,
- /*RequiresNullTerminator=*/false);
- if (!BufferOrError)
- return llvm::errorCodeToError(BufferOrError.getError());
- return fromYaml(BufferOrError.get()->getBuffer());
-}
+++ /dev/null
-//===- TestUtilities.h ------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
-#define LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
-
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Utility/DataBuffer.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileUtilities.h"
-#include <string>
-
-#define ASSERT_NO_ERROR(x) \
- if (std::error_code ASSERT_NO_ERROR_ec = x) { \
- llvm::SmallString<128> MessageStorage; \
- llvm::raw_svector_ostream Message(MessageStorage); \
- Message << #x ": did not return errc::success.\n" \
- << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
- << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
- GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
- } else { \
- }
-
-namespace lldb_private {
-std::string GetInputFilePath(const llvm::Twine &name);
-
-class TestFile {
-public:
- static llvm::Expected<TestFile> fromYaml(llvm::StringRef Yaml);
- static llvm::Expected<TestFile> fromYamlFile(const llvm::Twine &Name);
-
- ModuleSpec moduleSpec() {
- return ModuleSpec(FileSpec(), UUID(), dataBuffer());
- }
-
-private:
- TestFile(std::string &&Buffer) : Buffer(std::move(Buffer)) {}
-
- lldb::DataBufferSP dataBuffer() {
- auto *Data = reinterpret_cast<const uint8_t *>(Buffer.data());
- return std::make_shared<DataBufferUnowned>(const_cast<uint8_t *>(Data),
- Buffer.size());
- }
-
- std::string Buffer;
-};
-}
-
-#endif
+++ /dev/null
-
-module lldb_TestingSupport {
- requires cplusplus
- module TestUtilities { header "TestUtilities.h" export * }
- module MockTildeExpressionResolver { header "MockTildeExpressionResolver.h" export * }
-}
-
-module lldb_TestingSupport_Host {
- requires cplusplus
- module NativeProcessTestUtils { header "Host/NativeProcessTestUtils.h" export * }
-}
-
-module lldb_TestingSupport_Symbol {
- requires cplusplus
- module ClangTestUtils { header "Symbol/ClangTestUtils.h" export * }
- module YAMLModuleTester { header "Symbol/YAMLModuleTester.h" export * }
-}
+++ /dev/null
-add_lldb_unittest(ThreadTests
- ThreadTest.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbTarget
- lldbSymbol
- lldbUtility
- lldbUtilityHelpers
- lldbInterpreter
- lldbBreakpoint
- lldbPluginPlatformLinux
- )
-
+++ /dev/null
-//===-- ThreadTest.cpp ------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/Thread.h"
-#include "Plugins/Platform/Linux/PlatformLinux.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/Reproducer.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-using namespace lldb;
-
-namespace {
-class ThreadTest : public ::testing::Test {
-public:
- void SetUp() override {
- llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
- FileSystem::Initialize();
- HostInfo::Initialize();
- platform_linux::PlatformLinux::Initialize();
- }
- void TearDown() override {
- platform_linux::PlatformLinux::Terminate();
- HostInfo::Terminate();
- FileSystem::Terminate();
- Reproducer::Terminate();
- }
-};
-
-class DummyProcess : public Process {
-public:
- using Process::Process;
-
- bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
- return true;
- }
- Status DoDestroy() override { return {}; }
- void RefreshStateAfterStop() override {}
- size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
- Status &error) override {
- return 0;
- }
- bool DoUpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override {
- return false;
- }
- ConstString GetPluginName() override { return ConstString("Dummy"); }
- uint32_t GetPluginVersion() override { return 0; }
-
- ProcessModID &GetModIDNonConstRef() { return m_mod_id; }
-};
-
-class DummyThread : public Thread {
-public:
- using Thread::Thread;
-
- ~DummyThread() override { DestroyThread(); }
-
- void RefreshStateAfterStop() override {}
-
- lldb::RegisterContextSP GetRegisterContext() override { return nullptr; }
-
- lldb::RegisterContextSP
- CreateRegisterContextForFrame(StackFrame *frame) override {
- return nullptr;
- }
-
- bool CalculateStopInfo() override { return false; }
-
- bool IsStillAtLastBreakpointHit() override { return true; }
-};
-} // namespace
-
-TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) {
- PlatformSP platform_sp;
- TargetSP target_sp;
- debugger_sp->GetTargetList().CreateTarget(
- *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
-
- return target_sp;
-}
-
-TEST_F(ThreadTest, SetStopInfo) {
- ArchSpec arch("powerpc64-pc-linux");
-
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp = CreateTarget(debugger_sp, arch);
- ASSERT_TRUE(target_sp);
-
- ListenerSP listener_sp(Listener::MakeListener("dummy"));
- ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());
-
- ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
- ASSERT_TRUE(thread_sp);
-
- StopInfoSP stopinfo_sp =
- StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp.get(), 0);
- ASSERT_TRUE(stopinfo_sp->IsValid() == true);
-
- /*
- Should make stopinfo valid.
- */
- process->GetModIDNonConstRef().BumpStopID();
- ASSERT_TRUE(stopinfo_sp->IsValid() == false);
-
- thread_sp->SetStopInfo(stopinfo_sp);
- ASSERT_TRUE(stopinfo_sp->IsValid() == true);
-}
-
-TEST_F(ThreadTest, GetPrivateStopInfo) {
- ArchSpec arch("powerpc64-pc-linux");
-
- Platform::SetHostPlatform(
- platform_linux::PlatformLinux::CreateInstance(true, &arch));
-
- DebuggerSP debugger_sp = Debugger::CreateInstance();
- ASSERT_TRUE(debugger_sp);
-
- TargetSP target_sp = CreateTarget(debugger_sp, arch);
- ASSERT_TRUE(target_sp);
-
- ListenerSP listener_sp(Listener::MakeListener("dummy"));
- ProcessSP process_sp = std::make_shared<DummyProcess>(target_sp, listener_sp);
- ASSERT_TRUE(process_sp);
-
- DummyProcess *process = static_cast<DummyProcess *>(process_sp.get());
-
- ThreadSP thread_sp = std::make_shared<DummyThread>(*process_sp.get(), 0);
- ASSERT_TRUE(thread_sp);
-
- StopInfoSP stopinfo_sp =
- StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp.get(), 0);
- ASSERT_TRUE(stopinfo_sp);
-
- thread_sp->SetStopInfo(stopinfo_sp);
-
- /*
- Should make stopinfo valid if thread is at last breakpoint hit.
- */
- process->GetModIDNonConstRef().BumpStopID();
- ASSERT_TRUE(stopinfo_sp->IsValid() == false);
- StopInfoSP new_stopinfo_sp = thread_sp->GetPrivateStopInfo();
- ASSERT_TRUE(new_stopinfo_sp && stopinfo_sp->IsValid() == true);
-}
+++ /dev/null
-add_lldb_unittest(Arm64InstEmulationTests
- TestArm64InstEmulation.cpp
- LINK_LIBS
- lldbCore
- lldbSymbol
- lldbTarget
- lldbPluginUnwindAssemblyInstEmulation
- lldbPluginDisassemblerLLVMC
- lldbPluginInstructionARM64
- lldbPluginProcessUtility
- LINK_COMPONENTS
- Support
- ${LLVM_TARGETS_TO_BUILD})
+++ /dev/null
-//===-- TestArm64InstEmulation.cpp ----------------------------------------===//
-
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include <vector>
-
-#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/AddressRange.h"
-#include "lldb/Symbol/UnwindPlan.h"
-#include "lldb/Target/UnwindAssembly.h"
-#include "lldb/Utility/ArchSpec.h"
-
-#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
-#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
-#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestArm64InstEmulation : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
- // virtual void SetUp() override { }
- // virtual void TearDown() override { }
-
-protected:
-};
-
-void TestArm64InstEmulation::SetUpTestCase() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
- DisassemblerLLVMC::Initialize();
- EmulateInstructionARM64::Initialize();
-}
-
-void TestArm64InstEmulation::TearDownTestCase() {
- DisassemblerLLVMC::Terminate();
- EmulateInstructionARM64::Terminate();
-}
-
-TEST_F(TestArm64InstEmulation, TestSimpleDarwinFunction) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // 'int main() { }' compiled for arm64-apple-ios with clang
- uint8_t data[] = {
- 0xfd, 0x7b, 0xbf, 0xa9, // 0xa9bf7bfd : stp x29, x30, [sp, #-0x10]!
- 0xfd, 0x03, 0x00, 0x91, // 0x910003fd : mov x29, sp
- 0xff, 0x43, 0x00, 0xd1, // 0xd10043ff : sub sp, sp, #0x10
-
- 0xbf, 0x03, 0x00, 0x91, // 0x910003bf : mov sp, x29
- 0xfd, 0x7b, 0xc1, 0xa8, // 0xa8c17bfd : ldp x29, x30, [sp], #16
- 0xc0, 0x03, 0x5f, 0xd6, // 0xd65f03c0 : ret
- };
-
- // UnwindPlan we expect:
-
- // row[0]: 0: CFA=sp +0 =>
- // row[1]: 4: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
- // row[2]: 8: CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
- // row[2]: 16: CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
- // row[3]: 20: CFA=sp +0 => fp= <same> lr= <same>
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // CFA=sp +0
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // CFA=fp+16 => fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(8ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // CFA=sp+16 => fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // CFA=sp +0 => fp= <same> lr= <same>
- row_sp = unwind_plan.GetRowForFunctionOffset(20);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestMediumDarwinFunction) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // disassembly of -[NSPlaceholderString initWithBytes:length:encoding:]
- // from Foundation for iOS.
- uint8_t data[] = {
- 0xf6, 0x57, 0xbd, 0xa9, // 0: 0xa9bd57f6 stp x22, x21, [sp, #-48]!
- 0xf4, 0x4f, 0x01, 0xa9, // 4: 0xa9014ff4 stp x20, x19, [sp, #16]
- 0xfd, 0x7b, 0x02, 0xa9, // 8: 0xa9027bfd stp x29, x30, [sp, #32]
- 0xfd, 0x83, 0x00, 0x91, // 12: 0x910083fd add x29, sp, #32
- 0xff, 0x43, 0x00, 0xd1, // 16: 0xd10043ff sub sp, sp, #16
-
- // [... function body ...]
- 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
-
- 0xbf, 0x83, 0x00, 0xd1, // 24: 0xd10083bf sub sp, x29, #32
- 0xfd, 0x7b, 0x42, 0xa9, // 28: 0xa9427bfd ldp x29, x30, [sp, #32]
- 0xf4, 0x4f, 0x41, 0xa9, // 32: 0xa9414ff4 ldp x20, x19, [sp, #16]
- 0xf6, 0x57, 0xc3, 0xa8, // 36: 0xa8c357f6 ldp x22, x21, [sp], #48
- 0x01, 0x16, 0x09, 0x14, // 40: 0x14091601 b 0x18f640524 ; symbol stub
- // for: CFStringCreateWithBytes
- };
-
- // UnwindPlan we expect:
- // 0: CFA=sp +0 =>
- // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
- // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
- // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
-
- // [... function body ...]
-
- // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
- // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
- // <same> lr= <same>
- // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
- // <same> lr= <same>
- // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
- // lr= <same>
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 0: CFA=sp +0 =>
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // 4: CFA=sp+48 => x21=[CFA-40] x22=[CFA-48]
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-40, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-48, regloc.GetOffset());
-
- // 8: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(8ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-24, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-32, regloc.GetOffset());
-
- // 12: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 16: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // 28: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // fp=[CFA-16] lr=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(28);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(48, row_sp->GetCFAValue().GetOffset());
-
- // 32: CFA=sp+48 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48] fp=
- // <same> lr= <same>
- row_sp = unwind_plan.GetRowForFunctionOffset(32);
- EXPECT_EQ(32ull, row_sp->GetOffset());
-
- // I'd prefer if these restored registers were cleared entirely instead of set
- // to IsSame...
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-
- // 36: CFA=sp+48 => x19= <same> x20= <same> x21=[CFA-40] x22=[CFA-48] fp=
- // <same> lr= <same>
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_EQ(36ull, row_sp->GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-
- // 40: CFA=sp +0 => x19= <same> x20= <same> x21= <same> x22= <same> fp= <same>
- // lr= <same>
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(40ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
- EXPECT_TRUE(regloc.IsSame());
-}
-
-TEST_F(TestArm64InstEmulation, TestFramelessThreeEpilogueFunction) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // disassembly of JSC::ARM64LogicalImmediate::findBitRange<16u>
- // from JavaScriptcore for iOS.
- uint8_t data[] = {
- 0x08, 0x3c, 0x0f, 0x53, // 0: 0x530f3c08 ubfx w8, w0, #15, #1
- 0x68, 0x00, 0x00, 0x39, // 4: 0x39000068 strb w8, [x3]
- 0x08, 0x3c, 0x40, 0xd2, // 8: 0xd2403c08 eor x8, x0, #0xffff
- 0x1f, 0x00, 0x71, 0xf2, // 12: 0xf271001f tst x0, #0x8000
-
- // [...]
-
- 0x3f, 0x01, 0x0c, 0xeb, // 16: 0xeb0c013f cmp x9, x12
- 0x81, 0x00, 0x00, 0x54, // 20: 0x54000081 b.ne +34
- 0x5f, 0x00, 0x00, 0xb9, // 24: 0xb900005f str wzr, [x2]
- 0xe0, 0x03, 0x00, 0x32, // 28: 0x320003e0 orr w0, wzr, #0x1
- 0xc0, 0x03, 0x5f, 0xd6, // 32: 0xd65f03c0 ret
- 0x89, 0x01, 0x09, 0xca, // 36: 0xca090189 eor x9, x12, x9
-
- // [...]
-
- 0x08, 0x05, 0x00, 0x11, // 40: 0x11000508 add w8, w8, #0x1
- 0x48, 0x00, 0x00, 0xb9, // 44: 0xb9000048 str w8, [x2]
- 0xe0, 0x03, 0x00, 0x32, // 48: 0x320003e0 orr w0, wzr, #0x1
- 0xc0, 0x03, 0x5f, 0xd6, // 52: 0xd65f03c0 ret
- 0x00, 0x00, 0x80, 0x52, // 56: 0x52800000 mov w0, #0x0
- 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
-
- };
-
- // UnwindPlan we expect:
- // 0: CFA=sp +0 =>
- // (possibly with additional rows at offsets 36 and 56 saying the same thing)
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 0: CFA=sp +0 =>
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(32);
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x19_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x21_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x22_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x23_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x24_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x25_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x26_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x27_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_x28_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_fp_arm64, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(gpr_lr_arm64, regloc));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(52);
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(56);
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(60);
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestRegisterSavedTwice) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // disassembly of mach_msg_sever_once from libsystem_kernel.dylib for iOS.
- uint8_t data[] = {
-
- 0xfc, 0x6f, 0xba, 0xa9, // 0: 0xa9ba6ffc stp x28, x27, [sp, #-0x60]!
- 0xfa, 0x67, 0x01, 0xa9, // 4: 0xa90167fa stp x26, x25, [sp, #0x10]
- 0xf8, 0x5f, 0x02, 0xa9, // 8: 0xa9025ff8 stp x24, x23, [sp, #0x20]
- 0xf6, 0x57, 0x03, 0xa9, // 12: 0xa90357f6 stp x22, x21, [sp, #0x30]
- 0xf4, 0x4f, 0x04, 0xa9, // 16: 0xa9044ff4 stp x20, x19, [sp, #0x40]
- 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
- 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
- 0xff, 0xc3, 0x00, 0xd1, // 28: 0xd100c3ff sub sp, sp, #0x30
-
- // mid-function, store x20 & x24 on the stack at a different location.
- // this should not show up in the unwind plan; caller's values are not
- // being saved to stack.
- 0xf8, 0x53, 0x01, 0xa9, // 32: 0xa90153f8 stp x24, x20, [sp, #0x10]
-
- // mid-function, copy x20 and x19 off of the stack -- but not from
- // their original locations. unwind plan should ignore this.
- 0xf4, 0x4f, 0x41, 0xa9, // 36: 0xa9414ff4 ldp x20, x19, [sp, #0x10]
-
- // epilogue
- 0xbf, 0x43, 0x01, 0xd1, // 40: 0xd10143bf sub sp, x29, #0x50
- 0xfd, 0x7b, 0x45, 0xa9, // 44: 0xa9457bfd ldp x29, x30, [sp, #0x50]
- 0xf4, 0x4f, 0x44, 0xa9, // 48: 0xa9444ff4 ldp x20, x19, [sp, #0x40]
- 0xf6, 0x57, 0x43, 0xa9, // 52: 0xa94357f6 ldp x22, x21, [sp, #0x30]
- 0xf8, 0x5f, 0x42, 0xa9, // 56: 0xa9425ff8 ldp x24, x23, [sp, #0x20]
- 0xfa, 0x67, 0x41, 0xa9, // 60: 0xa94167fa ldp x26, x25, [sp, #0x10]
- 0xfc, 0x6f, 0xc6, 0xa8, // 64: 0xa8c66ffc ldp x28, x27, [sp], #0x60
- 0xc0, 0x03, 0x5f, 0xd6, // 68: 0xd65f03c0 ret
- };
-
- // UnwindPlan we expect:
- // 0: CFA=sp +0 =>
- // 4: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
- // 8: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
- // 12: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
- // x27=[CFA-88] x28=[CFA-96]
- // 16: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
- // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
- // 20: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
- // x28=[CFA-96]
- // 24: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
- // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
- // 28: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
- // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
-
- // 44: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
- // x28=[CFA-96] fp=[CFA-16] lr=[CFA-8]
- // 48: CFA=sp+96 => x19=[CFA-24] x20=[CFA-32] x21=[CFA-40] x22=[CFA-48]
- // x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88]
- // x28=[CFA-96]
- // 52: CFA=sp+96 => x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64]
- // x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
- // 56: CFA=sp+96 => x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80]
- // x27=[CFA-88] x28=[CFA-96]
- // 60: CFA=sp+96 => x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
- // 64: CFA=sp+96 => x27=[CFA-88] x28=[CFA-96]
- // 68: CFA=sp +0 =>
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-32, regloc.GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_x20_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-32, regloc.GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // this file built with clang for iOS arch arm64 optimization -Os
- // #include <stdio.h>
- // double foo(double in) {
- // double arr[32];
- // for (int i = 0; i < 32; i++)
- // arr[i] = in + i;
- // for (int i = 2; i < 30; i++)
- // arr[i] = ((((arr[i - 1] * arr[i - 2] * 0.2) + (0.7 * arr[i])) /
- // ((((arr[i] * 0.73) + 0.65) * (arr[i - 1] + 0.2)) - ((arr[i + 1] + (arr[i]
- // * 0.32) + 0.52) / 0.3) + (0.531 * arr[i - 2]))) + ((arr[i - 1] + 5) /
- // ((arr[i + 2] + 0.4) / arr[i])) + (arr[5] * (0.17 + arr[7] * arr[i])) +
- // ((i > 5 ? (arr[i - 3]) : arr[i - 1]) * 0.263) + (((arr[i - 2] + arr[i -
- // 1]) * 0.3252) + 3.56) - (arr[i + 1] * 0.852311)) * ((arr[i] * 85234.1345)
- // + (77342.451324 / (arr[i - 2] + arr[i - 1] - 73425341.33455))) + (arr[i]
- // * 875712013.55) - (arr[i - 1] * 0.5555) - ((arr[i] * (arr[i + 1] +
- // 17342834.44) / 8688200123.555)) + (arr[i - 2] + 8888.888);
- // return arr[16];
- //}
- // int main(int argc, char **argv) { printf("%g\n", foo(argc)); }
-
- // so function foo() uses enough registers that it spills the callee-saved
- // floating point registers.
- uint8_t data[] = {
- // prologue
- 0xef, 0x3b, 0xba, 0x6d, // 0: 0x6dba3bef stp d15, d14, [sp, #-0x60]!
- 0xed, 0x33, 0x01, 0x6d, // 4: 0x6d0133ed stp d13, d12, [sp, #0x10]
- 0xeb, 0x2b, 0x02, 0x6d, // 8: 0x6d022beb stp d11, d10, [sp, #0x20]
- 0xe9, 0x23, 0x03, 0x6d, // 12: 0x6d0323e9 stp d9, d8, [sp, #0x30]
- 0xfc, 0x6f, 0x04, 0xa9, // 16: 0xa9046ffc stp x28, x27, [sp, #0x40]
- 0xfd, 0x7b, 0x05, 0xa9, // 20: 0xa9057bfd stp x29, x30, [sp, #0x50]
- 0xfd, 0x43, 0x01, 0x91, // 24: 0x910143fd add x29, sp, #0x50
- 0xff, 0x43, 0x04, 0xd1, // 28: 0xd10443ff sub sp, sp, #0x110
-
- // epilogue
- 0xbf, 0x43, 0x01, 0xd1, // 32: 0xd10143bf sub sp, x29, #0x50
- 0xfd, 0x7b, 0x45, 0xa9, // 36: 0xa9457bfd ldp x29, x30, [sp, #0x50]
- 0xfc, 0x6f, 0x44, 0xa9, // 40: 0xa9446ffc ldp x28, x27, [sp, #0x40]
- 0xe9, 0x23, 0x43, 0x6d, // 44: 0x6d4323e9 ldp d9, d8, [sp, #0x30]
- 0xeb, 0x2b, 0x42, 0x6d, // 48: 0x6d422beb ldp d11, d10, [sp, #0x20]
- 0xed, 0x33, 0x41, 0x6d, // 52: 0x6d4133ed ldp d13, d12, [sp, #0x10]
- 0xef, 0x3b, 0xc6, 0x6c, // 56: 0x6cc63bef ldp d15, d14, [sp], #0x60
- 0xc0, 0x03, 0x5f, 0xd6, // 60: 0xd65f03c0 ret
- };
-
- // UnwindPlan we expect:
- // 0: CFA=sp +0 =>
- // 4: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
- // 8: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 12: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
- // d14=[CFA-88] d15=[CFA-96]
- // 16: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
- // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 20: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
- // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
- // d15=[CFA-96]
- // 24: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
- // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
- // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 36: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
- // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 40: CFA=sp+96 => x27=[CFA-24] x28=[CFA-32] d8=[CFA-40] d9=[CFA-48]
- // d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80] d14=[CFA-88]
- // d15=[CFA-96]
- // 44: CFA=sp+96 => d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64]
- // d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 48: CFA=sp+96 => d10=[CFA-56] d11=[CFA-64] d12=[CFA-72] d13=[CFA-80]
- // d14=[CFA-88] d15=[CFA-96]
- // 52: CFA=sp+96 => d12=[CFA-72] d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- // 56: CFA=sp+96 => d14=[CFA-88] d15=[CFA-96]
- // 60: CFA=sp +0 =>
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 28: CFA=fp+16 => x27=[CFA-24] x28=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // d8=[CFA-40] d9=[CFA-48] d10=[CFA-56] d11=[CFA-64] d12=[CFA-72]
- // d13=[CFA-80] d14=[CFA-88] d15=[CFA-96]
- row_sp = unwind_plan.GetRowForFunctionOffset(28);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d15_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-96, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d14_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-88, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d13_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-80, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d12_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-72, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d11_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-64, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d10_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-56, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d9_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-48, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(fpu_d8_arm64, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-40, regloc.GetOffset());
-
- // 60: CFA=sp +0 =>
- row_sp = unwind_plan.GetRowForFunctionOffset(60);
- EXPECT_EQ(60ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- if (row_sp->GetRegisterInfo(fpu_d8_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d9_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d10_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d11_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d12_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d13_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d14_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(fpu_d15_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(gpr_x27_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
- if (row_sp->GetRegisterInfo(gpr_x28_arm64, regloc)) {
- EXPECT_TRUE(regloc.IsSame());
- }
-}
-
-TEST_F(TestArm64InstEmulation, TestRetguardEmptyFunction) {
- ArchSpec arch("arm64-unknown-openbsd6.4");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // void main() { } compiled on arm64-unknown-openbsd6.4 with -fret-protector
- uint8_t data[] = {
- 0x2f, 0x37, 0x00, 0xf0, // 0: adrp x15, #7237632
- 0xef, 0x35, 0x43, 0xf9, // 4: ldr x15, [x15, #1640]
- 0xef, 0x01, 0x1e, 0xca, // 8: eor x15, x15, x30
- 0xef, 0x0f, 0x1f, 0xf8, // 12: str x15, [sp, #-16]!
- 0xef, 0x07, 0x41, 0xf8, // 16: ldr x15, [sp], #16
- 0x29, 0x37, 0x00, 0xf0, // 20: adrp x9, #7237632
- 0x29, 0x35, 0x43, 0xf9, // 24: ldr x9, [x9, #1640]
- 0xef, 0x01, 0x1e, 0xca, // 28: eor x15, x15, x30
- 0xef, 0x01, 0x09, 0xeb, // 32: subs x15, x15, x9
- 0x4f, 0x00, 0x00, 0xb4, // 36: cbz x15, #8
- 0x20, 0x00, 0x20, 0xd4, // 40: brk #0x1
- 0xc0, 0x03, 0x5f, 0xd6, // 44: ret
- };
-
- // UnwindPlan we expect
- // 0: CFA=sp+0
- // 16: CFA=sp+16
- // 20: CFA=sp+0
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 0: CFA=sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(0ull, row_sp->GetOffset());
-
- // 16: CFA=sp+16
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // 20: CFA=sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(20);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(24);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(28);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(32);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(20ull, row_sp->GetOffset());
-}
-
-TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) {
- ArchSpec arch("arm64-apple-ios10");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- uint8_t data[] = {
- // prologue
- 0xf4, 0x4f, 0xbe, 0xa9, // 0: 0xa9be4ff4 stp x20, x19, [sp, #-0x20]!
- 0xfd, 0x7b, 0x01, 0xa9, // 4: 0xa9017bfd stp x29, x30, [sp, #0x10]
- 0xfd, 0x43, 0x00, 0x91, // 8: 0x910043fd add x29, sp, #0x10
- 0xff, 0x43, 0x00, 0xd1, // 12: 0xd10043ff sub sp, sp, #0x10
- // conditional branch over a mid-function epilogue
- 0xeb, 0x00, 0x00, 0x54, // 16: 0x540000eb b.lt <+44>
- // mid-function epilogue
- 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop
- 0xe0, 0x03, 0x13, 0xaa, // 24: 0xaa1303e0 mov x0, x19
- 0xbf, 0x43, 0x00, 0xd1, // 28: 0xd10043bf sub sp, x29, #0x10
- 0xfd, 0x7b, 0x41, 0xa9, // 32: 0xa9417bfd ldp x29, x30, [sp, #0x10]
- 0xf4, 0x4f, 0xc2, 0xa8, // 36: 0xa8c24ff4 ldp x20, x19, [sp], #0x20
- 0xc0, 0x03, 0x5f, 0xd6, // 40: 0xd65f03c0 ret
- // unwind state restored, we're using a frame pointer, let's change the
- // stack pointer and see no change in how the CFA is computed
- 0x1f, 0x20, 0x03, 0xd5, // 44: 0xd503201f nop
- 0xff, 0x43, 0x00, 0xd1, // 48: 0xd10043ff sub sp, sp, #0x10
- 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop
- // final epilogue
- 0xe0, 0x03, 0x13, 0xaa, // 56: 0xaa1303e0 mov x0, x19
- 0xbf, 0x43, 0x00, 0xd1, // 60: 0xd10043bf sub sp, x29, #0x10
- 0xfd, 0x7b, 0x41, 0xa9, // 64: 0xa9417bfd ldp x29, x30, [sp, #0x10]
- 0xf4, 0x4f, 0xc2, 0xa8, // 68: 0xa8c24ff4 ldp x20, x19, [sp], #0x20
- 0xc0, 0x03, 0x5f, 0xd6, // 72: 0xd65f03c0 ret
-
- 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop
- };
-
- // UnwindPlan we expect:
- // row[0]: 0: CFA=sp +0 =>
- // row[1]: 4: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32]
- // row[2]: 8: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[3]: 12: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[4]: 32: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[5]: 36: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
- // row[6]: 40: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same>
- // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[8]: 64: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[9]: 68: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
- // row[10]: 72: CFA=sp +0 => x19= <same> x20= <same> fp= <same> lr= <same>
-
- // The specific bug we're looking for is this incorrect CFA definition,
- // where the InstEmulation is using the $sp value mixed in with $fp,
- // it looks like this:
- //
- // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[8]: 52: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8]
- // row[9]: 68: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp= <same> lr= <same>
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // Confirm CFA at mid-func epilogue 'ret' is $sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(40ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // After the 'ret', confirm we're back to the correct CFA of $fp+16
- row_sp = unwind_plan.GetRowForFunctionOffset(44);
- EXPECT_EQ(44ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // Confirm that we have no additional UnwindPlan rows before the
- // real epilogue -- we still get the Row at offset 44.
- row_sp = unwind_plan.GetRowForFunctionOffset(60);
- EXPECT_EQ(44ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // And in the epilogue, confirm that we start by switching back to
- // defining the CFA in terms of $sp.
- row_sp = unwind_plan.GetRowForFunctionOffset(64);
- EXPECT_EQ(64ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(32, row_sp->GetCFAValue().GetOffset());
-}
-
+++ /dev/null
-if ("AArch64" IN_LIST LLVM_TARGETS_TO_BUILD)
- add_subdirectory(ARM64)
-endif()
-
-if ("PowerPC" IN_LIST LLVM_TARGETS_TO_BUILD)
- add_subdirectory(PPC64)
-endif()
-
-if ("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
- add_subdirectory(x86)
-endif()
+++ /dev/null
-add_lldb_unittest(PPC64InstEmulationTests
- TestPPC64InstEmulation.cpp
- LINK_LIBS
- lldbCore
- lldbSymbol
- lldbTarget
- lldbPluginUnwindAssemblyInstEmulation
- lldbPluginDisassemblerLLVMC
- lldbPluginInstructionPPC64
- lldbPluginProcessUtility
- LINK_COMPONENTS
- Support
- ${LLVM_TARGETS_TO_BUILD})
+++ /dev/null
-//===-- TestPPC64InstEmulation.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include <vector>
-
-#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/AddressRange.h"
-#include "lldb/Symbol/UnwindPlan.h"
-#include "lldb/Target/UnwindAssembly.h"
-#include "lldb/Utility/ArchSpec.h"
-
-#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
-#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
-#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class TestPPC64InstEmulation : public testing::Test {
-public:
- static void SetUpTestCase();
- static void TearDownTestCase();
-
- // virtual void SetUp() override { }
- // virtual void TearDown() override { }
-
-protected:
-};
-
-void TestPPC64InstEmulation::SetUpTestCase() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
- DisassemblerLLVMC::Initialize();
- EmulateInstructionPPC64::Initialize();
-}
-
-void TestPPC64InstEmulation::TearDownTestCase() {
- DisassemblerLLVMC::Terminate();
- EmulateInstructionPPC64::Terminate();
-}
-
-TEST_F(TestPPC64InstEmulation, TestSimpleFunction) {
- ArchSpec arch("powerpc64le-linux-gnu");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // prologue and epilogue of:
- // int main() {
- // int i = test();
- // return i;
- // }
- //
- // compiled with clang -O0 -g
- uint8_t data[] = {
- // prologue
- 0x02, 0x10, 0x40, 0x3c, // 0: lis r2, 4098
- 0x00, 0x7f, 0x42, 0x38, // 4: addi r2, r2, 32512
- 0xa6, 0x02, 0x08, 0x7c, // 8: mflr r0
- 0xf8, 0xff, 0xe1, 0xfb, // 12: std r31, -8(r1)
- 0x10, 0x00, 0x01, 0xf8, // 16: std r0, 16(r1)
- 0x91, 0xff, 0x21, 0xf8, // 20: stdu r1, -112(r1)
- 0x78, 0x0b, 0x3f, 0x7c, // 24: mr r31, r1
- 0x00, 0x00, 0x60, 0x38, // 28: li r3, 0
- 0x64, 0x00, 0x7f, 0x90, // 32: stw r3, 100(r31)
-
- // epilogue
- 0x70, 0x00, 0x21, 0x38, // 36: addi r1, r1, 112
- 0x10, 0x00, 0x01, 0xe8, // 40: ld r0, 16(r1)
- 0xf8, 0xff, 0xe1, 0xeb, // 44: ld r31, -8(r1)
- 0xa6, 0x03, 0x08, 0x7c, // 48: mtlr r0
- 0x20, 0x00, 0x80, 0x4e // 52: blr
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 0: CFA=sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // 1: CFA=sp+0 => fp=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
- row_sp = unwind_plan.GetRowForFunctionOffset(20);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(16, regloc.GetOffset());
-
- // 3: CFA=sp+112 => fp=[CFA-8] lr=[CFA+16]
- row_sp = unwind_plan.GetRowForFunctionOffset(24);
- EXPECT_EQ(24ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(16, regloc.GetOffset());
-
- // 4: CFA=r31+112 => fp=[CFA-8] lr=[CFA+16]
- row_sp = unwind_plan.GetRowForFunctionOffset(28);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r31_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(112, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(16, regloc.GetOffset());
-
- // 5: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(40ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(16, regloc.GetOffset());
-}
-
-TEST_F(TestPPC64InstEmulation, TestMediumFunction) {
- ArchSpec arch("powerpc64le-linux-gnu");
- std::unique_ptr<UnwindAssemblyInstEmulation> engine(
- static_cast<UnwindAssemblyInstEmulation *>(
- UnwindAssemblyInstEmulation::CreateInstance(arch)));
- ASSERT_NE(nullptr, engine);
-
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- UnwindPlan::Row::RegisterLocation regloc;
-
- // prologue and epilogue of main() (call-func.c),
- // with several calls and stack variables.
- //
- // compiled with clang -O0 -g
- uint8_t data[] = {
- // prologue
- 0xa6, 0x02, 0x08, 0x7c, // 0: mflr r0
- 0xf8, 0xff, 0xe1, 0xfb, // 4: std r31, -8(r1)
- 0x10, 0x00, 0x01, 0xf8, // 8: std r0, 16(r1)
- 0x78, 0x0b, 0x3e, 0x7c, // 12: mr r30, r1
- 0xe0, 0x06, 0x20, 0x78, // 16: clrldi r0, r1, 59
- 0xa0, 0xfa, 0x00, 0x20, // 20: subfic r0, r0, -1376
- 0x6a, 0x01, 0x21, 0x7c, // 24: stdux r1, r1, r0
- 0x78, 0x0b, 0x3f, 0x7c, // 28: mr r31, r1
-
- // epilogue
- 0x00, 0x00, 0x21, 0xe8, // 32: ld r1, 0(r1)
- 0x20, 0x00, 0x80, 0x4e // 36: blr
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- sample_range, data, sizeof(data), unwind_plan));
-
- // 0: CFA=sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // 1: CFA=sp+0 => fp=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(8ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_r31_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 2: CFA=sp+0 => fp=[CFA-8] lr=[CFA+16]
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(gpr_lr_ppc64le, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(16, regloc.GetOffset());
-
- // 3: CFA=r30
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(32);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r30_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-
- // 4: CFA=sp+0
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_EQ(36ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_r1_ppc64le);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset());
-}
+++ /dev/null
-add_lldb_unittest(UnwindAssemblyx86Tests
- Testx86AssemblyInspectionEngine.cpp
- LINK_LIBS
- lldbCore
- lldbSymbol
- lldbPluginUnwindAssemblyX86
- LINK_COMPONENTS
- Support
- ${LLVM_TARGETS_TO_BUILD}
- )
+++ /dev/null
-//===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//
-
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include <memory>
-#include <vector>
-
-#include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
-#include "lldb/Core/Address.h"
-#include "lldb/Core/AddressRange.h"
-#include "lldb/Symbol/UnwindPlan.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/StreamString.h"
-
-#include "llvm/Support/TargetSelect.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-class Testx86AssemblyInspectionEngine : public testing::Test {
-public:
- static void SetUpTestCase();
-
- // static void TearDownTestCase() { }
-
- // virtual void SetUp() override { }
-
- // virtual void TearDown() override { }
-
-protected:
-};
-
-void Testx86AssemblyInspectionEngine::SetUpTestCase() {
- llvm::InitializeAllTargets();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
-}
-
-// only defining the register names / numbers that the unwinder is actually
-// using today
-
-// names should match the constants below. These will be the eRegisterKindLLDB
-// register numbers.
-
-const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
- "rsi", "rdi", "r8", "r9", "r10", "r11",
- "r12", "r13", "r14", "r15", "rip"};
-
-enum x86_64_regs {
- k_rax = 0,
- k_rbx = 1,
- k_rcx = 2,
- k_rdx = 3,
- k_rsp = 4,
- k_rbp = 5,
- k_rsi = 6,
- k_rdi = 7,
- k_r8 = 8,
- k_r9 = 9,
- k_r10 = 10,
- k_r11 = 11,
- k_r12 = 12,
- k_r13 = 13,
- k_r14 = 14,
- k_r15 = 15,
- k_rip = 16
-};
-
-// names should match the constants below. These will be the eRegisterKindLLDB
-// register numbers.
-
-const char *i386_reg_names[] = {"eax", "ecx", "edx", "ebx", "esp",
- "ebp", "esi", "edi", "eip"};
-
-enum i386_regs {
- k_eax = 0,
- k_ecx = 1,
- k_edx = 2,
- k_ebx = 3,
- k_esp = 4,
- k_ebp = 5,
- k_esi = 6,
- k_edi = 7,
- k_eip = 8
-};
-
-std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
-
- ArchSpec arch("x86_64-apple-macosx");
- std::unique_ptr<x86AssemblyInspectionEngine> engine(
- new x86AssemblyInspectionEngine(arch));
-
- std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
- int i = 0;
- for (const auto &name : x86_64_reg_names) {
- x86AssemblyInspectionEngine::lldb_reg_info ri;
- ri.name = name;
- ri.lldb_regnum = i++;
- lldb_regnums.push_back(ri);
- }
-
- engine->Initialize(lldb_regnums);
- return engine;
-}
-
-std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
-
- ArchSpec arch("i386-apple-macosx");
- std::unique_ptr<x86AssemblyInspectionEngine> engine(
- new x86AssemblyInspectionEngine(arch));
-
- std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
- int i = 0;
- for (const auto &name : i386_reg_names) {
- x86AssemblyInspectionEngine::lldb_reg_info ri;
- ri.name = name;
- ri.lldb_regnum = i++;
- lldb_regnums.push_back(ri);
- }
-
- engine->Initialize(lldb_regnums);
- return engine;
-}
-
-namespace lldb_private {
-static std::ostream &operator<<(std::ostream &OS,
- const UnwindPlan::Row::FAValue &CFA) {
- StreamString S;
- CFA.Dump(S, nullptr, nullptr);
- return OS << S.GetData();
-}
-} // namespace lldb_private
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // 'int main() { }' compiled for x86_64-apple-macosx with clang
- uint8_t data[] = {
- 0x55, // offset 0 -- pushq %rbp
- 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
- 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
- 0x5d, // offset 6 -- popq %rbp
- 0xc3 // offset 7 -- retq
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Expect four unwind rows:
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
-
- EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
- EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
- eLazyBoolYes);
- EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSimple32bitFrameFunction) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- // 'int main() { }' compiled for i386-apple-macosx with clang
- uint8_t data[] = {
- 0x55, // offset 0 -- pushl %ebp
- 0x89, 0xe5, // offset 1 -- movl %esp, %ebp
- 0x31, 0xc0, // offset 3 -- xorl %eax, %eax
- 0x5d, // offset 5 -- popl %ebp
- 0xc3 // offset 6 -- retl
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Expect four unwind rows:
- // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
-
- EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_esp);
- EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
- eLazyBoolYes);
- EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // offset 0 -- pushl %ebp
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_TRUE(regloc.GetOffset() == -4);
-
- // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-4, regloc.GetOffset());
-
- // 3: CFA=ebp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(3);
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-4, regloc.GetOffset());
-
- // 6: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(6);
- EXPECT_EQ(6ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-4, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessBigStackFrame) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // this source file:
- //
- // #include <stdio.h>
- // int main (int argc, char **argv)
- // {
- //
- // const int arrsize = 60;
- // int buf[arrsize * arrsize];
- // int accum = argc;
- // for (int i = 0; i < arrsize; i++)
- // for (int j = 0; j < arrsize; j++)
- // {
- // if (i > 0 && j > 0)
- // {
- // int n = buf[(i-1) * (j-1)] * 2;
- // int m = buf[(i-1) * (j-1)] / 2;
- // int j = buf[(i-1) * (j-1)] + 2;
- // int k = buf[(i-1) * (j-1)] - 2;
- // printf ("%d ", n + m + j + k);
- // buf[(i-1) * (j-1)] += n - m + j - k;
- // }
- // buf[i*j] = accum++;
- // }
- //
- // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
- // arrsize) - 3]);
- // }
- //
- // compiled 'clang -fomit-frame-pointer -Os' for x86_64-apple-macosx
-
- uint8_t data[] = {
- 0x55, // offset 0 -- pushq %rbp
- 0x41, 0x57, // offset 1 -- pushq %r15
- 0x41, 0x56, // offset 3 -- pushq %r14
- 0x41, 0x55, // offset 5 -- pushq %r13
- 0x41, 0x54, // offset 7 -- pushq %r12
- 0x53, // offset 9 -- pushq %rbx
- 0x48, 0x81, 0xec, 0x68, 0x38, 0x00,
- 0x00, // offset 10 -- subq $0x3868, %rsp
-
- // ....
-
- 0x48, 0x81, 0xc4, 0x68, 0x38, 0x00,
- 0x00, // offset 17 -- addq $0x3868, %rsp
- 0x5b, // offset 24 -- popq %rbx
- 0x41, 0x5c, // offset 25 -- popq %r12
- 0x41, 0x5d, // offset 27 -- popq %r13
- 0x41, 0x5e, // offset 29 -- popq %r14
- 0x41, 0x5f, // offset 31 -- popq %r15
- 0x5d, // offset 33 -- popq %rbp
- 0xc3, // offset 34 -- retq
- 0xe8, 0x12, 0x34, 0x56, 0x78 // offset 35 -- callq whatever
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Unwind rules should look like
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 3: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
- // 5: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
- // rip=[CFA-8
- // 7: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
- // r15=[CFA-24] rip=[CFA-8]
- // 9: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
- // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
- // 10: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
- // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
- // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
- // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
-
- // 24: CFA=rsp+56 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
- // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
- // 25: CFA=rsp+48 => rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48] r13=[CFA-40]
- // r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
- // 27: CFA=rsp+40 => rbp=[CFA-16] rsp=CFA+0 r13=[CFA-40] r14=[CFA-32]
- // r15=[CFA-24] rip=[CFA-8]
- // 29: CFA=rsp+32 => rbp=[CFA-16] rsp=CFA+0 r14=[CFA-32] r15=[CFA-24]
- // rip=[CFA-8]
- // 31: CFA=rsp+24 => rbp=[CFA-16] rsp=CFA+0 r15=[CFA-24] rip=[CFA-8]
- // 33: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // grab the Row for when the prologue has finished executing:
- // 17: CFA=rsp+14496 => rbx=[CFA-56] rbp=[CFA-16] rsp=CFA+0 r12=[CFA-48]
- // r13=[CFA-40] r14=[CFA-32] r15=[CFA-24] rip=[CFA-8]
-
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(17);
-
- EXPECT_EQ(17ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(14496, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-24, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-32, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-40, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-48, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-56, regloc.GetOffset());
-
- // grab the Row for when the epilogue has finished executing:
- // 34: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
-
- row_sp = unwind_plan.GetRowForFunctionOffset(34);
-
- EXPECT_EQ(34ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // these could be set to IsSame and be valid -- meaning that the
- // register value is the same as the caller's -- but I'd rather
- // they not be mentioned at all.
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessBigStackFrame) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- // this source file:
- //
- // #include <stdio.h>
- // int main (int argc, char **argv)
- // {
- //
- // const int arrsize = 60;
- // int buf[arrsize * arrsize];
- // int accum = argc;
- // for (int i = 0; i < arrsize; i++)
- // for (int j = 0; j < arrsize; j++)
- // {
- // if (i > 0 && j > 0)
- // {
- // int n = buf[(i-1) * (j-1)] * 2;
- // int m = buf[(i-1) * (j-1)] / 2;
- // int j = buf[(i-1) * (j-1)] + 2;
- // int k = buf[(i-1) * (j-1)] - 2;
- // printf ("%d ", n + m + j + k);
- // buf[(i-1) * (j-1)] += n - m + j - k;
- // }
- // buf[i*j] = accum++;
- // }
- //
- // return buf[(arrsize * arrsize) - 2] + printf ("%d\n", buf[(arrsize *
- // arrsize) - 3]);
- // }
- //
- // compiled 'clang -arch i386 -fomit-frame-pointer -Os' for i386-apple-macosx
-
- // simplified assembly version of the above function, which is used as the
- // input
- // data:
- //
- // .section __TEXT,__text,regular,pure_instructions
- // .macosx_version_min 10, 12
- // .globl _main
- // .align 4, 0x90
- // _main: ## @main
- // ## BB#0:
- // pushl %ebp
- // pushl %ebx
- // pushl %edi
- // pushl %esi
- // L0$pb:
- // subl $0x386c, %esp
- // calll L1
- // L1:
- // popl %ecx
- // movl %ecx, 0x8(%esp)
- // subl $0x8, %esp
- // pushl %eax
- // pushl 0x20(%esp)
- // calll _puts
- // addl $0x10, %esp
- // incl %ebx
- // addl $0x386c, %esp
- // popl %esi
- // popl %edi
- // popl %ebx
- // popl %ebp
- // retl
- //
- // .section __TEXT,__cstring,cstring_literals
- // L_.str: ## @.str
- // .asciz "HI"
- //
- //
- // .subsections_via_symbols
-
- uint8_t data[] = {
- 0x55,
- // offset 0 -- pushl %ebp
-
- 0x53,
- // offset 1 -- pushl %ebx
-
- 0x57,
- // offset 2 -- pushl %edi
-
- 0x56,
- // offset 3 -- pushl %esi
-
- 0x81, 0xec, 0x6c, 0x38, 0x00, 0x00,
- // offset 4 -- subl $0x386c, %esp
-
- 0xe8, 0x00, 0x00, 0x00, 0x00,
- // offset 10 -- calll 0
- // call the next instruction, to put the pc on the stack
-
- 0x59,
- // offset 15 -- popl %ecx
- // pop the saved pc address into ecx
-
- 0x89, 0x4c, 0x24, 0x08,
- // offset 16 -- movl %ecx, 0x8(%esp)
-
- // ....
-
- 0x83, 0xec, 0x08,
- // offset 20 -- subl $0x8, %esp
-
- 0x50,
- // offset 23 -- pushl %eax
-
- 0xff, 0x74, 0x24, 0x20,
- // offset 24 -- pushl 0x20(%esp)
-
- 0xe8, 0x8c, 0x00, 0x00, 0x00,
- // offset 28 -- calll puts
-
- 0x83, 0xc4, 0x10,
- // offset 33 -- addl $0x10, %esp
- // get esp back to the value it was before the
- // alignment & argument saves for the puts call
-
- 0x43,
- // offset 36 -- incl %ebx
-
- // ....
-
- 0x81, 0xc4, 0x6c, 0x38, 0x00, 0x00,
- // offset 37 -- addl $0x386c, %esp
-
- 0x5e,
- // offset 43 -- popl %esi
-
- 0x5f,
- // offset 44 -- popl %edi
-
- 0x5b,
- // offset 45 -- popl %ebx
-
- 0x5d,
- // offset 46 -- popl %ebp
-
- 0xc3,
- // offset 47 -- retl
-
- 0xe8, 0x12, 0x34, 0x56, 0x78,
- // offset 48 -- calll __stack_chk_fail
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Unwind rules should look like
- //
- // 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- // 1: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 2: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 3: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
- // eip=[CFA-4]
- // 4: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 10: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- //
- // ....
- //
- // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- //
- // .....
- //
- // 37: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 43: CFA=esp+20 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- // 44: CFA=esp+16 => ebx=[CFA-12] edi=[CFA-16] ebp=[CFA-8] esp=CFA+0
- // eip=[CFA-4]
- // 45: CFA=esp+12 => ebx=[CFA-12] ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 46: CFA=esp +8 => ebp=[CFA-8] esp=CFA+0 eip=[CFA-4]
- // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- // 48: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
-
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- // Check that we get the CFA correct for the pic base setup sequence
-
- // CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(10);
- EXPECT_EQ(10ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
-
- // 15: CFA=esp+14468 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(15);
- EXPECT_EQ(15ull, row_sp->GetOffset());
- EXPECT_EQ(14468, row_sp->GetCFAValue().GetOffset());
-
- // 16: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
-
- // Check that the row for offset 16 has the registers saved that we expect
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-4, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-12, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-20, regloc.GetOffset());
-
- //
- // Check the pushing & popping around the call printf instruction
-
- // 23: CFA=esp+14472 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(23);
- EXPECT_EQ(23ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(14472, row_sp->GetCFAValue().GetOffset());
-
- // 24: CFA=esp+14476 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(24);
- EXPECT_EQ(24ull, row_sp->GetOffset());
- EXPECT_EQ(14476, row_sp->GetCFAValue().GetOffset());
-
- // 28: CFA=esp+14480 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(28);
- EXPECT_EQ(28ull, row_sp->GetOffset());
- EXPECT_EQ(14480, row_sp->GetCFAValue().GetOffset());
-
- // 36: CFA=esp+14464 => ebx=[CFA-12] edi=[CFA-16] esi=[CFA-20] ebp=[CFA-8]
- // esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(36);
- EXPECT_EQ(36ull, row_sp->GetOffset());
- EXPECT_EQ(14464, row_sp->GetCFAValue().GetOffset());
-
- // Check that the epilogue gets us back to the original unwind state
-
- // 47: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(47);
- EXPECT_EQ(47ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_eip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-4, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_esp, regloc));
- EXPECT_TRUE(regloc.IsCFAPlusOffset());
- EXPECT_EQ(0, regloc.GetOffset());
-
- // Check that no unexpected registers were saved
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, Test64bitFramelessSmallStackFrame) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // this source file:
- // #include <stdio.h>
- // int main () {
- // puts ("HI");
- // }
- //
- // compiled 'clang -fomit-frame-pointer' for x86_64-apple-macosx
-
- uint8_t data[] = {
- 0x50,
- // offset 0 -- pushq %rax
-
- 0x48, 0x8d, 0x3d, 0x32, 0x00, 0x00, 0x00,
- // offset 1 -- leaq 0x32(%rip), %rdi ; "HI"
-
- 0xe8, 0x0b, 0x00, 0x00, 0x00,
- // offset 8 -- callq 0x100000f58 ; puts
-
- 0x31, 0xc9,
- // offset 13 -- xorl %ecx, %ecx
-
- 0x89, 0x44, 0x24, 0x04,
- // offset 15 -- movl %eax, 0x4(%rsp)
-
- 0x89, 0xc8,
- // offset 19 -- movl %ecx, %eax
-
- 0x59,
- // offset 21 -- popq %rcx
-
- 0xc3
- // offset 22 -- retq
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Unwind rules should look like
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
- // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // grab the Row for when the prologue has finished executing:
- // 1: CFA=rsp+16 => rsp=CFA+0 rip=[CFA-8]
-
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(13);
-
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // none of these were spilled
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rax, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rcx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rsi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rdi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r8, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r9, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r10, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r11, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
-
- // grab the Row for when the epilogue has finished executing:
- // 22: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
-
- row_sp = unwind_plan.GetRowForFunctionOffset(22);
-
- EXPECT_EQ(22ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, Test32bitFramelessSmallStackFrame) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- // this source file:
- // #include <stdio.h>
- // int main () {
- // puts ("HI");
- // }
- //
- // compiled 'clang -arch i386 -fomit-frame-pointer' for i386-apple-macosx
-
- uint8_t data[] = {
- 0x83, 0xec, 0x0c,
- // offset 0 -- subl $0xc, %esp
-
- 0xe8, 0x00, 0x00, 0x00, 0x00,
- // offset 3 -- calll 0 {call the next instruction, to put the pc on
- // the stack}
-
- 0x58,
- // offset 8 -- popl %eax {pop the saved pc value off stack, into eax}
-
- 0x8d, 0x80, 0x3a, 0x00, 0x00, 0x00,
- // offset 9 -- leal 0x3a(%eax),%eax
-
- 0x89, 0x04, 0x24,
- // offset 15 -- movl %eax, (%esp)
-
- 0xe8, 0x0d, 0x00, 0x00, 0x00,
- // offset 18 -- calll 0x1f94 (puts)
-
- 0x31, 0xc9,
- // offset 23 -- xorl %ecx, %ecx
-
- 0x89, 0x44, 0x24, 0x08,
- // offset 25 -- movl %eax, 0x8(%esp)
-
- 0x89, 0xc8,
- // offset 29 -- movl %ecx, %eax
-
- 0x83, 0xc4, 0x0c,
- // offset 31 -- addl $0xc, %esp
-
- 0xc3
- // offset 34 -- retl
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Unwind rules should look like
- // row[0]: 0: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- // row[1]: 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
- // row[2]: 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
- // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
- // row[4]: 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // Check unwind state before we set up the picbase register
- // 3: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
-
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(3);
-
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // Check unwind state after we call the next instruction
- // 8: CFA=esp+20 => esp=CFA+0 eip=[CFA-4]
-
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(8ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
-
- // Check unwind state after we pop the pic base value off the stack
- // row[3]: 9: CFA=esp+16 => esp=CFA+0 eip=[CFA-4]
-
- row_sp = unwind_plan.GetRowForFunctionOffset(9);
- EXPECT_EQ(9ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- // Check that no unexpected registers were saved
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-
- // verify that we get back to the original unwind state before the ret
- // 34: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
-
- row_sp = unwind_plan.GetRowForFunctionOffset(34);
- EXPECT_EQ(34ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushRBP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
-
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
-
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushImm) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x68, 0xff, 0xff, 0x01, 0x69, // pushq $0x6901ffff
- 0x6a, 0x7d, // pushl $0x7d
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(5);
- EXPECT_EQ(5ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(5);
- EXPECT_EQ(5ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
-}
-
-// We treat 'pushq $0' / 'pushl $0' specially - this shows up
-// in the first function called in a new thread and it needs to
-// put a 0 as the saved pc. We pretend it didn't change the CFA.
-TEST_F(Testx86AssemblyInspectionEngine, TestPush0) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x6a, 0x00, // pushq $0
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- // We're verifying that no row was created for the 'pushq $0'
- EXPECT_EQ(0ull, row_sp->GetOffset());
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- // We're verifying that no row was created for the 'pushq $0'
- EXPECT_EQ(0ull, row_sp->GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushExtended) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0xff, 0x74, 0x24, 0x20, // pushl 0x20(%esp)
- 0xff, 0xb6, 0xce, 0x01, 0xf0, 0x00, // pushl 0xf001ce(%esi)
- 0xff, 0x30, // pushl (%eax)
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
-
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(10);
- EXPECT_EQ(10ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(12, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushR15) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x41, 0x57, // pushq %r15
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushR14) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x41, 0x56, // pushq %r14
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushR13) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x41, 0x55, // pushq %r13
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r13, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushR12) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x41, 0x54, // pushq %r13
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r12, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushRBX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x53, // pushq %rbx
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
-
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-// The ABI is hardcoded in x86AssemblyInspectionEngine such that
-// eax, ecx, edx are all considered volatile and push/pops of them are
-// not tracked (except to keep track of stack pointer movement)
-TEST_F(Testx86AssemblyInspectionEngine, TestPushEAX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x50, // pushl %eax
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_eax, regloc));
-}
-
-// The ABI is hardcoded in x86AssemblyInspectionEngine such that
-// eax, ecx, edx are all considered volatile and push/pops of them are
-// not tracked (except to keep track of stack pointer movement)
-TEST_F(Testx86AssemblyInspectionEngine, TestPushECX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x51, // pushl %ecx
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ecx, regloc));
-}
-
-// The ABI is hardcoded in x86AssemblyInspectionEngine such that
-// eax, ecx, edx are all considered volatile and push/pops of them are
-// not tracked (except to keep track of stack pointer movement)
-TEST_F(Testx86AssemblyInspectionEngine, TestPushEDX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x52, // pushl %edx
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edx, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushEBX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x53, // pushl %ebx
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushEBP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // pushl %ebp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushRBPWithREX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data[] = {
- 0x40, 0x55, // pushq %rbp
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
-
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushESI) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x56, // pushl %esi
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPushEDI) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x57, // pushl %edi
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_edi, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestMovRSPtoRBP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
-
- uint8_t data64_1[] = {
- 0x48, 0x8b, 0xec, // movq %rsp, %rbp
- 0x90 // nop
- };
-
- AddressRange sample_range(0x1000, sizeof(data64_1));
- UnwindPlan unwind_plan(eRegisterKindLLDB);
-
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data64_1, sizeof(data64_1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(3);
-
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data64_2[] = {
- 0x48, 0x89, 0xe5, // movq %rsp, %rbp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data64_2));
- unwind_plan.Clear();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data64_2, sizeof(data64_2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(3);
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data32_1[] = {
- 0x8b, 0xec, // movl %rsp, %rbp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data32_1));
- unwind_plan.Clear();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data32_1, sizeof(data32_1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data32_2[] = {
- 0x89, 0xe5, // movl %rsp, %rbp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data32_2));
- unwind_plan.Clear();
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data32_2, sizeof(data32_2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSubRSP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data1[] = {
- 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $0x100, $rsp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data1));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data1, sizeof(data1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(264, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data2[] = {
- 0x48, 0x83, 0xec, 0x10, // subq $0x10, %rsp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data2));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data2, sizeof(data2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(24, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSubESP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data1[] = {
- 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subl $0x100, %esp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data1));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data1, sizeof(data1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(6);
- EXPECT_EQ(6ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(260, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data2[] = {
- 0x83, 0xec, 0x10, // subq $0x10, %esp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data2));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data2, sizeof(data2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(3);
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestAddRSP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data1[] = {
- 0x48, 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addq $0x100, %rsp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data1));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data1, sizeof(data1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8 - 256, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data2[] = {
- 0x48, 0x83, 0xc4, 0x10, // addq $0x10, %rsp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data2));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data2, sizeof(data2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8 - 16, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestAddESP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data1[] = {
- 0x81, 0xc4, 0x00, 0x01, 0x00, 0x00, // addl $0x100, %esp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data1));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data1, sizeof(data1), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(6);
- EXPECT_EQ(6ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4 - 256, row_sp->GetCFAValue().GetOffset());
-
- uint8_t data2[] = {
- 0x83, 0xc4, 0x10, // addq $0x10, %esp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data2));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data2, sizeof(data2), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(3);
- EXPECT_EQ(3ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4 - 16, row_sp->GetCFAValue().GetOffset());
-}
-
-// FIXME add test for lea_rsp_pattern_p
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopRBX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x53, // pushq %rbx
- 0x5b, // popq %rbx
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbx, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopRBP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x5d, // popq %rbp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopR12) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x41, 0x54, // pushq %r12
- 0x41, 0x5c, // popq %r12
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r12, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopR13) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x41, 0x55, // pushq %r13
- 0x41, 0x5d, // popq %r13
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r13, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopR14) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x41, 0x56, // pushq %r14
- 0x41, 0x5e, // popq %r14
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r14, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopR15) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x41, 0x57, // pushq %r15
- 0x41, 0x5f, // popq %r15
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_r15, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopEBX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x53, // pushl %ebx
- 0x5b, // popl %ebx
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebx, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopEBP) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // pushl %ebp
- 0x5d, // popl %ebp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopRBPWithREX) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x40, 0x55, // pushq %rbp
- 0x40, 0x5d, // popq %rbp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopESI) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x56, // pushl %esi
- 0x5e, // popl %esi
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_esi, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestPopEDI) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x57, // pushl %edi
- 0x5f, // popl %edi
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_edi, regloc));
-}
-
-// We don't track these registers, but make sure the CFA address is updated
-// if we're defining the CFA in term of esp.
-TEST_F(Testx86AssemblyInspectionEngine, Testi386IgnoredRegisters) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x0e, // push cs
- 0x16, // push ss
- 0x1e, // push ds
- 0x06, // push es
-
- 0x07, // pop es
- 0x1f, // pop ds
- 0x17, // pop ss
-
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(20, row_sp->GetCFAValue().GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestLEAVE) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // push %rbp/ebp
- 0xc9, // leave
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-}
-
-// In i386, which lacks pc-relative addressing, a common code sequence
-// is to call the next instruction (i.e. call imm32, value of 0) which
-// pushes the addr of the next insn on the stack, and then pop that value
-// into a register (the "pic base" register).
-TEST_F(Testx86AssemblyInspectionEngine, TestCALLNextInsn) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0xe8, 0x00, 0x00, 0x00, 0x00, // call 0
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(5);
- EXPECT_EQ(5ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVx86_64) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x48, 0x89, 0xe5, // movq %rsp, %rbp
- 0x4c, 0x89, 0x75, 0xc0, // movq %r14, -0x40(%rbp)
- 0x4c, 0x89, 0xbd, 0x28, 0xfa, 0xff, 0xff, // movq %r15, -0x5d8(%rbp)
- 0x48, 0x89, 0x5d, 0xb8, // movq %rbx, -0x48(%rbp)
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(19);
- EXPECT_EQ(19ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r14, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-80, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_r15, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-1512, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-88, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSpillRegToStackViaMOVi386) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // pushl %ebp
- 0x89, 0xe5, // movl %esp, %ebp
- 0x89, 0x9d, 0xb0, 0xfe, 0xff, 0xff, // movl %ebx, -0x150(%ebp)
- 0x89, 0x75, 0xe0, // movl %esi, -0x20(%ebp)
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebx, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-344, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_esi, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-40, regloc.GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSpArithx86_64Augmented) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x48, 0x89, 0xe5, // movq %rsp, %rbp
-
- // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
- // has a bug where it can't augment a function that is just
- // prologue+epilogue - it needs at least one other instruction
- // in between.
-
- 0x90, // nop
- 0x48, 0x81, 0xec, 0x88, 0, 0, 0, // subq $0x88, %rsp
- 0x90, // nop
- 0x48, 0x81, 0xc4, 0x88, 0, 0, 0, // addq $0x88, %rsp
-
- 0x5d, // popq %rbp
- 0xc3 // retq
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- unwind_plan.SetSourceName("unit testing hand-created unwind plan");
- unwind_plan.SetPlanValidAddressRange(sample_range);
- unwind_plan.SetRegisterKind(eRegisterKindLLDB);
-
- row_sp = std::make_shared<UnwindPlan::Row>();
-
- // Describe offset 0
- row_sp->SetOffset(0);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
-
- regloc.SetAtCFAPlusOffset(-8);
- row_sp->SetRegisterInfo(k_rip, regloc);
-
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- UnwindPlan::Row *new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 1
- row_sp->SetOffset(1);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
- regloc.SetAtCFAPlusOffset(-16);
- row_sp->SetRegisterInfo(k_rbp, regloc);
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 4
- row_sp->SetOffset(4);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
- unwind_plan.AppendRow(row_sp);
-
- RegisterContextSP reg_ctx_sp;
- EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
- data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
-
- // Before we touch the stack pointer, we should still refer to the
- // row from after the prologue.
- row_sp = unwind_plan.GetRowForFunctionOffset(5);
- EXPECT_EQ(4ull, row_sp->GetOffset());
-
- // Check the first stack pointer update.
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_EQ(152, row_sp->GetCFAValue().GetOffset());
-
- // After the nop, we should still refer to the same row.
- row_sp = unwind_plan.GetRowForFunctionOffset(13);
- EXPECT_EQ(12ull, row_sp->GetOffset());
-
- // Check that the second stack pointer update is reflected in the
- // unwind plan.
- row_sp = unwind_plan.GetRowForFunctionOffset(20);
- EXPECT_EQ(20ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSimplex86_64Augmented) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x48, 0x89, 0xe5, // movq %rsp, %rbp
-
- // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
- // has a bug where it can't augment a function that is just
- // prologue+epilogue - it needs at least one other instruction
- // in between.
- 0x90, // nop
-
- 0x5d, // popq %rbp
- 0xc3 // retq
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- unwind_plan.SetSourceName("unit testing hand-created unwind plan");
- unwind_plan.SetPlanValidAddressRange(sample_range);
- unwind_plan.SetRegisterKind(eRegisterKindLLDB);
-
- row_sp = std::make_shared<UnwindPlan::Row>();
-
- // Describe offset 0
- row_sp->SetOffset(0);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 8);
-
- regloc.SetAtCFAPlusOffset(-8);
- row_sp->SetRegisterInfo(k_rip, regloc);
-
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- UnwindPlan::Row *new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 1
- row_sp->SetOffset(1);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rsp, 16);
- regloc.SetAtCFAPlusOffset(-16);
- row_sp->SetRegisterInfo(k_rbp, regloc);
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 4
- row_sp->SetOffset(4);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_rbp, 16);
- unwind_plan.AppendRow(row_sp);
-
- RegisterContextSP reg_ctx_sp;
- EXPECT_TRUE(engine64->AugmentUnwindPlanFromCallSite(
- data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(6);
- EXPECT_EQ(6ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
- // doesn't track register restores (pop'ing a reg value back from
- // the stack) - it was just written to make stepping work correctly.
- // Technically we should be able to do the following test, but it
- // won't work today - the unwind plan will still say that the caller's
- // rbp is on the stack.
- // EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSimplei386ugmented) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // pushl %ebp
- 0x89, 0xe5, // movl %esp, %ebp
-
- // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
- // has a bug where it can't augment a function that is just
- // prologue+epilogue - it needs at least one other instruction
- // in between.
- 0x90, // nop
-
- 0x5d, // popl %ebp
- 0xc3 // retl
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- unwind_plan.SetSourceName("unit testing hand-created unwind plan");
- unwind_plan.SetPlanValidAddressRange(sample_range);
- unwind_plan.SetRegisterKind(eRegisterKindLLDB);
-
- row_sp = std::make_shared<UnwindPlan::Row>();
-
- // Describe offset 0
- row_sp->SetOffset(0);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 4);
-
- regloc.SetAtCFAPlusOffset(-4);
- row_sp->SetRegisterInfo(k_eip, regloc);
-
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- UnwindPlan::Row *new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 1
- row_sp->SetOffset(1);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_esp, 8);
- regloc.SetAtCFAPlusOffset(-8);
- row_sp->SetRegisterInfo(k_ebp, regloc);
- unwind_plan.AppendRow(row_sp);
-
- // Allocate a new Row, populate it with the existing Row contents.
- new_row = new UnwindPlan::Row;
- *new_row = *row_sp.get();
- row_sp.reset(new_row);
-
- // Describe offset 3
- row_sp->SetOffset(3);
- row_sp->GetCFAValue().SetIsRegisterPlusOffset(k_ebp, 8);
- unwind_plan.AppendRow(row_sp);
-
- RegisterContextSP reg_ctx_sp;
- EXPECT_TRUE(engine32->AugmentUnwindPlanFromCallSite(
- data, sizeof(data), sample_range, unwind_plan, reg_ctx_sp));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(5);
- EXPECT_EQ(5ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_EQ(4, row_sp->GetCFAValue().GetOffset());
-
- // x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite
- // doesn't track register restores (pop'ing a reg value back from
- // the stack) - it was just written to make stepping work correctly.
- // Technically we should be able to do the following test, but it
- // won't work today - the unwind plan will still say that the caller's
- // ebp is on the stack.
- // EXPECT_FALSE(row_sp->GetRegisterInfo(k_ebp, regloc));
-}
-
-// Check that the i386 disassembler disassembles past an opcode that
-// is only valid in 32-bit mode (non-long mode), and the x86_64 disassembler
-// stops
-// disassembling at that point (long-mode).
-TEST_F(Testx86AssemblyInspectionEngine, Test32BitOnlyInstruction) {
- UnwindPlan::Row::RegisterLocation regloc;
- UnwindPlan::RowSP row_sp;
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x43, // incl $ebx --- an invalid opcode in 64-bit mode
- 0x55, // pushl %ebp
- 0x90 // nop
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(2ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_ebp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- unwind_plan.Clear();
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- row_sp = unwind_plan.GetRowForFunctionOffset(2);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_FALSE(row_sp->GetRegisterInfo(k_rbp, regloc));
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x55, // pushl %ebp
- 0x89, 0xe5, // movl %esp, %ebp
- 0x53, // pushl %ebx
- 0x83, 0xe4, 0xf0, // andl $-16, %esp
- 0x83, 0xec, 0x10, // subl $16, %esp
- 0x8d, 0x65, 0xfc, // leal -4(%ebp), %esp
- 0x5b, // popl %ebx
- 0x5d, // popl %ebp
- 0xc3, // retl
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan plan(eRegisterKindLLDB);
- ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
- sample_range, plan));
-
- UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
- esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
- esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
- ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
-
- EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
- EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
- for (size_t i = 3; i < sizeof(data) - 2; ++i)
- EXPECT_EQ(ebp_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
- << "i: " << i;
- EXPECT_EQ(esp_plus_4,
- plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // pushq %rbp
- 0x48, 0x89, 0xe5, // movq %rsp, %rbp
- 0x53, // pushl %rbx
- 0x48, 0x83, 0xe4, 0xf0, // andq $-16, %rsp
- 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, // subq $256, %rsp
- 0x48, 0x8d, 0x65, 0xf8, // leaq -8(%rbp), %rsp
- 0x5b, // popq %rbx
- 0x5d, // popq %rbp
- 0xc3, // retq
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan plan(eRegisterKindLLDB);
- ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
- sample_range, plan));
-
- UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
- rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
- rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
- rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
-
- EXPECT_EQ(rsp_plus_8, plan.GetRowForFunctionOffset(0)->GetCFAValue());
- EXPECT_EQ(rsp_plus_16, plan.GetRowForFunctionOffset(1)->GetCFAValue());
- for (size_t i = 4; i < sizeof(data) - 2; ++i)
- EXPECT_EQ(rbp_plus_16, plan.GetRowForFunctionOffset(i)->GetCFAValue())
- << "i: " << i;
- EXPECT_EQ(rsp_plus_8,
- plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
-
- uint8_t data[] = {
- 0x53, // offset 00 -- pushl %ebx
- 0x8b, 0xdc, // offset 01 -- movl %esp, %ebx
- 0x83, 0xec, 0x08, // offset 03 -- subl $8, %esp
- 0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
- 0x83, 0xc4, 0x04, // offset 12 -- addl $4, %esp
- 0x55, // offset 15 -- pushl %ebp
- 0x8b, 0xec, // offset 16 -- movl %esp, %ebp
- 0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
- 0x89, 0x7d, 0xfc, // offset 24 -- movl %edi, -4(%ebp)
- 0x8b, 0xe5, // offset 27 -- movl %ebp, %esp
- 0x5d, // offset 29 -- popl %ebp
- 0x8b, 0xe3, // offset 30 -- movl %ebx, %esp
- 0x5b, // offset 32 -- popl %ebx
- 0xc3 // offset 33 -- retl
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
- UnwindPlan plan(eRegisterKindLLDB);
- ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
- sample_range, plan));
-
- UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
- ebx_plus_8, ebp_plus_0;
- esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4);
- esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0);
- esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
- esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
- ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8);
- ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0);
-
- // Test CFA
- EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
- EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
- for (size_t i = 3; i < 33; ++i)
- EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
- << "i: " << i;
- EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
-
- // Test AFA
- EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
- EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
- EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
- for (size_t i = 18; i < 30; ++i)
- EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
- << "i: " << i;
- EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
-
- // Test saved register
- UnwindPlan::Row::RegisterLocation reg_loc;
- EXPECT_TRUE(
- plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
- EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
- EXPECT_EQ(-4, reg_loc.GetOffset());
-}
-
-// Give the disassembler random bytes to test that it doesn't exceed
-// the bounds of the array when run under clang's address sanitizer.
-TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- unwind_plan.Clear();
-
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestRetguard64bitFrameFunction) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // 'int main() { }' compiled for amd64-unknown-openbsd6.4 with -fret-protector
- uint8_t data[] = {
- 0x4c, 0x8b, 0x1d, 0xf1, 0x0c, 0x00, 0x00, // offset 0 -- movq 3313(%rip), %r11
- 0x4c, 0x33, 0x1c, 0x24, // offset 7 -- xorq (%rsp), %r11
- 0x55, // offset 11 -- pushq %rbp
- 0x48, 0x89, 0xe5, // offset 12 -- movq %rsp, %rbp
- 0x41, 0x53, // offset 15 -- pushq %r11
- 0x31, 0xc0, // offset 17 -- xorl %eax, %eax
- 0x41, 0x5b, // offset 19 -- popq %r11
- 0x5d, // offset 21 -- popq %rbp
- 0x4c, 0x33, 0x1c, 0x24, // offset 22 -- xorq (%rsp), %r11
- 0x4c, 0x3b, 0x1d, 0xd7, 0x0c, 0x00, 0x00, // offset 26 -- cmp 3287(%rsp), %r11
- 0x0f, 0x84, 0x02, 0x00, 0x00, 0x00, // offset 33 -- je +2
- 0xcc, // offset 39 -- int3
- 0xcc, // offset 40 -- int3
- 0xc3 // offset 41 -- retq
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // We expect 4 rows in the unwind plan, corresponding to offsets
- // 0: CFA=rsp+8 => rsp=CFA+0, rip=[CFA-8]
- // 12: CFA=rsp+16 => rsp=CFA+0, rip=[CFA-8], rbp=[CFA-16]
- // 15: CFA=rbp+16 => rsp=CFA+0, rip=[CFA-8], rbp=[CFA-16]
- // 22: CFA=rsp+8 => rsp=CFA+0, rip=[CFA-8]
-
- EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
- EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
- eLazyBoolYes);
- EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // 0: CFA=rsp+8 => rsp=CFA+0, rip=[CFA-8]
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rsp, regloc));
- EXPECT_TRUE(regloc.IsCFAPlusOffset());
- EXPECT_EQ(0, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(11);
- EXPECT_EQ(0ull, row_sp->GetOffset());
-
- // 12: CFA=rsp+16 => rsp=CFA+0, rip=[CFA-8], rbp=[CFA-16]
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rsp, regloc));
- EXPECT_TRUE(regloc.IsCFAPlusOffset());
- EXPECT_EQ(0, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- // 15: CFA=rbp+16 => rsp=CFA+0, rip=[CFA-8], rbp=[CFA-16]
- row_sp = unwind_plan.GetRowForFunctionOffset(15);
- EXPECT_EQ(15ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rsp, regloc));
- EXPECT_TRUE(regloc.IsCFAPlusOffset());
- EXPECT_EQ(0, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rbp, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-16, regloc.GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(17);
- EXPECT_EQ(15ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(19);
- EXPECT_EQ(15ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(21);
- EXPECT_EQ(15ull, row_sp->GetOffset());
-
- // 22: CFA=rsp+8 => rsp=CFA+0, rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(22);
- EXPECT_EQ(22ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rsp, regloc));
- EXPECT_TRUE(regloc.IsCFAPlusOffset());
- EXPECT_EQ(0, regloc.GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- row_sp = unwind_plan.GetRowForFunctionOffset(26);
- EXPECT_EQ(22ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(33);
- EXPECT_EQ(22ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(39);
- EXPECT_EQ(22ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(40);
- EXPECT_EQ(22ull, row_sp->GetOffset());
- row_sp = unwind_plan.GetRowForFunctionOffset(41);
- EXPECT_EQ(22ull, row_sp->GetOffset());
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitPrologueDetection) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // 'int main() { }' compiled for x86_64-apple-macosx with clang
- uint8_t data[] = {
- 0x55, // offset 0 -- pushq %rbp
- 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
- 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
- 0x5d, // offset 6 -- popq %rbp
- 0xc3 // offset 7 -- retq
- };
-
- size_t offset = 0;
- EXPECT_TRUE(engine->FindFirstNonPrologueInstruction(data, sizeof(data), offset));
- EXPECT_EQ(4ull, offset);
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestRetguard64bitPrologueDetection) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // 'int main() { }' compiled for amd64-unknown-openbsd6.4 with -fret-protector
- uint8_t data[] = {
- 0x4c, 0x8b, 0x1d, 0xf1, 0x0c, 0x00, 0x00, // offset 0 -- movq 3313(%rip), %r11
- 0x4c, 0x33, 0x1c, 0x24, // offset 7 -- xorq (%rsp), %r11
- 0x55, // offset 11 -- pushq %rbp
- 0x48, 0x89, 0xe5, // offset 12 -- movq %rsp, %rbp
- 0x41, 0x53, // offset 15 -- pushq %r11
- 0x31, 0xc0, // offset 17 -- xorl %eax, %eax
- 0x41, 0x5b, // offset 19 -- popq %r11
- 0x5d, // offset 21 -- popq %rbp
- 0x4c, 0x33, 0x1c, 0x24, // offset 22 -- xorq (%rsp), %r11
- 0x4c, 0x3b, 0x1d, 0xd7, 0x0c, 0x00, 0x00, // offset 26 -- cmp 3287(%rsp), %r11
- 0x0f, 0x84, 0x02, 0x00, 0x00, 0x00, // offset 33 -- je +2
- 0xcc, // offset 39 -- int3
- 0xcc, // offset 40 -- int3
- 0xc3 // offset 41 -- retq
- };
-
- size_t offset = 0;
- EXPECT_TRUE(engine->FindFirstNonPrologueInstruction(data, sizeof(data), offset));
- EXPECT_EQ(17ull, offset);
-}
-
-TEST_F(Testx86AssemblyInspectionEngine, TestReturnDetect) {
- std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
-
- // Single fragment with all four return forms.
- // We want to verify that the unwind state is reset after each ret.
- uint8_t data[] = {
- 0x55, // offset 0 -- pushq %rbp
- 0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
- 0x31, 0xc0, // offset 4 -- xorl %eax, %eax
- 0x5d, // offset 6 -- popq %rbp
- 0xc3, // offset 7 -- retq
- 0x31, 0xc0, // offset 8 -- xorl %eax, %eax
- 0x5d, // offset 10 -- popq %rbp
- 0xcb, // offset 11 -- retf
- 0x31, 0xc0, // offset 12 -- xorl %eax, %eax
- 0x5d, // offset 14 -- popq %rbp
- 0xc2, 0x22, 0x11, // offset 15 -- retq 0x1122
- 0x31, 0xc0, // offset 18 -- xorl %eax, %eax
- 0x5d, // offset 20 -- popq %rbp
- 0xca, 0x44, 0x33, // offset 21 -- retf 0x3344
- 0x31, 0xc0, // offset 24 -- xorl %eax, %eax
- };
-
- AddressRange sample_range(0x1000, sizeof(data));
-
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
- data, sizeof(data), sample_range, unwind_plan));
-
- // Expect following unwind rows:
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
-
- EXPECT_TRUE(unwind_plan.GetInitialCFARegister() == k_rsp);
- EXPECT_TRUE(unwind_plan.GetUnwindPlanValidAtAllInstructions() ==
- eLazyBoolYes);
- EXPECT_TRUE(unwind_plan.GetSourcedFromCompiler() == eLazyBoolNo);
-
- UnwindPlan::Row::RegisterLocation regloc;
-
- // 0: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(0);
- EXPECT_EQ(0ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 1: CFA=rsp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(1);
- EXPECT_EQ(1ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 4: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(4);
- EXPECT_EQ(4ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 7: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(7);
- EXPECT_EQ(7ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 8: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(8);
- EXPECT_EQ(8ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 11: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(11);
- EXPECT_EQ(11ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 12: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(12);
- EXPECT_EQ(12ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 15: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(15);
- EXPECT_EQ(15ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 18: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(18);
- EXPECT_EQ(18ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 21: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(21);
- EXPECT_EQ(21ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(8, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-
- // 24: CFA=rbp+16 => rbp=[CFA-16] rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(24);
- EXPECT_EQ(24ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset());
-
- EXPECT_TRUE(row_sp->GetRegisterInfo(k_rip, regloc));
- EXPECT_TRUE(regloc.IsAtCFAPlusOffset());
- EXPECT_EQ(-8, regloc.GetOffset());
-}
-
-
-// Test mid-function epilogues - the unwind state post-prologue
-// should be re-instated.
-
-TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyMidFunctionEpilogues) {
- AddressRange sample_range;
- UnwindPlan unwind_plan(eRegisterKindLLDB);
- std::unique_ptr<x86AssemblyInspectionEngine> engine32 = Geti386Inspector();
- std::unique_ptr<x86AssemblyInspectionEngine> engine64 = Getx86_64Inspector();
-
- uint8_t data[] = {
- 0x55, // <+0>: pushq %rbp
- 0x48, 0x89, 0xe5, // <+1>: movq %rsp, %rbp
- 0x48, 0x83, 0xec, 0x70, // <+4>: subq $0x70, %rsp
- 0x90, // <+8>: nop // prologue set up
-
- 0x74, 0x7, // <+9>: je 7 <+18>
- 0x48, 0x83, 0xc4, 0x70, // <+11>: addq $0x70, %rsp
- 0x5d, // <+15>: popq %rbp
- 0xff, 0xe0, // <+16>: jmpq *%rax // epilogue completed
-
- 0x90, // <+18>: nop // prologue setup back
-
- 0x74, 0x7, // <+19>: je 6 <+27>
- 0x48, 0x83, 0xc4, 0x70, // <+21>: addq $0x70, %rsp
- 0x5d, // <+25>: popq %rbp
- 0xc3, // <+26>: retq // epilogue completed
-
- 0x90, // <+27>: nop // prologue setup back
-
- 0x48, 0x83, 0xc4, 0x70, // <+28>: addq $0x70, %rsp
- 0x5d, // <+32>: popq %rbp
- 0xc3, // <+33>: retq // epilogue completed
-
- };
-
- sample_range = AddressRange(0x1000, sizeof(data));
-
- int wordsize = 4;
- EXPECT_TRUE(engine32->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Check that we've unwound the stack after the first mid-function epilogue
- // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- UnwindPlan::RowSP row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
-
- // Check that we've reinstated the stack frame setup
- // unwind instructions after a jmpq *%eax
- // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(18);
- EXPECT_EQ(18ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
-
- // Check that we've reinstated the stack frame setup
- // unwind instructions after a mid-function retq
- // row: CFA=ebp +8 => esp=CFA+0 eip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(27);
- EXPECT_EQ(27ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_ebp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
-
- // After last instruction in the function, verify that
- // the stack frame has been unwound
- // row: CFA=esp +4 => esp=CFA+0 eip=[CFA-4]
- row_sp = unwind_plan.GetRowForFunctionOffset(33);
- EXPECT_EQ(33ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_esp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
-
-
- unwind_plan.Clear();
-
- wordsize = 8;
- EXPECT_TRUE(engine64->GetNonCallSiteUnwindPlanFromAssembly(
- data, sizeof(data), sample_range, unwind_plan));
-
- // Check that we've unwound the stack after the first mid-function epilogue
- // row: CFA=rsp +8 => rsp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(16);
- EXPECT_EQ(16ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
-
- // Check that we've reinstated the stack frame setup
- // unwind instructions after a jmpq *%eax
- // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
- row_sp = unwind_plan.GetRowForFunctionOffset(18);
- EXPECT_EQ(18ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
-
- // Check that we've reinstated the stack frame setup
- // unwind instructions after a mid-function retq
- // row: CFA=rbp+16 => rsp=CFA+0 rip=[CFA-16]
- row_sp = unwind_plan.GetRowForFunctionOffset(27);
- EXPECT_EQ(27ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rbp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize * 2, row_sp->GetCFAValue().GetOffset());
-
- // After last instruction in the function, verify that
- // the stack frame has been unwound
- // row: CFA=rsp +8 => esp=CFA+0 rip=[CFA-8]
- row_sp = unwind_plan.GetRowForFunctionOffset(33);
- EXPECT_EQ(33ull, row_sp->GetOffset());
- EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == k_rsp);
- EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true);
- EXPECT_EQ(wordsize, row_sp->GetCFAValue().GetOffset());
-
-
-}
+++ /dev/null
-//===-- AnsiTerminalTest.cpp ----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/AnsiTerminal.h"
-
-using namespace lldb_private;
-
-TEST(AnsiTerminal, Empty) { EXPECT_EQ("", ansi::FormatAnsiTerminalCodes("")); }
-
-TEST(AnsiTerminal, WhiteSpace) {
- EXPECT_EQ(" ", ansi::FormatAnsiTerminalCodes(" "));
-}
-
-TEST(AnsiTerminal, AtEnd) {
- EXPECT_EQ("abc\x1B[30m",
- ansi::FormatAnsiTerminalCodes("abc${ansi.fg.black}"));
-}
-
-TEST(AnsiTerminal, AtStart) {
- EXPECT_EQ("\x1B[30mabc",
- ansi::FormatAnsiTerminalCodes("${ansi.fg.black}abc"));
-}
-
-TEST(AnsiTerminal, KnownPrefix) {
- EXPECT_EQ("${ansi.fg.redish}abc",
- ansi::FormatAnsiTerminalCodes("${ansi.fg.redish}abc"));
-}
-
-TEST(AnsiTerminal, Unknown) {
- EXPECT_EQ("${ansi.fg.foo}abc",
- ansi::FormatAnsiTerminalCodes("${ansi.fg.foo}abc"));
-}
-
-TEST(AnsiTerminal, Incomplete) {
- EXPECT_EQ("abc${ansi.", ansi::FormatAnsiTerminalCodes("abc${ansi."));
-}
-
-TEST(AnsiTerminal, Twice) {
- EXPECT_EQ("\x1B[30m\x1B[31mabc",
- ansi::FormatAnsiTerminalCodes("${ansi.fg.black}${ansi.fg.red}abc"));
-}
-
-TEST(AnsiTerminal, Basic) {
- EXPECT_EQ(
- "abc\x1B[31mabc\x1B[0mabc",
- ansi::FormatAnsiTerminalCodes("abc${ansi.fg.red}abc${ansi.normal}abc"));
-}
+++ /dev/null
-//===-- ArchSpecTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/ArchSpec.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Support/YAMLParser.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(ArchSpecTest, TestParseMachCPUDashSubtypeTripleSimple) {
-
- // Success conditions. Valid cpu/subtype combinations using both - and .
- ArchSpec AS;
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(10u, AS.GetMachOCPUSubType());
-
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(15u, AS.GetMachOCPUSubType());
-
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12.15", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(15u, AS.GetMachOCPUSubType());
-
- // Failure conditions.
-
- // Valid string, unknown cpu/subtype.
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("13.11", AS));
- EXPECT_EQ(0u, AS.GetMachOCPUType());
- EXPECT_EQ(0u, AS.GetMachOCPUSubType());
-
- // Missing / invalid cpu or subtype
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("13", AS));
-
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("13.A", AS));
-
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("A.13", AS));
-
- // Empty string.
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("", AS));
-}
-
-TEST(ArchSpecTest, TestParseMachCPUDashSubtypeTripleExtra) {
- ArchSpec AS;
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15-vendor-os", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(15u, AS.GetMachOCPUSubType());
- EXPECT_EQ("vendor", AS.GetTriple().getVendorName());
- EXPECT_EQ("os", AS.GetTriple().getOSName());
-
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10-vendor-os-name", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(10u, AS.GetMachOCPUSubType());
- EXPECT_EQ("vendor", AS.GetTriple().getVendorName());
- EXPECT_EQ("os", AS.GetTriple().getOSName());
-
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-15-vendor.os-name", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(15u, AS.GetMachOCPUSubType());
- EXPECT_EQ("vendor.os", AS.GetTriple().getVendorName());
- EXPECT_EQ("name", AS.GetTriple().getOSName());
-
- // These there should parse correctly, but the vendor / OS should be defaulted
- // since they are unrecognized.
- AS = ArchSpec();
- EXPECT_TRUE(ParseMachCPUDashSubtypeTriple("12-10-vendor", AS));
- EXPECT_EQ(12u, AS.GetMachOCPUType());
- EXPECT_EQ(10u, AS.GetMachOCPUSubType());
- EXPECT_EQ("apple", AS.GetTriple().getVendorName());
- EXPECT_EQ("", AS.GetTriple().getOSName());
-
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("12.10.10", AS));
-
- AS = ArchSpec();
- EXPECT_FALSE(ParseMachCPUDashSubtypeTriple("12-10.10", AS));
-}
-
-TEST(ArchSpecTest, TestSetTriple) {
- ArchSpec AS;
-
- // Various flavors of valid triples.
- EXPECT_TRUE(AS.SetTriple("12-10-apple-darwin"));
- EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_ARM), AS.GetMachOCPUType());
- EXPECT_EQ(10u, AS.GetMachOCPUSubType());
- EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str())
- .consume_front("armv7f-apple-darwin"));
- EXPECT_EQ(ArchSpec::eCore_arm_armv7f, AS.GetCore());
-
- AS = ArchSpec();
- EXPECT_TRUE(AS.SetTriple("18.100-apple-darwin"));
- EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_POWERPC), AS.GetMachOCPUType());
- EXPECT_EQ(100u, AS.GetMachOCPUSubType());
- EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str())
- .consume_front("powerpc-apple-darwin"));
- EXPECT_EQ(ArchSpec::eCore_ppc_ppc970, AS.GetCore());
-
- AS = ArchSpec();
- EXPECT_TRUE(AS.SetTriple("i686-pc-windows"));
- EXPECT_EQ(llvm::Triple::x86, AS.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::PC, AS.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::Win32, AS.GetTriple().getOS());
- EXPECT_TRUE(
- llvm::StringRef(AS.GetTriple().str()).consume_front("i686-pc-windows"));
- EXPECT_STREQ("i686", AS.GetArchitectureName());
- EXPECT_EQ(ArchSpec::eCore_x86_32_i686, AS.GetCore());
-
- // Various flavors of invalid triples.
- AS = ArchSpec();
- EXPECT_FALSE(AS.SetTriple("unknown-unknown-unknown"));
-
- AS = ArchSpec();
- EXPECT_FALSE(AS.SetTriple("unknown"));
-
- AS = ArchSpec();
- EXPECT_FALSE(AS.SetTriple(""));
-}
-
-TEST(ArchSpecTest, MergeFrom) {
- {
- ArchSpec A;
- ArchSpec B("x86_64-pc-linux");
-
- EXPECT_FALSE(A.IsValid());
- ASSERT_TRUE(B.IsValid());
- EXPECT_EQ(llvm::Triple::ArchType::x86_64, B.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::PC, B.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS());
- EXPECT_EQ(ArchSpec::eCore_x86_64_x86_64, B.GetCore());
-
- A.MergeFrom(B);
- ASSERT_TRUE(A.IsValid());
- EXPECT_EQ(llvm::Triple::ArchType::x86_64, A.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::PC, A.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS());
- EXPECT_EQ(ArchSpec::eCore_x86_64_x86_64, A.GetCore());
- }
- {
- ArchSpec A("aarch64");
- ArchSpec B("aarch64--linux-android");
-
- ArchSpec C("arm64_32");
- ArchSpec D("arm64_32--watchos");
-
- EXPECT_TRUE(A.IsValid());
- EXPECT_TRUE(B.IsValid());
- EXPECT_TRUE(C.IsValid());
- EXPECT_TRUE(D.IsValid());
-
- EXPECT_EQ(llvm::Triple::ArchType::aarch64, B.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- B.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::EnvironmentType::Android,
- B.GetTriple().getEnvironment());
-
- A.MergeFrom(B);
- EXPECT_EQ(llvm::Triple::ArchType::aarch64, A.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- A.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::EnvironmentType::Android,
- A.GetTriple().getEnvironment());
-
- EXPECT_EQ(llvm::Triple::ArchType::aarch64_32, D.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- D.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::WatchOS, D.GetTriple().getOS());
-
- C.MergeFrom(D);
- EXPECT_EQ(llvm::Triple::ArchType::aarch64_32, C.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- C.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::WatchOS, C.GetTriple().getOS());
- }
- {
- ArchSpec A, B;
- A.SetArchitecture(eArchTypeELF, llvm::ELF::EM_ARM,
- LLDB_INVALID_CPUTYPE, llvm::ELF::ELFOSABI_NONE);
- B.SetArchitecture(eArchTypeELF, llvm::ELF::EM_ARM,
- LLDB_INVALID_CPUTYPE, llvm::ELF::ELFOSABI_LINUX);
-
- EXPECT_TRUE(A.IsValid());
- EXPECT_TRUE(B.IsValid());
-
- EXPECT_EQ(llvm::Triple::ArchType::arm, B.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- B.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::EnvironmentType::UnknownEnvironment,
- B.GetTriple().getEnvironment());
-
- A.MergeFrom(B);
- EXPECT_EQ(llvm::Triple::ArchType::arm, A.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- A.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::EnvironmentType::UnknownEnvironment,
- A.GetTriple().getEnvironment());
- }
- {
- ArchSpec A("arm--linux-eabihf");
- ArchSpec B("armv8l--linux-gnueabihf");
-
- EXPECT_TRUE(A.IsValid());
- EXPECT_TRUE(B.IsValid());
-
- EXPECT_EQ(llvm::Triple::ArchType::arm, A.GetTriple().getArch());
- EXPECT_EQ(llvm::Triple::ArchType::arm, B.GetTriple().getArch());
-
- EXPECT_EQ(ArchSpec::eCore_arm_generic, A.GetCore());
- EXPECT_EQ(ArchSpec::eCore_arm_armv8l, B.GetCore());
-
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- A.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- B.GetTriple().getVendor());
-
- EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS());
-
- EXPECT_EQ(llvm::Triple::EnvironmentType::EABIHF,
- A.GetTriple().getEnvironment());
- EXPECT_EQ(llvm::Triple::EnvironmentType::GNUEABIHF,
- B.GetTriple().getEnvironment());
-
- A.MergeFrom(B);
- EXPECT_EQ(llvm::Triple::ArchType::arm, A.GetTriple().getArch());
- EXPECT_EQ(ArchSpec::eCore_arm_armv8l, A.GetCore());
- EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor,
- A.GetTriple().getVendor());
- EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS());
- EXPECT_EQ(llvm::Triple::EnvironmentType::EABIHF,
- A.GetTriple().getEnvironment());
- }
-}
-
-TEST(ArchSpecTest, MergeFromMachOUnknown) {
- class MyArchSpec : public ArchSpec {
- public:
- MyArchSpec() {
- this->SetTriple("unknown-mach-64");
- this->m_core = ArchSpec::eCore_uknownMach64;
- this->m_byte_order = eByteOrderLittle;
- this->m_flags = 0;
- }
- };
-
- MyArchSpec A;
- ASSERT_TRUE(A.IsValid());
- MyArchSpec B;
- ASSERT_TRUE(B.IsValid());
- A.MergeFrom(B);
- ASSERT_EQ(A.GetCore(), ArchSpec::eCore_uknownMach64);
-}
-
-TEST(ArchSpecTest, Compatibility) {
- {
- ArchSpec A("x86_64-apple-macosx10.12");
- ArchSpec B("x86_64-apple-macosx10.12");
- ASSERT_TRUE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- // The version information is auxiliary to support availability but
- // doesn't affect compatibility.
- ArchSpec A("x86_64-apple-macosx10.11");
- ArchSpec B("x86_64-apple-macosx10.12");
- ASSERT_TRUE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-macosx10.13");
- ArchSpec B("x86_64h-apple-macosx10.13");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-macosx");
- ArchSpec B("x86_64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-*-*");
- ArchSpec B("x86_64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- ASSERT_FALSE(B.IsExactMatch(A));
- ASSERT_FALSE(B.IsCompatibleMatch(A));
- }
- {
- ArchSpec A("x86_64-apple-ios");
- ArchSpec B("x86_64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- ASSERT_FALSE(B.IsExactMatch(A));
- ASSERT_FALSE(B.IsCompatibleMatch(A));
- }
- {
- // FIXME: This is surprisingly not equivalent to "x86_64-*-*".
- ArchSpec A("x86_64");
- ArchSpec B("x86_64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- ASSERT_FALSE(B.IsExactMatch(A));
- ASSERT_TRUE(B.IsCompatibleMatch(A));
- }
- {
- ArchSpec A("arm64-apple-ios");
- ArchSpec B("arm64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- ASSERT_FALSE(B.IsCompatibleMatch(A));
- ASSERT_FALSE(B.IsCompatibleMatch(A));
- }
- {
- ArchSpec A("arm64-*-*");
- ArchSpec B("arm64-apple-ios");
- ASSERT_FALSE(A.IsExactMatch(B));
- // FIXME: This looks unintuitive and we should investigate whether
- // this is the desired behavior.
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-*-*");
- ArchSpec B("x86_64-apple-ios-simulator");
- ASSERT_FALSE(A.IsExactMatch(B));
- // FIXME: See above, though the extra environment complicates things.
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64");
- ArchSpec B("x86_64-apple-macosx10.14");
- // FIXME: The exact match also looks unintuitive.
- ASSERT_TRUE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64");
- ArchSpec B("x86_64-apple-ios12.0.0-macabi");
- // FIXME: The exact match also looks unintuitive.
- ASSERT_TRUE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-ios12.0.0");
- ArchSpec B("x86_64-apple-ios12.0.0-macabi");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_FALSE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-macosx10.14.2");
- ArchSpec B("x86_64-apple-ios12.0.0-macabi");
- ASSERT_FALSE(A.IsExactMatch(B));
- ASSERT_TRUE(A.IsCompatibleMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-macosx10.14.2");
- ArchSpec B("x86_64-apple-ios12.0.0-macabi");
- // ios-macabi wins.
- A.MergeFrom(B);
- ASSERT_TRUE(A.IsExactMatch(B));
- }
- {
- ArchSpec A("x86_64-apple-macosx10.14.2");
- ArchSpec B("x86_64-apple-ios12.0.0-macabi");
- ArchSpec C(B);
- // ios-macabi wins.
- B.MergeFrom(A);
- ASSERT_TRUE(B.IsExactMatch(C));
- }
-}
-
-TEST(ArchSpecTest, OperatorBool) {
- EXPECT_FALSE(ArchSpec());
- EXPECT_TRUE(ArchSpec("x86_64-pc-linux"));
-}
-
-TEST(ArchSpecTest, TripleComponentsWereSpecified) {
- {
- ArchSpec A("");
- ArchSpec B("-");
- ArchSpec C("--");
- ArchSpec D("---");
-
- ASSERT_FALSE(A.TripleVendorWasSpecified());
- ASSERT_FALSE(A.TripleOSWasSpecified());
- ASSERT_FALSE(A.TripleEnvironmentWasSpecified());
-
- ASSERT_FALSE(B.TripleVendorWasSpecified());
- ASSERT_FALSE(B.TripleOSWasSpecified());
- ASSERT_FALSE(B.TripleEnvironmentWasSpecified());
-
- ASSERT_FALSE(C.TripleVendorWasSpecified());
- ASSERT_FALSE(C.TripleOSWasSpecified());
- ASSERT_FALSE(C.TripleEnvironmentWasSpecified());
-
- ASSERT_FALSE(D.TripleVendorWasSpecified());
- ASSERT_FALSE(D.TripleOSWasSpecified());
- ASSERT_FALSE(D.TripleEnvironmentWasSpecified());
- }
- {
- // TODO: llvm::Triple::normalize treats the missing components from these
- // triples as specified unknown components instead of unspecified
- // components. We need to either change the behavior in llvm or work around
- // this in lldb.
- ArchSpec A("armv7");
- ArchSpec B("armv7-");
- ArchSpec C("armv7--");
- ArchSpec D("armv7---");
-
- ASSERT_FALSE(A.TripleVendorWasSpecified());
- ASSERT_FALSE(A.TripleOSWasSpecified());
- ASSERT_FALSE(A.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(B.TripleVendorWasSpecified());
- ASSERT_FALSE(B.TripleOSWasSpecified());
- ASSERT_FALSE(B.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(C.TripleVendorWasSpecified());
- ASSERT_TRUE(C.TripleOSWasSpecified());
- ASSERT_FALSE(C.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(D.TripleVendorWasSpecified());
- ASSERT_TRUE(D.TripleOSWasSpecified());
- ASSERT_TRUE(D.TripleEnvironmentWasSpecified());
- }
- {
- ArchSpec A("x86_64-unknown");
- ArchSpec B("powerpc-unknown-linux");
- ArchSpec C("i386-pc-windows-msvc");
- ArchSpec D("aarch64-unknown-linux-android");
-
- ASSERT_TRUE(A.TripleVendorWasSpecified());
- ASSERT_FALSE(A.TripleOSWasSpecified());
- ASSERT_FALSE(A.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(B.TripleVendorWasSpecified());
- ASSERT_TRUE(B.TripleOSWasSpecified());
- ASSERT_FALSE(B.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(C.TripleVendorWasSpecified());
- ASSERT_TRUE(C.TripleOSWasSpecified());
- ASSERT_TRUE(C.TripleEnvironmentWasSpecified());
-
- ASSERT_TRUE(D.TripleVendorWasSpecified());
- ASSERT_TRUE(D.TripleOSWasSpecified());
- ASSERT_TRUE(D.TripleEnvironmentWasSpecified());
- }
-}
-
-TEST(ArchSpecTest, YAML) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- llvm::yaml::Output yout(os);
- std::vector<ArchSpec> archs = {ArchSpec("x86_64-pc-linux"),
- ArchSpec("x86_64-apple-macosx10.12"),
- ArchSpec("i686-pc-windows")};
- yout << archs;
- os.flush();
-
- // Deserialize.
- std::vector<ArchSpec> deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- EXPECT_EQ(archs, deserialized);
-}
+++ /dev/null
-//===-- ArgsTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Args.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/StringList.h"
-
-#include <limits>
-#include <sstream>
-
-using namespace lldb_private;
-
-TEST(ArgsTest, TestSingleArg) {
- Args args;
- args.SetCommandString("arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
-}
-
-TEST(ArgsTest, TestSingleQuotedArgWithSpace) {
- Args args;
- args.SetCommandString("\"arg with space\"");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
-}
-
-TEST(ArgsTest, TestSingleArgWithQuotedSpace) {
- Args args;
- args.SetCommandString("arg\\ with\\ space");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg with space");
-}
-
-TEST(ArgsTest, TestTrailingBackslash) {
- Args args;
- args.SetCommandString("arg\\");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\");
-}
-
-TEST(ArgsTest, TestQuotedTrailingBackslash) {
- Args args;
- args.SetCommandString("\"arg\\");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\");
-}
-
-TEST(ArgsTest, TestUnknownEscape) {
- Args args;
- args.SetCommandString("arg\\y");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\y");
-}
-
-TEST(ArgsTest, TestQuotedUnknownEscape) {
- Args args;
- args.SetCommandString("\"arg\\y");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg\\y");
-}
-
-TEST(ArgsTest, TestMultipleArgs) {
- Args args;
- args.SetCommandString("this has multiple args");
- EXPECT_EQ(4u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "this");
- EXPECT_STREQ(args.GetArgumentAtIndex(1), "has");
- EXPECT_STREQ(args.GetArgumentAtIndex(2), "multiple");
- EXPECT_STREQ(args.GetArgumentAtIndex(3), "args");
-}
-
-TEST(ArgsTest, TestOverwriteArgs) {
- Args args;
- args.SetCommandString("this has multiple args");
- EXPECT_EQ(4u, args.GetArgumentCount());
- args.SetCommandString("arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "arg");
-}
-
-TEST(ArgsTest, TestAppendArg) {
- Args args;
- args.SetCommandString("first_arg");
- EXPECT_EQ(1u, args.GetArgumentCount());
- args.AppendArgument(llvm::StringRef("second_arg"));
- EXPECT_EQ(2u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "first_arg");
- EXPECT_STREQ(args.GetArgumentAtIndex(1), "second_arg");
-}
-
-TEST(ArgsTest, TestInsertArg) {
- Args args;
- args.AppendArgument("1");
- args.AppendArgument("2");
- args.AppendArgument("3");
- args.InsertArgumentAtIndex(1, "1.5");
- args.InsertArgumentAtIndex(4, "3.5");
-
- ASSERT_EQ(5u, args.GetArgumentCount());
- EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
- EXPECT_STREQ("1.5", args.GetArgumentAtIndex(1));
- EXPECT_STREQ("2", args.GetArgumentAtIndex(2));
- EXPECT_STREQ("3", args.GetArgumentAtIndex(3));
- EXPECT_STREQ("3.5", args.GetArgumentAtIndex(4));
-}
-
-TEST(ArgsTest, TestArgv) {
- Args args;
- EXPECT_EQ(nullptr, args.GetArgumentVector());
-
- args.AppendArgument("1");
- EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[1]);
-
- args.AppendArgument("2");
- EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);
-
- args.AppendArgument("3");
- EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[3]);
-
- args.InsertArgumentAtIndex(1, "1.5");
- EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[3]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);
-
- args.InsertArgumentAtIndex(4, "3.5");
- EXPECT_NE(nullptr, args.GetArgumentVector()[0]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[1]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[2]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[3]);
- EXPECT_NE(nullptr, args.GetArgumentVector()[4]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[5]);
-}
-
-TEST(ArgsTest, StringListConstructor) {
- StringList list;
- list << "foo"
- << "bar"
- << "baz";
- Args args(list);
- ASSERT_EQ(3u, args.GetArgumentCount());
- EXPECT_EQ("foo", args[0].ref());
- EXPECT_EQ("bar", args[1].ref());
- EXPECT_EQ("baz", args[2].ref());
-}
-
-TEST(ArgsTest, GetQuotedCommandString) {
- Args args;
- const char *str = "process launch -o stdout.txt -- \"a b c\"";
- args.SetCommandString(str);
-
- std::string stdstr;
- ASSERT_TRUE(args.GetQuotedCommandString(stdstr));
- EXPECT_EQ(str, stdstr);
-}
-
-TEST(ArgsTest, BareSingleQuote) {
- Args args;
- args.SetCommandString("a\\'b");
- EXPECT_EQ(1u, args.GetArgumentCount());
-
- EXPECT_STREQ("a'b", args.GetArgumentAtIndex(0));
-}
-
-TEST(ArgsTest, DoubleQuotedItem) {
- Args args;
- args.SetCommandString("\"a b c\"");
- EXPECT_EQ(1u, args.GetArgumentCount());
-
- EXPECT_STREQ("a b c", args.GetArgumentAtIndex(0));
-}
-
-TEST(ArgsTest, AppendArguments) {
- Args args;
- const char *argv[] = {"1", "2", nullptr};
- const char *argv2[] = {"3", "4", nullptr};
-
- args.AppendArguments(argv);
- ASSERT_EQ(2u, args.GetArgumentCount());
- EXPECT_STREQ("1", args.GetArgumentVector()[0]);
- EXPECT_STREQ("2", args.GetArgumentVector()[1]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[2]);
- EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
- EXPECT_STREQ("2", args.GetArgumentAtIndex(1));
-
- args.AppendArguments(argv2);
- ASSERT_EQ(4u, args.GetArgumentCount());
- EXPECT_STREQ("1", args.GetArgumentVector()[0]);
- EXPECT_STREQ("2", args.GetArgumentVector()[1]);
- EXPECT_STREQ("3", args.GetArgumentVector()[2]);
- EXPECT_STREQ("4", args.GetArgumentVector()[3]);
- EXPECT_EQ(nullptr, args.GetArgumentVector()[4]);
- EXPECT_STREQ("1", args.GetArgumentAtIndex(0));
- EXPECT_STREQ("2", args.GetArgumentAtIndex(1));
- EXPECT_STREQ("3", args.GetArgumentAtIndex(2));
- EXPECT_STREQ("4", args.GetArgumentAtIndex(3));
-}
-
-TEST(ArgsTest, GetArgumentArrayRef) {
- Args args("foo bar");
- auto ref = args.GetArgumentArrayRef();
- ASSERT_EQ(2u, ref.size());
- EXPECT_STREQ("foo", ref[0]);
- EXPECT_STREQ("bar", ref[1]);
-}
-
-TEST(ArgsTest, EscapeLLDBCommandArgument) {
- const std::string foo = "foo'";
- EXPECT_EQ("foo\\'", Args::EscapeLLDBCommandArgument(foo, '\0'));
- EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '\''));
- EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '`'));
- EXPECT_EQ("foo'", Args::EscapeLLDBCommandArgument(foo, '"'));
-
- const std::string bar = "bar\"";
- EXPECT_EQ("bar\\\"", Args::EscapeLLDBCommandArgument(bar, '\0'));
- EXPECT_EQ("bar\"", Args::EscapeLLDBCommandArgument(bar, '\''));
- EXPECT_EQ("bar\"", Args::EscapeLLDBCommandArgument(bar, '`'));
- EXPECT_EQ("bar\\\"", Args::EscapeLLDBCommandArgument(bar, '"'));
-
- const std::string baz = "baz`";
- EXPECT_EQ("baz\\`", Args::EscapeLLDBCommandArgument(baz, '\0'));
- EXPECT_EQ("baz`", Args::EscapeLLDBCommandArgument(baz, '\''));
- EXPECT_EQ("baz`", Args::EscapeLLDBCommandArgument(baz, '`'));
- EXPECT_EQ("baz\\`", Args::EscapeLLDBCommandArgument(baz, '"'));
-
- const std::string quux = "quux\t";
- EXPECT_EQ("quux\\\t", Args::EscapeLLDBCommandArgument(quux, '\0'));
- EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '\''));
- EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '`'));
- EXPECT_EQ("quux\t", Args::EscapeLLDBCommandArgument(quux, '"'));
-}
-
-TEST(ArgsTest, ReplaceArgumentAtIndexShort) {
- Args args;
- args.SetCommandString("foo ba b");
- args.ReplaceArgumentAtIndex(0, "f");
- EXPECT_EQ(3u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "f");
-}
-
-TEST(ArgsTest, ReplaceArgumentAtIndexEqual) {
- Args args;
- args.SetCommandString("foo ba b");
- args.ReplaceArgumentAtIndex(0, "bar");
- EXPECT_EQ(3u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "bar");
-}
-
-TEST(ArgsTest, ReplaceArgumentAtIndexLonger) {
- Args args;
- args.SetCommandString("foo ba b");
- args.ReplaceArgumentAtIndex(0, "baar");
- EXPECT_EQ(3u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(0), "baar");
-}
-
-TEST(ArgsTest, ReplaceArgumentAtIndexOutOfRange) {
- Args args;
- args.SetCommandString("foo ba b");
- args.ReplaceArgumentAtIndex(3, "baar");
- EXPECT_EQ(3u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(2), "b");
-}
-
-TEST(ArgsTest, ReplaceArgumentAtIndexFarOutOfRange) {
- Args args;
- args.SetCommandString("foo ba b");
- args.ReplaceArgumentAtIndex(4, "baar");
- EXPECT_EQ(3u, args.GetArgumentCount());
- EXPECT_STREQ(args.GetArgumentAtIndex(2), "b");
-}
-
-TEST(ArgsTest, Yaml) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- Args args;
- args.SetCommandString("this 'has' \"multiple\" args");
- llvm::yaml::Output yout(os);
- yout << args;
- os.flush();
-
- llvm::outs() << buffer;
-
- // Deserialize.
- Args deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- EXPECT_EQ(4u, deserialized.GetArgumentCount());
- EXPECT_STREQ(deserialized.GetArgumentAtIndex(0), "this");
- EXPECT_STREQ(deserialized.GetArgumentAtIndex(1), "has");
- EXPECT_STREQ(deserialized.GetArgumentAtIndex(2), "multiple");
- EXPECT_STREQ(deserialized.GetArgumentAtIndex(3), "args");
-
- llvm::ArrayRef<Args::ArgEntry> entries = deserialized.entries();
- EXPECT_EQ(entries[0].GetQuoteChar(), '\0');
- EXPECT_EQ(entries[1].GetQuoteChar(), '\'');
- EXPECT_EQ(entries[2].GetQuoteChar(), '"');
- EXPECT_EQ(entries[3].GetQuoteChar(), '\0');
-}
-
-TEST(ArgsTest, GetShellSafeArgument) {
- // Try escaping with bash at start/middle/end of the argument.
- FileSpec bash("/bin/bash", FileSpec::Style::posix);
- EXPECT_EQ(Args::GetShellSafeArgument(bash, "\"b"), "\\\"b");
- EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\""), "a\\\"");
- EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\"b"), "a\\\"b");
-
- FileSpec zsh("/bin/zsh", FileSpec::Style::posix);
- EXPECT_EQ(Args::GetShellSafeArgument(zsh, R"('";()<>&|\)"),
- R"(\'\"\;\(\)\<\>\&\|\\)");
- // Normal characters and expressions that shouldn't be escaped.
- EXPECT_EQ(Args::GetShellSafeArgument(zsh, "aA$1*"), "aA$1*");
-
- // String that doesn't need to be escaped
- EXPECT_EQ(Args::GetShellSafeArgument(bash, "a"), "a");
-
- // Try escaping with tcsh and the tcsh-specific "$" escape.
- FileSpec tcsh("/bin/tcsh", FileSpec::Style::posix);
- EXPECT_EQ(Args::GetShellSafeArgument(tcsh, "a$b"), "a\\$b");
- // Bash however doesn't need escaping for "$".
- EXPECT_EQ(Args::GetShellSafeArgument(bash, "a$b"), "a$b");
-
- // Try escaping with an unknown shell.
- FileSpec unknown_shell("/bin/unknown_shell", FileSpec::Style::posix);
- EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a'b"), "a\\'b");
- EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a\"b"), "a\\\"b");
-}
+++ /dev/null
-//===-- BroadcasterTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Broadcaster.h"
-#include "lldb/Utility/Event.h"
-#include "lldb/Utility/Listener.h"
-#include "lldb/Utility/Predicate.h"
-
-#include <thread>
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(BroadcasterTest, BroadcastEvent) {
- EventSP event_sp;
- Broadcaster broadcaster(nullptr, "test-broadcaster");
- std::chrono::seconds timeout(0);
-
- // Create a listener, sign it up, make sure it receives an event.
- ListenerSP listener1_sp = Listener::MakeListener("test-listener1");
- const uint32_t event_mask1 = 1;
- EXPECT_EQ(event_mask1,
- listener1_sp->StartListeningForEvents(&broadcaster, event_mask1));
- broadcaster.BroadcastEvent(event_mask1, nullptr);
- EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
- EXPECT_EQ(event_mask1, event_sp->GetType());
-
- {
- // Add one more listener, make sure it works as well.
- ListenerSP listener2_sp = Listener::MakeListener("test-listener2");
- const uint32_t event_mask2 = 1;
- EXPECT_EQ(event_mask2, listener2_sp->StartListeningForEvents(
- &broadcaster, event_mask1 | event_mask2));
- broadcaster.BroadcastEvent(event_mask2, nullptr);
- EXPECT_TRUE(listener2_sp->GetEvent(event_sp, timeout));
- EXPECT_EQ(event_mask2, event_sp->GetType());
-
- // Both listeners should get this event.
- broadcaster.BroadcastEvent(event_mask1, nullptr);
- EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
- EXPECT_EQ(event_mask1, event_sp->GetType());
- EXPECT_TRUE(listener2_sp->GetEvent(event_sp, timeout));
- EXPECT_EQ(event_mask2, event_sp->GetType());
- }
-
- // Now again only one listener should be active.
- broadcaster.BroadcastEvent(event_mask1, nullptr);
- EXPECT_TRUE(listener1_sp->GetEvent(event_sp, timeout));
- EXPECT_EQ(event_mask1, event_sp->GetType());
-}
-
-TEST(BroadcasterTest, EventTypeHasListeners) {
- EventSP event_sp;
- Broadcaster broadcaster(nullptr, "test-broadcaster");
-
- const uint32_t event_mask = 1;
- EXPECT_FALSE(broadcaster.EventTypeHasListeners(event_mask));
-
- {
- ListenerSP listener_sp = Listener::MakeListener("test-listener");
- EXPECT_EQ(event_mask,
- listener_sp->StartListeningForEvents(&broadcaster, event_mask));
- EXPECT_TRUE(broadcaster.EventTypeHasListeners(event_mask));
- }
-
- EXPECT_FALSE(broadcaster.EventTypeHasListeners(event_mask));
-}
+++ /dev/null
-add_lldb_unittest(UtilityTests
- AnsiTerminalTest.cpp
- ArgsTest.cpp
- OptionsWithRawTest.cpp
- ArchSpecTest.cpp
- BroadcasterTest.cpp
- ConstStringTest.cpp
- CompletionRequestTest.cpp
- DataExtractorTest.cpp
- EnvironmentTest.cpp
- EventTest.cpp
- FileSpecTest.cpp
- FlagsTest.cpp
- ListenerTest.cpp
- LogTest.cpp
- NameMatchesTest.cpp
- PredicateTest.cpp
- ProcessInfoTest.cpp
- ProcessInstanceInfoTest.cpp
- RangeMapTest.cpp
- RangeTest.cpp
- RegisterValueTest.cpp
- RegularExpressionTest.cpp
- ReproducerInstrumentationTest.cpp
- ReproducerTest.cpp
- ScalarTest.cpp
- SharedClusterTest.cpp
- StateTest.cpp
- StatusTest.cpp
- StreamTeeTest.cpp
- StreamTest.cpp
- StringExtractorGDBRemoteTest.cpp
- StringExtractorTest.cpp
- StringLexerTest.cpp
- StringListTest.cpp
- StructuredDataTest.cpp
- SubsystemRAIITest.cpp
- TildeExpressionResolverTest.cpp
- TimeoutTest.cpp
- TimerTest.cpp
- UriParserTest.cpp
- UserIDResolverTest.cpp
- UUIDTest.cpp
- VASprintfTest.cpp
- VMRangeTest.cpp
- XcodeSDKTest.cpp
-
- LINK_LIBS
- lldbUtility
- lldbUtilityHelpers
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
-
-add_unittest_inputs(UtilityTests
- StructuredData-basic.json
- )
+++ /dev/null
-//===-- CompletionRequestTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/CompletionRequest.h"
-using namespace lldb_private;
-
-TEST(CompletionRequest, Constructor) {
- std::string command = "a bad c";
- const unsigned cursor_pos = 3;
- const size_t arg_index = 1;
- StringList matches;
- CompletionResult result;
-
- CompletionRequest request(command, cursor_pos, result);
- result.GetMatches(matches);
-
- EXPECT_EQ(request.GetRawLine(), "a b");
- EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
- EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
- EXPECT_EQ(request.GetCursorIndex(), arg_index);
-
- EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 2u);
- EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "b");
-}
-
-TEST(CompletionRequest, FakeLastArg) {
- // We insert an empty fake argument into the argument list when the
- // cursor is after a space.
- std::string command = "a bad c ";
- const unsigned cursor_pos = command.size();
- CompletionResult result;
-
- CompletionRequest request(command, cursor_pos, result);
-
- EXPECT_EQ(request.GetRawLine(), command);
- EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
- EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
- EXPECT_EQ(request.GetCursorIndex(), 3U);
-
- EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 4U);
- EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "");
-}
-
-TEST(CompletionRequest, TryCompleteCurrentArgGood) {
- std::string command = "a bad c";
- StringList matches, descriptions;
- CompletionResult result;
-
- CompletionRequest request(command, 3, result);
- request.TryCompleteCurrentArg("boo", "car");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(1U, result.GetResults().size());
- EXPECT_STREQ("boo", matches.GetStringAtIndex(0U));
- EXPECT_EQ(1U, descriptions.GetSize());
- EXPECT_STREQ("car", descriptions.GetStringAtIndex(0U));
-}
-
-TEST(CompletionRequest, TryCompleteCurrentArgBad) {
- std::string command = "a bad c";
- CompletionResult result;
-
- CompletionRequest request(command, 3, result);
- request.TryCompleteCurrentArg("car", "card");
-
- EXPECT_EQ(0U, result.GetResults().size());
-}
-
-TEST(CompletionRequest, TryCompleteCurrentArgMode) {
- std::string command = "a bad c";
- CompletionResult result;
-
- CompletionRequest request(command, 3, result);
- request.TryCompleteCurrentArg<CompletionMode::Partial>("bar", "bard");
-
- EXPECT_EQ(1U, result.GetResults().size());
- EXPECT_EQ(CompletionMode::Partial, result.GetResults()[0].GetMode());
-}
-
-TEST(CompletionRequest, ShiftArguments) {
- std::string command = "a bad c";
- const unsigned cursor_pos = 3;
- const size_t arg_index = 1;
- StringList matches;
- CompletionResult result;
-
- CompletionRequest request(command, cursor_pos, result);
- result.GetMatches(matches);
-
- EXPECT_EQ(request.GetRawLine(), "a b");
- EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
- EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
- EXPECT_EQ(request.GetCursorIndex(), arg_index);
-
- EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 2u);
- EXPECT_STREQ(request.GetParsedLine().GetArgumentAtIndex(1), "b");
-
- // Shift away the 'a' argument.
- request.ShiftArguments();
-
- // The raw line/cursor stays identical.
- EXPECT_EQ(request.GetRawLine(), "a b");
- EXPECT_EQ(request.GetRawLineWithUnusedSuffix(), command);
- EXPECT_EQ(request.GetRawCursorPos(), cursor_pos);
-
- // Partially parsed line and cursor should be updated.
- EXPECT_EQ(request.GetCursorIndex(), arg_index - 1U);
- EXPECT_EQ(request.GetParsedLine().GetArgumentCount(), 1u);
- EXPECT_EQ(request.GetCursorArgumentPrefix().str(), "b");
-}
-
-TEST(CompletionRequest, DuplicateFiltering) {
- std::string command = "a bad c";
- const unsigned cursor_pos = 3;
- StringList matches;
-
- CompletionResult result;
- CompletionRequest request(command, cursor_pos, result);
- result.GetMatches(matches);
-
- EXPECT_EQ(0U, result.GetNumberOfResults());
-
- // Add foo twice
- request.AddCompletion("foo");
- result.GetMatches(matches);
-
- EXPECT_EQ(1U, result.GetNumberOfResults());
- EXPECT_EQ(1U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
-
- request.AddCompletion("foo");
- result.GetMatches(matches);
-
- EXPECT_EQ(1U, result.GetNumberOfResults());
- EXPECT_EQ(1U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
-
- // Add bar twice
- request.AddCompletion("bar");
- result.GetMatches(matches);
-
- EXPECT_EQ(2U, result.GetNumberOfResults());
- EXPECT_EQ(2U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
-
- request.AddCompletion("bar");
- result.GetMatches(matches);
-
- EXPECT_EQ(2U, result.GetNumberOfResults());
- EXPECT_EQ(2U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
-
- // Add foo again.
- request.AddCompletion("foo");
- result.GetMatches(matches);
-
- EXPECT_EQ(2U, result.GetNumberOfResults());
- EXPECT_EQ(2U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
-
- // Add something with an existing prefix
- request.AddCompletion("foobar");
- result.GetMatches(matches);
-
- EXPECT_EQ(3U, result.GetNumberOfResults());
- EXPECT_EQ(3U, matches.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
- EXPECT_STREQ("foobar", matches.GetStringAtIndex(2));
-}
-
-TEST(CompletionRequest, DuplicateFilteringWithComments) {
- std::string command = "a bad c";
- const unsigned cursor_pos = 3;
- StringList matches, descriptions;
-
- CompletionResult result;
- CompletionRequest request(command, cursor_pos, result);
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(0U, result.GetNumberOfResults());
-
- // Add foo twice with same comment
- request.AddCompletion("foo", "comment");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(1U, result.GetNumberOfResults());
- EXPECT_EQ(1U, matches.GetSize());
- EXPECT_EQ(1U, descriptions.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
-
- request.AddCompletion("foo", "comment");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(1U, result.GetNumberOfResults());
- EXPECT_EQ(1U, matches.GetSize());
- EXPECT_EQ(1U, descriptions.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
-
- // Add bar twice with different comments
- request.AddCompletion("bar", "comment");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(2U, result.GetNumberOfResults());
- EXPECT_EQ(2U, matches.GetSize());
- EXPECT_EQ(2U, descriptions.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
-
- request.AddCompletion("bar", "another comment");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(3U, result.GetNumberOfResults());
- EXPECT_EQ(3U, matches.GetSize());
- EXPECT_EQ(3U, descriptions.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(1));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(2));
- EXPECT_STREQ("another comment", descriptions.GetStringAtIndex(2));
-
- // Add foo again with no comment
- request.AddCompletion("foo");
- result.GetMatches(matches);
- result.GetDescriptions(descriptions);
-
- EXPECT_EQ(4U, result.GetNumberOfResults());
- EXPECT_EQ(4U, matches.GetSize());
- EXPECT_EQ(4U, descriptions.GetSize());
- EXPECT_STREQ("foo", matches.GetStringAtIndex(0));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(0));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(1));
- EXPECT_STREQ("comment", descriptions.GetStringAtIndex(1));
- EXPECT_STREQ("bar", matches.GetStringAtIndex(2));
- EXPECT_STREQ("another comment", descriptions.GetStringAtIndex(2));
- EXPECT_STREQ("foo", matches.GetStringAtIndex(3));
- EXPECT_STREQ("", descriptions.GetStringAtIndex(3));
-}
-
-TEST(CompletionRequest, TestCompletionOwnership) {
- std::string command = "a bad c";
- const unsigned cursor_pos = 3;
- StringList matches;
-
- CompletionResult result;
- CompletionRequest request(command, cursor_pos, result);
-
- std::string Temporary = "bar";
- request.AddCompletion(Temporary);
- // Manipulate our completion. The request should have taken a copy, so that
- // shouldn't influence anything.
- Temporary[0] = 'f';
-
- result.GetMatches(matches);
- EXPECT_EQ(1U, result.GetNumberOfResults());
- EXPECT_STREQ("bar", matches.GetStringAtIndex(0));
-}
+++ /dev/null
-//===-- ConstStringTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/ConstString.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/YAMLParser.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(ConstStringTest, format_provider) {
- EXPECT_EQ("foo", llvm::formatv("{0}", ConstString("foo")).str());
-}
-
-TEST(ConstStringTest, MangledCounterpart) {
- ConstString uvw("uvw");
- ConstString counterpart;
- EXPECT_FALSE(uvw.GetMangledCounterpart(counterpart));
- EXPECT_EQ("", counterpart.GetStringRef());
-
- ConstString xyz;
- xyz.SetStringWithMangledCounterpart("xyz", uvw);
- EXPECT_EQ("xyz", xyz.GetStringRef());
-
- EXPECT_TRUE(xyz.GetMangledCounterpart(counterpart));
- EXPECT_EQ("uvw", counterpart.GetStringRef());
-
- EXPECT_TRUE(uvw.GetMangledCounterpart(counterpart));
- EXPECT_EQ("xyz", counterpart.GetStringRef());
-}
-
-TEST(ConstStringTest, UpdateMangledCounterpart) {
- { // Add counterpart
- ConstString some1;
- some1.SetStringWithMangledCounterpart("some", ConstString(""));
- }
- { // Overwrite empty string
- ConstString some2;
- some2.SetStringWithMangledCounterpart("some", ConstString("one"));
- }
- { // Overwrite with identical value
- ConstString some2;
- some2.SetStringWithMangledCounterpart("some", ConstString("one"));
- }
- { // Check counterpart is set
- ConstString counterpart;
- EXPECT_TRUE(ConstString("some").GetMangledCounterpart(counterpart));
- EXPECT_EQ("one", counterpart.GetStringRef());
- }
-}
-
-TEST(ConstStringTest, FromMidOfBufferStringRef) {
- // StringRef's into bigger buffer: no null termination
- const char *buffer = "abcdefghi";
- llvm::StringRef foo_ref(buffer, 3);
- llvm::StringRef bar_ref(buffer + 3, 3);
-
- ConstString foo(foo_ref);
-
- ConstString bar;
- bar.SetStringWithMangledCounterpart(bar_ref, foo);
- EXPECT_EQ("def", bar.GetStringRef());
-
- ConstString counterpart;
- EXPECT_TRUE(bar.GetMangledCounterpart(counterpart));
- EXPECT_EQ("abc", counterpart.GetStringRef());
-
- EXPECT_TRUE(foo.GetMangledCounterpart(counterpart));
- EXPECT_EQ("def", counterpart.GetStringRef());
-}
-
-TEST(ConstStringTest, NullAndEmptyStates) {
- ConstString foo("foo");
- EXPECT_FALSE(!foo);
- EXPECT_FALSE(foo.IsEmpty());
- EXPECT_FALSE(foo.IsNull());
-
- ConstString empty("");
- EXPECT_TRUE(!empty);
- EXPECT_TRUE(empty.IsEmpty());
- EXPECT_FALSE(empty.IsNull());
-
- ConstString null;
- EXPECT_TRUE(!null);
- EXPECT_TRUE(null.IsEmpty());
- EXPECT_TRUE(null.IsNull());
-}
-
-TEST(ConstStringTest, CompareConstString) {
- ConstString foo("foo");
- ConstString foo2("foo");
- ConstString bar("bar");
-
- EXPECT_TRUE(foo == foo2);
- EXPECT_TRUE(foo2 == foo);
- EXPECT_TRUE(foo == ConstString("foo"));
-
- EXPECT_FALSE(foo == bar);
- EXPECT_FALSE(foo2 == bar);
- EXPECT_FALSE(foo == ConstString("bar"));
- EXPECT_FALSE(foo == ConstString("different"));
- EXPECT_FALSE(foo == ConstString(""));
- EXPECT_FALSE(foo == ConstString());
-
- ConstString empty("");
- EXPECT_FALSE(empty == ConstString("bar"));
- EXPECT_FALSE(empty == ConstString());
- EXPECT_TRUE(empty == ConstString(""));
-
- ConstString null;
- EXPECT_FALSE(null == ConstString("bar"));
- EXPECT_TRUE(null == ConstString());
- EXPECT_FALSE(null == ConstString(""));
-}
-
-TEST(ConstStringTest, CompareStringRef) {
- ConstString foo("foo");
-
- EXPECT_TRUE(foo == "foo");
- EXPECT_TRUE(foo != "");
- EXPECT_FALSE(foo == static_cast<const char *>(nullptr));
- EXPECT_TRUE(foo != "bar");
-
- ConstString empty("");
- EXPECT_FALSE(empty == "foo");
- EXPECT_FALSE(empty != "");
- EXPECT_FALSE(empty == static_cast<const char *>(nullptr));
- EXPECT_TRUE(empty != "bar");
-
- ConstString null;
- EXPECT_FALSE(null == "foo");
- EXPECT_TRUE(null != "");
- EXPECT_TRUE(null == static_cast<const char *>(nullptr));
- EXPECT_TRUE(null != "bar");
-}
-
-TEST(ConstStringTest, YAML) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- std::vector<ConstString> strings = {ConstString("foo"), ConstString("bar"),
- ConstString("")};
- llvm::yaml::Output yout(os);
- yout << strings;
- os.flush();
-
- // Deserialize.
- std::vector<ConstString> deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- EXPECT_EQ(strings, deserialized);
-}
+++ /dev/null
-//===-- DataExtractorTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/DataExtractor.h"
-
-using namespace lldb_private;
-
-TEST(DataExtractorTest, GetBitfield) {
- uint8_t buffer[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- offset = 0;
- ASSERT_EQ(buffer[1], LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(buffer[1], BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(static_cast<uint64_t>(0xEFCDAB8967452301),
- LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 64, 0));
- offset = 0;
- ASSERT_EQ(static_cast<uint64_t>(0x0123456789ABCDEF),
- BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 64, 0));
- offset = 0;
- ASSERT_EQ(static_cast<uint64_t>(0x01234567),
- BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 32, 0));
- offset = 0;
- ASSERT_EQ(static_cast<uint64_t>(0x012345678),
- BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 36, 0));
-
- offset = 0;
- ASSERT_EQ(int8_t(buffer[1]),
- LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(int8_t(buffer[1]),
- BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
- offset = 0;
- ASSERT_EQ(static_cast<int64_t>(0xEFCDAB8967452301),
- LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 64, 0));
- offset = 0;
- ASSERT_EQ(static_cast<int64_t>(0x0123456789ABCDEF),
- BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 64, 0));
-}
-
-TEST(DataExtractorTest, PeekData) {
- uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- EXPECT_EQ(buffer + 0, E.PeekData(0, 0));
- EXPECT_EQ(buffer + 0, E.PeekData(0, 4));
- EXPECT_EQ(nullptr, E.PeekData(0, 5));
-
- EXPECT_EQ(buffer + 2, E.PeekData(2, 0));
- EXPECT_EQ(buffer + 2, E.PeekData(2, 2));
- EXPECT_EQ(nullptr, E.PeekData(2, 3));
-
- EXPECT_EQ(buffer + 4, E.PeekData(4, 0));
- EXPECT_EQ(nullptr, E.PeekData(4, 1));
-}
-
-TEST(DataExtractorTest, GetCStr) {
- uint8_t buffer[] = {'X', 'f', 'o', 'o', '\0'};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- lldb::offset_t offset = 1;
- EXPECT_STREQ("foo", E.GetCStr(&offset));
- EXPECT_EQ(5U, offset);
-}
-
-TEST(DataExtractorTest, GetCStrEmpty) {
- uint8_t buffer[] = {'X', '\0'};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- lldb::offset_t offset = 1;
- EXPECT_STREQ("", E.GetCStr(&offset));
- EXPECT_EQ(2U, offset);
-}
-
-TEST(DataExtractorTest, GetCStrUnterminated) {
- uint8_t buffer[] = {'X', 'f', 'o', 'o'};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- lldb::offset_t offset = 1;
- EXPECT_EQ(nullptr, E.GetCStr(&offset));
- EXPECT_EQ(1U, offset);
-}
-
-TEST(DataExtractorTest, GetCStrAtEnd) {
- uint8_t buffer[] = {'X'};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- lldb::offset_t offset = 1;
- EXPECT_EQ(nullptr, E.GetCStr(&offset));
- EXPECT_EQ(1U, offset);
-}
-
-TEST(DataExtractorTest, GetCStrAtNullOffset) {
- uint8_t buffer[] = {'f', 'o', 'o', '\0'};
- DataExtractor E(buffer, sizeof buffer, lldb::eByteOrderLittle, 4);
-
- lldb::offset_t offset = 0;
- EXPECT_STREQ("foo", E.GetCStr(&offset));
- EXPECT_EQ(4U, offset);
-}
-
-TEST(DataExtractorTest, UncommonAddressSize) {
- uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
- DataExtractor E2(buffer, sizeof buffer, lldb::eByteOrderLittle, 2);
- DataExtractor E5(buffer, sizeof buffer, lldb::eByteOrderLittle, 5);
- DataExtractor E7(buffer, sizeof buffer, lldb::eByteOrderLittle, 7);
-
- lldb::offset_t offset;
-
- // Test 2-byte addresses (for AVR).
- offset = 0;
- EXPECT_EQ(0x0201U, E2.GetMaxU64(&offset, 2));
- EXPECT_EQ(2U, offset);
- offset = 0;
- EXPECT_EQ(0x0201U, E2.GetAddress(&offset));
- EXPECT_EQ(2U, offset);
-
- // Test 5-byte addresses.
- offset = 0;
- EXPECT_EQ(0x030201U, E5.GetMaxU64(&offset, 3));
- EXPECT_EQ(3U, offset);
- offset = 3;
- EXPECT_EQ(0x0807060504U, E5.GetAddress(&offset));
- EXPECT_EQ(8U, offset);
-
- // Test 7-byte addresses.
- offset = 0;
- EXPECT_EQ(0x0504030201U, E7.GetMaxU64(&offset, 5));
- EXPECT_EQ(5U, offset);
- offset = 0;
- EXPECT_EQ(0x07060504030201U, E7.GetAddress(&offset));
- EXPECT_EQ(7U, offset);
-}
-
-TEST(DataExtractorTest, GetMaxU64) {
- uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- // Check with the minimum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x01U, LE.GetMaxU64(&offset, 1));
- EXPECT_EQ(1U, offset);
- offset = 0;
- EXPECT_EQ(0x01U, BE.GetMaxU64(&offset, 1));
- EXPECT_EQ(1U, offset);
-
- // Check with a non-zero offset.
- offset = 1;
- EXPECT_EQ(0x0302U, LE.GetMaxU64(&offset, 2));
- EXPECT_EQ(3U, offset);
- offset = 1;
- EXPECT_EQ(0x0203U, BE.GetMaxU64(&offset, 2));
- EXPECT_EQ(3U, offset);
-
- // Check with the byte size not being a multiple of 2.
- offset = 0;
- EXPECT_EQ(0x07060504030201U, LE.GetMaxU64(&offset, 7));
- EXPECT_EQ(7U, offset);
- offset = 0;
- EXPECT_EQ(0x01020304050607U, BE.GetMaxU64(&offset, 7));
- EXPECT_EQ(7U, offset);
-
- // Check with the maximum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64(&offset, 8));
- EXPECT_EQ(8U, offset);
- offset = 0;
- EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64(&offset, 8));
- EXPECT_EQ(8U, offset);
-}
-
-TEST(DataExtractorTest, GetMaxS64) {
- uint8_t buffer[] = {0x01, 0x02, 0x83, 0x04, 0x05, 0x06, 0x07, 0x08};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- // Check with the minimum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x01, LE.GetMaxS64(&offset, 1));
- EXPECT_EQ(1U, offset);
- offset = 0;
- EXPECT_EQ(0x01, BE.GetMaxS64(&offset, 1));
- EXPECT_EQ(1U, offset);
-
- // Check that sign extension works correctly.
- offset = 0;
- int64_t value = LE.GetMaxS64(&offset, 3);
- EXPECT_EQ(0xffffffffff830201U, *reinterpret_cast<uint64_t *>(&value));
- EXPECT_EQ(3U, offset);
- offset = 2;
- value = BE.GetMaxS64(&offset, 3);
- EXPECT_EQ(0xffffffffff830405U, *reinterpret_cast<uint64_t *>(&value));
- EXPECT_EQ(5U, offset);
-
- // Check with the maximum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x0807060504830201, LE.GetMaxS64(&offset, 8));
- EXPECT_EQ(8U, offset);
- offset = 0;
- EXPECT_EQ(0x0102830405060708, BE.GetMaxS64(&offset, 8));
- EXPECT_EQ(8U, offset);
-}
-
-TEST(DataExtractorTest, GetMaxU64_unchecked) {
- uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- // Check with the minimum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x01U, LE.GetMaxU64_unchecked(&offset, 1));
- EXPECT_EQ(1U, offset);
- offset = 0;
- EXPECT_EQ(0x01U, BE.GetMaxU64_unchecked(&offset, 1));
- EXPECT_EQ(1U, offset);
-
- // Check with a non-zero offset.
- offset = 1;
- EXPECT_EQ(0x0302U, LE.GetMaxU64_unchecked(&offset, 2));
- EXPECT_EQ(3U, offset);
- offset = 1;
- EXPECT_EQ(0x0203U, BE.GetMaxU64_unchecked(&offset, 2));
- EXPECT_EQ(3U, offset);
-
- // Check with the byte size not being a multiple of 2.
- offset = 0;
- EXPECT_EQ(0x07060504030201U, LE.GetMaxU64_unchecked(&offset, 7));
- EXPECT_EQ(7U, offset);
- offset = 0;
- EXPECT_EQ(0x01020304050607U, BE.GetMaxU64_unchecked(&offset, 7));
- EXPECT_EQ(7U, offset);
-
- // Check with the maximum allowed byte size.
- offset = 0;
- EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64_unchecked(&offset, 8));
- EXPECT_EQ(8U, offset);
- offset = 0;
- EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64_unchecked(&offset, 8));
- EXPECT_EQ(8U, offset);
-}
-
-TEST(DataExtractorTest, GetSLEB128_bit63) {
- uint8_t buffer[] = {0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x7f};
-
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- int64_t expected =
- 0b1111111100000001111111000000011111110000000111111100000001111111;
- offset = 0;
- EXPECT_EQ(expected, LE.GetSLEB128(&offset));
- EXPECT_EQ(9U, offset);
- offset = 0;
- EXPECT_EQ(expected, BE.GetSLEB128(&offset));
- EXPECT_EQ(9U, offset);
-}
-
-TEST(DataExtractorTest, GetULEB128_bit63) {
- uint8_t buffer[] = {0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0xff, 0x80, 0x7f};
-
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
-
- lldb::offset_t offset;
-
- uint64_t expected =
- 0b0111111100000001111111000000011111110000000111111100000001111111;
- offset = 0;
- EXPECT_EQ(expected, LE.GetULEB128(&offset));
- EXPECT_EQ(9U, offset);
- offset = 0;
- EXPECT_EQ(expected, BE.GetULEB128(&offset));
- EXPECT_EQ(9U, offset);
-}
-
-TEST(DataExtractorTest, GetFloat) {
- float expected = 4.0f;
- lldb::offset_t offset;
-
- {
- uint8_t buffer[] = {0x00, 0x00, 0x80, 0x40};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
-
- offset = 0;
- EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset));
- EXPECT_EQ(4U, offset);
- }
-
- {
- uint8_t buffer[] = {0x40, 0x80, 0x00, 0x00};
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig,
- sizeof(void *));
- offset = 0;
- EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset));
- EXPECT_EQ(4U, offset);
- }
-}
-
-TEST(DataExtractorTest, GetFloatUnaligned) {
- float expected = 4.0f;
- lldb::offset_t offset;
-
- {
- uint8_t buffer[] = {0x00, 0x00, 0x00, 0x80, 0x40};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
-
- offset = 1;
- EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset));
- EXPECT_EQ(5U, offset);
- }
-
- {
- uint8_t buffer[] = {0x00, 0x40, 0x80, 0x00, 0x00};
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig,
- sizeof(void *));
- offset = 1;
- EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset));
- EXPECT_EQ(5U, offset);
- }
-}
-
-TEST(DataExtractorTest, GetDouble) {
- if (sizeof(double) != 8)
- return;
-
- double expected = 4.0f;
- lldb::offset_t offset;
-
- {
- uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
-
- offset = 0;
- EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset));
- EXPECT_EQ(8U, offset);
- }
-
- {
- uint8_t buffer[] = {0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig,
- sizeof(void *));
- offset = 0;
- EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset));
- EXPECT_EQ(8U, offset);
- }
-}
-
-TEST(DataExtractorTest, GetDoubleUnaligned) {
- if (sizeof(double) != 8)
- return;
-
- float expected = 4.0f;
- lldb::offset_t offset;
-
- {
- uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40};
- DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
- sizeof(void *));
-
- offset = 1;
- EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset));
- EXPECT_EQ(9U, offset);
- }
-
- {
- uint8_t buffer[] = {0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig,
- sizeof(void *));
- offset = 1;
- EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset));
- EXPECT_EQ(9U, offset);
- }
-}
+++ /dev/null
-//===-- EnvironmentTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Environment.h"
-
-using namespace lldb_private;
-
-TEST(EnvironmentTest, EnvpConstruction) {
- const char **Envp1 = nullptr;
- EXPECT_EQ(0u, Environment(Envp1).size());
-
- const char *Envp2[] = {"FOO=BAR", nullptr};
- EXPECT_EQ("BAR", Environment(Envp2).lookup("FOO"));
-
- const char *Envp3[] = {"FOO=BAR", "FOO=BAZ", nullptr};
- EXPECT_EQ("BAR", Environment(Envp3).lookup("FOO"));
-
- const char *Envp4[] = {"FOO=", "BAR", nullptr};
- Environment Env4(Envp4);
- ASSERT_EQ(2u, Env4.size());
- EXPECT_EQ("", Environment(Envp4).find("FOO")->second);
- EXPECT_EQ("", Environment(Envp4).find("BAR")->second);
-
- const char *Envp5[] = {"FOO=BAR=BAZ", nullptr};
- EXPECT_EQ("BAR=BAZ", Environment(Envp5).lookup("FOO"));
-}
-
-TEST(EnvironmentTest, EnvpConversion) {
- std::string FOO_EQ_BAR("FOO=BAR");
- std::string BAR_EQ_BAZ("BAR=BAZ");
-
- Environment Env;
- Env.insert(FOO_EQ_BAR);
- Env.insert(BAR_EQ_BAZ);
- Environment::Envp Envp = Env.getEnvp();
- const char *const *Envp_ = Envp;
-
- EXPECT_TRUE(FOO_EQ_BAR == Envp_[0] || FOO_EQ_BAR == Envp_[1]);
- EXPECT_TRUE(BAR_EQ_BAZ == Envp_[0] || BAR_EQ_BAZ == Envp_[1]);
- EXPECT_EQ(nullptr, Envp_[2]);
-}
+++ /dev/null
-//===-- EventTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Event.h"
-#include "lldb/Utility/StreamString.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-static std::string to_string(const EventDataBytes &E) {
- StreamString S;
- E.Dump(&S);
- return std::string(S.GetString());
-}
-
-TEST(EventTest, DumpEventDataBytes) {
- EXPECT_EQ(R"("foo")", to_string(EventDataBytes("foo")));
- EXPECT_EQ("01 02 03", to_string(EventDataBytes("\x01\x02\x03")));
-}
+++ /dev/null
-//===-- FileSpecTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/FileSpec.h"
-
-using namespace lldb_private;
-
-static FileSpec PosixSpec(llvm::StringRef path) {
- return FileSpec(path, FileSpec::Style::posix);
-}
-
-static FileSpec WindowsSpec(llvm::StringRef path) {
- return FileSpec(path, FileSpec::Style::windows);
-}
-
-TEST(FileSpecTest, FileAndDirectoryComponents) {
- FileSpec fs_posix("/foo/bar", FileSpec::Style::posix);
- EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
- EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
-
- FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
- EXPECT_STREQ("F:\\bar", fs_windows.GetCString());
- // EXPECT_STREQ("F:\\", fs_windows.GetDirectory().GetCString()); // It returns
- // "F:/"
- EXPECT_STREQ("bar", fs_windows.GetFilename().GetCString());
-
- FileSpec fs_posix_root("/", FileSpec::Style::posix);
- EXPECT_STREQ("/", fs_posix_root.GetCString());
- EXPECT_EQ(nullptr, fs_posix_root.GetDirectory().GetCString());
- EXPECT_STREQ("/", fs_posix_root.GetFilename().GetCString());
-
- FileSpec fs_net_drive("//net", FileSpec::Style::posix);
- EXPECT_STREQ("//net", fs_net_drive.GetCString());
- EXPECT_EQ(nullptr, fs_net_drive.GetDirectory().GetCString());
- EXPECT_STREQ("//net", fs_net_drive.GetFilename().GetCString());
-
- FileSpec fs_net_root("//net/", FileSpec::Style::posix);
- EXPECT_STREQ("//net/", fs_net_root.GetCString());
- EXPECT_STREQ("//net", fs_net_root.GetDirectory().GetCString());
- EXPECT_STREQ("/", fs_net_root.GetFilename().GetCString());
-
- FileSpec fs_windows_drive("F:", FileSpec::Style::windows);
- EXPECT_STREQ("F:", fs_windows_drive.GetCString());
- EXPECT_EQ(nullptr, fs_windows_drive.GetDirectory().GetCString());
- EXPECT_STREQ("F:", fs_windows_drive.GetFilename().GetCString());
-
- FileSpec fs_windows_root("F:\\", FileSpec::Style::windows);
- EXPECT_STREQ("F:\\", fs_windows_root.GetCString());
- EXPECT_STREQ("F:", fs_windows_root.GetDirectory().GetCString());
- // EXPECT_STREQ("\\", fs_windows_root.GetFilename().GetCString()); // It
- // returns "/"
-
- FileSpec fs_posix_long("/foo/bar/baz", FileSpec::Style::posix);
- EXPECT_STREQ("/foo/bar/baz", fs_posix_long.GetCString());
- EXPECT_STREQ("/foo/bar", fs_posix_long.GetDirectory().GetCString());
- EXPECT_STREQ("baz", fs_posix_long.GetFilename().GetCString());
-
- FileSpec fs_windows_long("F:\\bar\\baz", FileSpec::Style::windows);
- EXPECT_STREQ("F:\\bar\\baz", fs_windows_long.GetCString());
- // EXPECT_STREQ("F:\\bar", fs_windows_long.GetDirectory().GetCString()); // It
- // returns "F:/bar"
- EXPECT_STREQ("baz", fs_windows_long.GetFilename().GetCString());
-
- FileSpec fs_posix_trailing_slash("/foo/bar/", FileSpec::Style::posix);
- EXPECT_STREQ("/foo/bar", fs_posix_trailing_slash.GetCString());
- EXPECT_STREQ("/foo", fs_posix_trailing_slash.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix_trailing_slash.GetFilename().GetCString());
-
- FileSpec fs_windows_trailing_slash("F:\\bar\\", FileSpec::Style::windows);
- EXPECT_STREQ("F:\\bar", fs_windows_trailing_slash.GetCString());
- EXPECT_STREQ("bar", fs_windows_trailing_slash.GetFilename().GetCString());
-}
-
-TEST(FileSpecTest, AppendPathComponent) {
- FileSpec fs_posix("/foo", FileSpec::Style::posix);
- fs_posix.AppendPathComponent("bar");
- EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
- EXPECT_STREQ("/foo", fs_posix.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix.GetFilename().GetCString());
-
- FileSpec fs_posix_2("/foo", FileSpec::Style::posix);
- fs_posix_2.AppendPathComponent("//bar/baz");
- EXPECT_STREQ("/foo/bar/baz", fs_posix_2.GetCString());
- EXPECT_STREQ("/foo/bar", fs_posix_2.GetDirectory().GetCString());
- EXPECT_STREQ("baz", fs_posix_2.GetFilename().GetCString());
-
- FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
- fs_windows.AppendPathComponent("baz");
- EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
- // EXPECT_STREQ("F:\\bar", fs_windows.GetDirectory().GetCString()); // It
- // returns "F:/bar"
- EXPECT_STREQ("baz", fs_windows.GetFilename().GetCString());
-
- FileSpec fs_posix_root("/", FileSpec::Style::posix);
- fs_posix_root.AppendPathComponent("bar");
- EXPECT_STREQ("/bar", fs_posix_root.GetCString());
- EXPECT_STREQ("/", fs_posix_root.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs_posix_root.GetFilename().GetCString());
-
- FileSpec fs_windows_root("F:\\", FileSpec::Style::windows);
- fs_windows_root.AppendPathComponent("bar");
- EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
- // EXPECT_STREQ("F:\\", fs_windows_root.GetDirectory().GetCString()); // It
- // returns "F:/"
- EXPECT_STREQ("bar", fs_windows_root.GetFilename().GetCString());
-}
-
-TEST(FileSpecTest, CopyByAppendingPathComponent) {
- FileSpec fs = PosixSpec("/foo").CopyByAppendingPathComponent("bar");
- EXPECT_STREQ("/foo/bar", fs.GetCString());
- EXPECT_STREQ("/foo", fs.GetDirectory().GetCString());
- EXPECT_STREQ("bar", fs.GetFilename().GetCString());
-}
-
-TEST(FileSpecTest, PrependPathComponent) {
- FileSpec fs_posix("foo", FileSpec::Style::posix);
- fs_posix.PrependPathComponent("/bar");
- EXPECT_STREQ("/bar/foo", fs_posix.GetCString());
-
- FileSpec fs_posix_2("foo/bar", FileSpec::Style::posix);
- fs_posix_2.PrependPathComponent("/baz");
- EXPECT_STREQ("/baz/foo/bar", fs_posix_2.GetCString());
-
- FileSpec fs_windows("baz", FileSpec::Style::windows);
- fs_windows.PrependPathComponent("F:\\bar");
- EXPECT_STREQ("F:\\bar\\baz", fs_windows.GetCString());
-
- FileSpec fs_posix_root("bar", FileSpec::Style::posix);
- fs_posix_root.PrependPathComponent("/");
- EXPECT_STREQ("/bar", fs_posix_root.GetCString());
-
- FileSpec fs_windows_root("bar", FileSpec::Style::windows);
- fs_windows_root.PrependPathComponent("F:\\");
- EXPECT_STREQ("F:\\bar", fs_windows_root.GetCString());
-}
-
-TEST(FileSpecTest, EqualSeparator) {
- EXPECT_EQ(WindowsSpec("C:\\foo\\bar"), WindowsSpec("C:/foo/bar"));
-}
-
-TEST(FileSpecTest, EqualDotsWindows) {
- std::pair<const char *, const char *> tests[] = {
- {R"(C:\foo\bar\baz)", R"(C:\foo\foo\..\bar\baz)"},
- {R"(C:\bar\baz)", R"(C:\foo\..\bar\baz)"},
- {R"(C:\bar\baz)", R"(C:/foo/../bar/baz)"},
- {R"(C:/bar/baz)", R"(C:\foo\..\bar\baz)"},
- {R"(C:\bar)", R"(C:\foo\..\bar)"},
- {R"(C:\foo\bar)", R"(C:\foo\.\bar)"},
- {R"(C:\foo\bar)", R"(C:\foo\bar\.)"},
- };
-
- for (const auto &test : tests) {
- SCOPED_TRACE(llvm::Twine(test.first) + " <=> " + test.second);
- EXPECT_EQ(WindowsSpec(test.first), WindowsSpec(test.second));
- }
-}
-
-TEST(FileSpecTest, EqualDotsPosix) {
- std::pair<const char *, const char *> tests[] = {
- {R"(/foo/bar/baz)", R"(/foo/foo/../bar/baz)"},
- {R"(/bar/baz)", R"(/foo/../bar/baz)"},
- {R"(/bar)", R"(/foo/../bar)"},
- {R"(/foo/bar)", R"(/foo/./bar)"},
- {R"(/foo/bar)", R"(/foo/bar/.)"},
- };
-
- for (const auto &test : tests) {
- SCOPED_TRACE(llvm::Twine(test.first) + " <=> " + test.second);
- EXPECT_EQ(PosixSpec(test.first), PosixSpec(test.second));
- }
-}
-
-TEST(FileSpecTest, EqualDotsPosixRoot) {
- std::pair<const char *, const char *> tests[] = {
- {R"(/)", R"(/..)"},
- {R"(/)", R"(/.)"},
- {R"(/)", R"(/foo/..)"},
- };
-
- for (const auto &test : tests) {
- SCOPED_TRACE(llvm::Twine(test.first) + " <=> " + test.second);
- EXPECT_EQ(PosixSpec(test.first), PosixSpec(test.second));
- }
-}
-
-TEST(FileSpecTest, GuessPathStyle) {
- EXPECT_EQ(FileSpec::Style::posix, FileSpec::GuessPathStyle("/foo/bar.txt"));
- EXPECT_EQ(FileSpec::Style::posix, FileSpec::GuessPathStyle("//net/bar.txt"));
- EXPECT_EQ(FileSpec::Style::windows,
- FileSpec::GuessPathStyle(R"(C:\foo.txt)"));
- EXPECT_EQ(FileSpec::Style::windows,
- FileSpec::GuessPathStyle(R"(\\net\foo.txt)"));
- EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo.txt"));
- EXPECT_EQ(llvm::None, FileSpec::GuessPathStyle("foo/bar.txt"));
-}
-
-TEST(FileSpecTest, GetPath) {
- std::pair<const char *, const char *> posix_tests[] = {
- {"/foo/.././bar", "/bar"},
- {"/foo/./../bar", "/bar"},
- {"/foo/../bar", "/bar"},
- {"/foo/./bar", "/foo/bar"},
- {"/foo/..", "/"},
- {"/foo/.", "/foo"},
- {"/foo//bar", "/foo/bar"},
- {"/foo//bar/baz", "/foo/bar/baz"},
- {"/foo//bar/./baz", "/foo/bar/baz"},
- {"/./foo", "/foo"},
- {"/", "/"},
- {"//", "/"},
- {"//net", "//net"},
- {"/..", "/"},
- {"/.", "/"},
- {"..", ".."},
- {".", "."},
- {"../..", "../.."},
- {"foo/..", "."},
- {"foo/../bar", "bar"},
- {"../foo/..", ".."},
- {"./foo", "foo"},
- {"././foo", "foo"},
- {"../foo", "../foo"},
- {"../../foo", "../../foo"},
- };
- for (auto test : posix_tests) {
- SCOPED_TRACE(llvm::Twine("test.first = ") + test.first);
- EXPECT_EQ(test.second, PosixSpec(test.first).GetPath());
- }
-
- std::pair<const char *, const char *> windows_tests[] = {
- {R"(c:\bar\..\bar)", R"(c:\bar)"},
- {R"(c:\bar\.\bar)", R"(c:\bar\bar)"},
- {R"(c:\bar\..)", R"(c:\)"},
- {R"(c:\bar\.)", R"(c:\bar)"},
- {R"(c:\.\bar)", R"(c:\bar)"},
- {R"(\)", R"(\)"},
- {R"(\\)", R"(\)"},
- {R"(\\net)", R"(\\net)"},
- {R"(c:\..)", R"(c:\)"},
- {R"(c:\.)", R"(c:\)"},
- {R"(\..)", R"(\)"},
- // {R"(c:..)", R"(c:..)"},
- {R"(..)", R"(..)"},
- {R"(.)", R"(.)"},
- {R"(c:..\..)", R"(c:)"},
- {R"(..\..)", R"(..\..)"},
- {R"(foo\..)", R"(.)"},
- {R"(foo\..\bar)", R"(bar)"},
- {R"(..\foo\..)", R"(..)"},
- {R"(.\foo)", R"(foo)"},
- {R"(.\.\foo)", R"(foo)"},
- {R"(..\foo)", R"(..\foo)"},
- {R"(..\..\foo)", R"(..\..\foo)"},
- };
- for (auto test : windows_tests) {
- SCOPED_TRACE(llvm::Twine("test.first = ") + test.first);
- EXPECT_EQ(test.second, WindowsSpec(test.first).GetPath());
- }
-}
-
-TEST(FileSpecTest, FormatFileSpec) {
- auto win = FileSpec::Style::windows;
-
- FileSpec F;
- EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
- EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
- EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
-
- F = FileSpec("C:\\foo\\bar.txt", win);
- EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
- EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
- EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
-
- F = FileSpec("foo\\bar.txt", win);
- EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
- EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
- EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
-
- F = FileSpec("foo", win);
- EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
- EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
- EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
-}
-
-TEST(FileSpecTest, IsRelative) {
- llvm::StringRef not_relative[] = {
- "/",
- "/a",
- "/a/",
- "/a/b",
- "/a/b/",
- "//",
- "//a/",
- "//a/b",
- "//a/b/",
- "~",
- "~/",
- "~/a",
- "~/a/",
- "~/a/b",
- "~/a/b/",
- "/foo/.",
- "/foo/..",
- "/foo/../",
- "/foo/../.",
- };
- for (const auto &path: not_relative) {
- SCOPED_TRACE(path);
- EXPECT_FALSE(PosixSpec(path).IsRelative());
- }
- llvm::StringRef is_relative[] = {
- ".",
- "./",
- ".///",
- "a",
- "./a",
- "./a/",
- "./a/",
- "./a/b",
- "./a/b/",
- "../foo",
- "foo/bar.c",
- "./foo/bar.c"
- };
- for (const auto &path: is_relative) {
- SCOPED_TRACE(path);
- EXPECT_TRUE(PosixSpec(path).IsRelative());
- }
-}
-
-TEST(FileSpecTest, RemoveLastPathComponent) {
- FileSpec fs_posix("/foo/bar/baz", FileSpec::Style::posix);
- EXPECT_STREQ("/foo/bar/baz", fs_posix.GetCString());
- EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
- EXPECT_STREQ("/foo/bar", fs_posix.GetCString());
- EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
- EXPECT_STREQ("/foo", fs_posix.GetCString());
- EXPECT_TRUE(fs_posix.RemoveLastPathComponent());
- EXPECT_STREQ("/", fs_posix.GetCString());
- EXPECT_FALSE(fs_posix.RemoveLastPathComponent());
- EXPECT_STREQ("/", fs_posix.GetCString());
-
- FileSpec fs_posix_relative("./foo/bar/baz", FileSpec::Style::posix);
- EXPECT_STREQ("foo/bar/baz", fs_posix_relative.GetCString());
- EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent());
- EXPECT_STREQ("foo/bar", fs_posix_relative.GetCString());
- EXPECT_TRUE(fs_posix_relative.RemoveLastPathComponent());
- EXPECT_STREQ("foo", fs_posix_relative.GetCString());
- EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent());
- EXPECT_STREQ("foo", fs_posix_relative.GetCString());
-
- FileSpec fs_posix_relative2("./", FileSpec::Style::posix);
- EXPECT_STREQ(".", fs_posix_relative2.GetCString());
- EXPECT_FALSE(fs_posix_relative2.RemoveLastPathComponent());
- EXPECT_STREQ(".", fs_posix_relative2.GetCString());
- EXPECT_FALSE(fs_posix_relative.RemoveLastPathComponent());
- EXPECT_STREQ(".", fs_posix_relative2.GetCString());
-
- FileSpec fs_windows("C:\\foo\\bar\\baz", FileSpec::Style::windows);
- EXPECT_STREQ("C:\\foo\\bar\\baz", fs_windows.GetCString());
- EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
- EXPECT_STREQ("C:\\foo\\bar", fs_windows.GetCString());
- EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
- EXPECT_STREQ("C:\\foo", fs_windows.GetCString());
- EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
- EXPECT_STREQ("C:\\", fs_windows.GetCString());
- EXPECT_TRUE(fs_windows.RemoveLastPathComponent());
- EXPECT_STREQ("C:", fs_windows.GetCString());
- EXPECT_FALSE(fs_windows.RemoveLastPathComponent());
- EXPECT_STREQ("C:", fs_windows.GetCString());
-}
-
-TEST(FileSpecTest, Equal) {
- auto Eq = [](const char *a, const char *b, bool full) {
- return FileSpec::Equal(PosixSpec(a), PosixSpec(b), full);
- };
- EXPECT_TRUE(Eq("/foo/bar", "/foo/bar", true));
- EXPECT_TRUE(Eq("/foo/bar", "/foo/bar", false));
-
- EXPECT_FALSE(Eq("/foo/bar", "/foo/baz", true));
- EXPECT_FALSE(Eq("/foo/bar", "/foo/baz", false));
-
- EXPECT_FALSE(Eq("/bar/foo", "/baz/foo", true));
- EXPECT_FALSE(Eq("/bar/foo", "/baz/foo", false));
-
- EXPECT_FALSE(Eq("/bar/foo", "foo", true));
- EXPECT_TRUE(Eq("/bar/foo", "foo", false));
-
- EXPECT_FALSE(Eq("foo", "/bar/foo", true));
- EXPECT_TRUE(Eq("foo", "/bar/foo", false));
-}
-
-TEST(FileSpecTest, Match) {
- auto Match = [](const char *pattern, const char *file) {
- return FileSpec::Match(PosixSpec(pattern), PosixSpec(file));
- };
- EXPECT_TRUE(Match("/foo/bar", "/foo/bar"));
- EXPECT_FALSE(Match("/foo/bar", "/oof/bar"));
- EXPECT_FALSE(Match("/foo/bar", "/foo/baz"));
- EXPECT_FALSE(Match("/foo/bar", "bar"));
- EXPECT_FALSE(Match("/foo/bar", ""));
-
- EXPECT_TRUE(Match("bar", "/foo/bar"));
- EXPECT_FALSE(Match("bar", "/foo/baz"));
- EXPECT_TRUE(Match("bar", "bar"));
- EXPECT_FALSE(Match("bar", "baz"));
- EXPECT_FALSE(Match("bar", ""));
-
- EXPECT_TRUE(Match("", "/foo/bar"));
- EXPECT_TRUE(Match("", ""));
-
-}
-
-TEST(FileSpecTest, Yaml) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- FileSpec fs_windows("F:\\bar", FileSpec::Style::windows);
- llvm::yaml::Output yout(os);
- yout << fs_windows;
- os.flush();
-
- // Deserialize.
- FileSpec deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- EXPECT_EQ(deserialized.GetPathStyle(), fs_windows.GetPathStyle());
- EXPECT_EQ(deserialized.GetFilename(), fs_windows.GetFilename());
- EXPECT_EQ(deserialized.GetDirectory(), fs_windows.GetDirectory());
- EXPECT_EQ(deserialized, fs_windows);
-}
-
-TEST(FileSpecTest, OperatorBool) {
- EXPECT_FALSE(FileSpec());
- EXPECT_FALSE(FileSpec(""));
- EXPECT_TRUE(FileSpec("/foo/bar"));
-}
+++ /dev/null
-//===-- FlagsTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Flags.h"
-
-using namespace lldb_private;
-
-enum DummyFlags {
- eFlag0 = 1 << 0,
- eFlag1 = 1 << 1,
- eFlag2 = 1 << 2,
- eAllFlags = (eFlag0 | eFlag1 | eFlag2)
-};
-
-TEST(Flags, GetBitSize) {
- Flags f;
- // Methods like ClearCount depend on this specific value, so we test
- // against it here.
- EXPECT_EQ(32U, f.GetBitSize());
-}
-
-TEST(Flags, Reset) {
- Flags f;
- f.Reset(0x3);
- EXPECT_EQ(0x3U, f.Get());
-}
-
-TEST(Flags, Clear) {
- Flags f;
- f.Reset(0x3);
- EXPECT_EQ(0x3U, f.Get());
-
- f.Clear(0x5);
- EXPECT_EQ(0x2U, f.Get());
-
- f.Clear();
- EXPECT_EQ(0x0U, f.Get());
-}
-
-TEST(Flags, AllSet) {
- Flags f;
-
- EXPECT_FALSE(f.AllSet(eFlag0 | eFlag1));
-
- f.Set(eFlag0);
- EXPECT_FALSE(f.AllSet(eFlag0 | eFlag1));
-
- f.Set(eFlag1);
- EXPECT_TRUE(f.AllSet(eFlag0 | eFlag1));
-
- f.Clear(eFlag1);
- EXPECT_FALSE(f.AllSet(eFlag0 | eFlag1));
-
- f.Clear(eFlag0);
- EXPECT_FALSE(f.AllSet(eFlag0 | eFlag1));
-}
-
-TEST(Flags, AnySet) {
- Flags f;
-
- EXPECT_FALSE(f.AnySet(eFlag0 | eFlag1));
-
- f.Set(eFlag0);
- EXPECT_TRUE(f.AnySet(eFlag0 | eFlag1));
-
- f.Set(eFlag1);
- EXPECT_TRUE(f.AnySet(eFlag0 | eFlag1));
-
- f.Clear(eFlag1);
- EXPECT_TRUE(f.AnySet(eFlag0 | eFlag1));
-
- f.Clear(eFlag0);
- EXPECT_FALSE(f.AnySet(eFlag0 | eFlag1));
-}
-
-TEST(Flags, Test) {
- Flags f;
-
- EXPECT_FALSE(f.Test(eFlag0));
- EXPECT_FALSE(f.Test(eFlag1));
- EXPECT_FALSE(f.Test(eFlag2));
-
- f.Set(eFlag0);
- EXPECT_TRUE(f.Test(eFlag0));
- EXPECT_FALSE(f.Test(eFlag1));
- EXPECT_FALSE(f.Test(eFlag2));
-
- f.Set(eFlag1);
- EXPECT_TRUE(f.Test(eFlag0));
- EXPECT_TRUE(f.Test(eFlag1));
- EXPECT_FALSE(f.Test(eFlag2));
-
- f.Clear(eFlag0);
- EXPECT_FALSE(f.Test(eFlag0));
- EXPECT_TRUE(f.Test(eFlag1));
- EXPECT_FALSE(f.Test(eFlag2));
-
- // FIXME: Should Flags assert on Test(eFlag0 | eFlag1) (more than one bit)?
-}
-
-TEST(Flags, AllClear) {
- Flags f;
-
- EXPECT_TRUE(f.AllClear(eFlag0 | eFlag1));
-
- f.Set(eFlag0);
- EXPECT_FALSE(f.AllClear(eFlag0 | eFlag1));
-
- f.Set(eFlag1);
- f.Clear(eFlag0);
- EXPECT_FALSE(f.AllClear(eFlag0 | eFlag1));
-
- f.Clear(eFlag1);
- EXPECT_TRUE(f.AnyClear(eFlag0 | eFlag1));
-}
-
-TEST(Flags, AnyClear) {
- Flags f;
- EXPECT_TRUE(f.AnyClear(eFlag0 | eFlag1));
-
- f.Set(eFlag0);
- EXPECT_TRUE(f.AnyClear(eFlag0 | eFlag1));
-
- f.Set(eFlag1);
- f.Set(eFlag0);
- EXPECT_FALSE(f.AnyClear(eFlag0 | eFlag1));
-
- f.Clear(eFlag1);
- EXPECT_TRUE(f.AnyClear(eFlag0 | eFlag1));
-
- f.Clear(eFlag0);
- EXPECT_TRUE(f.AnyClear(eFlag0 | eFlag1));
-}
-
-TEST(Flags, IsClear) {
- Flags f;
-
- EXPECT_TRUE(f.IsClear(eFlag0));
- EXPECT_TRUE(f.IsClear(eFlag1));
-
- f.Set(eFlag0);
- EXPECT_FALSE(f.IsClear(eFlag0));
- EXPECT_TRUE(f.IsClear(eFlag1));
-
- f.Set(eFlag1);
- EXPECT_FALSE(f.IsClear(eFlag0));
- EXPECT_FALSE(f.IsClear(eFlag1));
-
- f.Clear(eFlag0);
- EXPECT_TRUE(f.IsClear(eFlag0));
- EXPECT_FALSE(f.IsClear(eFlag1));
-
- f.Clear(eFlag1);
- EXPECT_TRUE(f.IsClear(eFlag0));
- EXPECT_TRUE(f.IsClear(eFlag1));
-}
+++ /dev/null
-//===-- ListenerTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Broadcaster.h"
-#include "lldb/Utility/Listener.h"
-#include <future>
-#include <thread>
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(ListenerTest, GetEventImmediate) {
- EventSP event_sp;
- Broadcaster broadcaster(nullptr, "test-broadcaster");
-
- // Create a listener, sign it up, make sure it receives an event.
- ListenerSP listener_sp = Listener::MakeListener("test-listener");
- const uint32_t event_mask = 1;
- ASSERT_EQ(event_mask,
- listener_sp->StartListeningForEvents(&broadcaster, event_mask));
-
- const std::chrono::seconds timeout(0);
- // Without any events sent, these should return false.
- EXPECT_FALSE(listener_sp->GetEvent(event_sp, timeout));
- EXPECT_FALSE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
- EXPECT_FALSE(
- listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
- EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask, event_sp, timeout));
-
- // Now send events and make sure they get it.
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(
- listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask * 2, event_sp, timeout));
- EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask, event_sp, timeout));
-}
-
-TEST(ListenerTest, GetEventWait) {
- EventSP event_sp;
- Broadcaster broadcaster(nullptr, "test-broadcaster");
-
- // Create a listener, sign it up, make sure it receives an event.
- ListenerSP listener_sp = Listener::MakeListener("test-listener");
- const uint32_t event_mask = 1;
- ASSERT_EQ(event_mask,
- listener_sp->StartListeningForEvents(&broadcaster, event_mask));
-
- // Without any events sent, these should make a short wait and return false.
- std::chrono::microseconds timeout(10);
- EXPECT_FALSE(listener_sp->GetEvent(event_sp, timeout));
- EXPECT_FALSE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
- EXPECT_FALSE(
- listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
- EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask, event_sp, timeout));
-
- // Now send events and make sure they get it.
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(listener_sp->GetEventForBroadcaster(nullptr, event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_TRUE(
- listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, timeout));
-
- broadcaster.BroadcastEvent(event_mask, nullptr);
- EXPECT_FALSE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask * 2, event_sp, timeout));
- EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask, event_sp, timeout));
-
- auto delayed_broadcast = [&] {
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- broadcaster.BroadcastEvent(event_mask, nullptr);
- };
-
- // These should do an infinite wait at return the event our asynchronous
- // broadcast sends.
- std::future<void> async_broadcast =
- std::async(std::launch::async, delayed_broadcast);
- EXPECT_TRUE(listener_sp->GetEvent(event_sp, llvm::None));
- async_broadcast.get();
-
- async_broadcast = std::async(std::launch::async, delayed_broadcast);
- EXPECT_TRUE(
- listener_sp->GetEventForBroadcaster(&broadcaster, event_sp, llvm::None));
- async_broadcast.get();
-
- async_broadcast = std::async(std::launch::async, delayed_broadcast);
- EXPECT_TRUE(listener_sp->GetEventForBroadcasterWithType(
- &broadcaster, event_mask, event_sp, llvm::None));
- async_broadcast.get();
-}
+++ /dev/null
-//===-- LogTest.cpp -------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Threading.h"
-#include <thread>
-
-using namespace lldb;
-using namespace lldb_private;
-
-enum { FOO = 1, BAR = 2 };
-static constexpr Log::Category test_categories[] = {
- {{"foo"}, {"log foo"}, FOO}, {{"bar"}, {"log bar"}, BAR},
-};
-static constexpr uint32_t default_flags = FOO;
-
-static Log::Channel test_channel(test_categories, default_flags);
-
-// Wrap enable, disable and list functions to make them easier to test.
-static bool EnableChannel(std::shared_ptr<llvm::raw_ostream> stream_sp,
- uint32_t log_options, llvm::StringRef channel,
- llvm::ArrayRef<const char *> categories,
- std::string &error) {
- error.clear();
- llvm::raw_string_ostream error_stream(error);
- return Log::EnableLogChannel(stream_sp, log_options, channel, categories,
- error_stream);
-}
-
-static bool DisableChannel(llvm::StringRef channel,
- llvm::ArrayRef<const char *> categories,
- std::string &error) {
- error.clear();
- llvm::raw_string_ostream error_stream(error);
- return Log::DisableLogChannel(channel, categories, error_stream);
-}
-
-static bool ListCategories(llvm::StringRef channel, std::string &result) {
- result.clear();
- llvm::raw_string_ostream result_stream(result);
- return Log::ListChannelCategories(channel, result_stream);
-}
-
-namespace {
-// A test fixture which provides tests with a pre-registered channel.
-struct LogChannelTest : public ::testing::Test {
- void TearDown() override { Log::DisableAllLogChannels(); }
-
- static void SetUpTestCase() {
- Log::Register("chan", test_channel);
- }
-
- static void TearDownTestCase() {
- Log::Unregister("chan");
- llvm::llvm_shutdown();
- }
-};
-
-// A test fixture which provides tests with a pre-registered and pre-enabled
-// channel. Additionally, the messages written to that channel are captured and
-// made available via getMessage().
-class LogChannelEnabledTest : public LogChannelTest {
- llvm::SmallString<0> m_messages;
- std::shared_ptr<llvm::raw_svector_ostream> m_stream_sp =
- std::make_shared<llvm::raw_svector_ostream>(m_messages);
- Log *m_log;
- size_t m_consumed_bytes = 0;
-
-protected:
- std::shared_ptr<llvm::raw_ostream> getStream() { return m_stream_sp; }
- Log *getLog() { return m_log; }
- llvm::StringRef takeOutput();
- llvm::StringRef logAndTakeOutput(llvm::StringRef Message);
-
-public:
- void SetUp() override;
-};
-} // end anonymous namespace
-
-void LogChannelEnabledTest::SetUp() {
- LogChannelTest::SetUp();
-
- std::string error;
- ASSERT_TRUE(EnableChannel(m_stream_sp, 0, "chan", {}, error));
-
- m_log = test_channel.GetLogIfAll(FOO);
- ASSERT_NE(nullptr, m_log);
-}
-
-llvm::StringRef LogChannelEnabledTest::takeOutput() {
- llvm::StringRef result = m_stream_sp->str().drop_front(m_consumed_bytes);
- m_consumed_bytes+= result.size();
- return result;
-}
-
-llvm::StringRef LogChannelEnabledTest::logAndTakeOutput(llvm::StringRef Message) {
- LLDB_LOG(m_log, "{0}", Message);
- return takeOutput();
-}
-
-TEST(LogTest, LLDB_LOG_nullptr) {
- Log *log = nullptr;
- LLDB_LOG(log, "{0}", 0); // Shouldn't crash
-}
-
-TEST(LogTest, Register) {
- llvm::llvm_shutdown_obj obj;
- Log::Register("chan", test_channel);
- Log::Unregister("chan");
- Log::Register("chan", test_channel);
- Log::Unregister("chan");
-}
-
-TEST(LogTest, Unregister) {
- llvm::llvm_shutdown_obj obj;
- Log::Register("chan", test_channel);
- EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO));
- std::string message;
- std::shared_ptr<llvm::raw_string_ostream> stream_sp(
- new llvm::raw_string_ostream(message));
- EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", {"foo"}, llvm::nulls()));
- EXPECT_NE(nullptr, test_channel.GetLogIfAny(FOO));
- Log::Unregister("chan");
- EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO));
-}
-
-TEST_F(LogChannelTest, Enable) {
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO));
- std::string message;
- std::shared_ptr<llvm::raw_string_ostream> stream_sp(
- new llvm::raw_string_ostream(message));
- std::string error;
- ASSERT_FALSE(EnableChannel(stream_sp, 0, "chanchan", {}, error));
- EXPECT_EQ("Invalid log channel 'chanchan'.\n", error);
-
- EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {}, error));
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
-
- EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"bar"}, error));
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
-
- EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"baz"}, error));
- EXPECT_NE(std::string::npos, error.find("unrecognized log category 'baz'"))
- << "error: " << error;
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
-}
-
-TEST_F(LogChannelTest, EnableOptions) {
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO));
- std::string message;
- std::shared_ptr<llvm::raw_string_ostream> stream_sp(
- new llvm::raw_string_ostream(message));
- std::string error;
- EXPECT_TRUE(
- EnableChannel(stream_sp, LLDB_LOG_OPTION_VERBOSE, "chan", {}, error));
-
- Log *log = test_channel.GetLogIfAll(FOO);
- ASSERT_NE(nullptr, log);
- EXPECT_TRUE(log->GetVerbose());
-}
-
-TEST_F(LogChannelTest, Disable) {
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO));
- std::string message;
- std::shared_ptr<llvm::raw_string_ostream> stream_sp(
- new llvm::raw_string_ostream(message));
- std::string error;
- EXPECT_TRUE(EnableChannel(stream_sp, 0, "chan", {"foo", "bar"}, error));
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR));
-
- EXPECT_TRUE(DisableChannel("chan", {"bar"}, error));
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
-
- EXPECT_TRUE(DisableChannel("chan", {"baz"}, error));
- EXPECT_NE(std::string::npos, error.find("unrecognized log category 'baz'"))
- << "error: " << error;
- EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO));
- EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR));
-
- EXPECT_TRUE(DisableChannel("chan", {}, error));
- EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO | BAR));
-}
-
-TEST_F(LogChannelTest, List) {
- std::string list;
- EXPECT_TRUE(ListCategories("chan", list));
- std::string expected =
- R"(Logging categories for 'chan':
- all - all available logging categories
- default - default set of logging categories
- foo - log foo
- bar - log bar
-)";
- EXPECT_EQ(expected, list);
-
- EXPECT_FALSE(ListCategories("chanchan", list));
- EXPECT_EQ("Invalid log channel 'chanchan'.\n", list);
-}
-
-TEST_F(LogChannelEnabledTest, log_options) {
- std::string Err;
- EXPECT_EQ("Hello World\n", logAndTakeOutput("Hello World"));
- EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_THREADSAFE, "chan", {},
- Err));
- EXPECT_EQ("Hello World\n", logAndTakeOutput("Hello World"));
-
- {
- EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_PREPEND_SEQUENCE,
- "chan", {}, Err));
- llvm::StringRef Msg = logAndTakeOutput("Hello World");
- int seq_no;
- EXPECT_EQ(1, sscanf(Msg.str().c_str(), "%d Hello World", &seq_no));
- }
-
- {
- EXPECT_TRUE(EnableChannel(getStream(), LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION,
- "chan", {}, Err));
- llvm::StringRef Msg = logAndTakeOutput("Hello World");
- char File[12];
- char Function[17];
-
- sscanf(Msg.str().c_str(), "%[^:]:%s Hello World", File, Function);
- EXPECT_STRCASEEQ("LogTest.cpp", File);
- EXPECT_STREQ("logAndTakeOutput", Function);
- }
-
- EXPECT_TRUE(EnableChannel(
- getStream(), LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD, "chan", {}, Err));
- EXPECT_EQ(llvm::formatv("[{0,0+4}/{1,0+4}] Hello World\n", ::getpid(),
- llvm::get_threadid())
- .str(),
- logAndTakeOutput("Hello World"));
-}
-
-TEST_F(LogChannelEnabledTest, LLDB_LOG_ERROR) {
- LLDB_LOG_ERROR(getLog(), llvm::Error::success(), "Foo failed: {0}");
- ASSERT_EQ("", takeOutput());
-
- LLDB_LOG_ERROR(getLog(),
- llvm::make_error<llvm::StringError>(
- "My Error", llvm::inconvertibleErrorCode()),
- "Foo failed: {0}");
- ASSERT_EQ("Foo failed: My Error\n", takeOutput());
-
- // Doesn't log, but doesn't assert either
- LLDB_LOG_ERROR(nullptr,
- llvm::make_error<llvm::StringError>(
- "My Error", llvm::inconvertibleErrorCode()),
- "Foo failed: {0}");
-}
-
-TEST_F(LogChannelEnabledTest, LogThread) {
- // Test that we are able to concurrently write to a log channel and disable
- // it.
- std::string err;
-
- // Start logging on one thread. Concurrently, try disabling the log channel.
- std::thread log_thread([this] { LLDB_LOG(getLog(), "Hello World"); });
- EXPECT_TRUE(DisableChannel("chan", {}, err));
- log_thread.join();
-
- // The log thread either managed to write to the log in time, or it didn't. In
- // either case, we should not trip any undefined behavior (run the test under
- // TSAN to verify this).
- EXPECT_THAT(takeOutput(), testing::AnyOf("", "Hello World\n"));
-}
-
-TEST_F(LogChannelEnabledTest, LogVerboseThread) {
- // Test that we are able to concurrently check the verbose flag of a log
- // channel and enable it.
- std::string err;
-
- // Start logging on one thread. Concurrently, try enabling the log channel
- // (with different log options).
- std::thread log_thread([this] { LLDB_LOGV(getLog(), "Hello World"); });
- EXPECT_TRUE(
- EnableChannel(getStream(), LLDB_LOG_OPTION_VERBOSE, "chan", {}, err));
- log_thread.join();
-
- // The log thread either managed to write to the log, or it didn't. In either
- // case, we should not trip any undefined behavior (run the test under TSAN to
- // verify this).
- EXPECT_THAT(takeOutput(), testing::AnyOf("", "Hello World\n"));
-}
-
-TEST_F(LogChannelEnabledTest, LogGetLogThread) {
- // Test that we are able to concurrently get mask of a Log object and disable
- // it.
- std::string err;
-
- // Try fetching the log mask on one thread. Concurrently, try disabling the
- // log channel.
- uint32_t mask;
- std::thread log_thread([this, &mask] { mask = getLog()->GetMask().Get(); });
- EXPECT_TRUE(DisableChannel("chan", {}, err));
- log_thread.join();
-
- // The mask should be either zero of "FOO". In either case, we should not trip
- // any undefined behavior (run the test under TSAN to verify this).
- EXPECT_THAT(mask, testing::AnyOf(0, FOO));
-}
+++ /dev/null
-//===-- NameMatchesTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/NameMatches.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(NameMatchesTest, Ignore) {
- EXPECT_TRUE(NameMatches("foo", NameMatch::Ignore, "bar"));
-}
-
-TEST(NameMatchesTest, Equals) {
- EXPECT_TRUE(NameMatches("foo", NameMatch::Equals, "foo"));
- EXPECT_FALSE(NameMatches("foo", NameMatch::Equals, "bar"));
-}
-
-TEST(NameMatchesTest, Contains) {
- EXPECT_TRUE(NameMatches("foobar", NameMatch::Contains, "foo"));
- EXPECT_TRUE(NameMatches("foobar", NameMatch::Contains, "oob"));
- EXPECT_TRUE(NameMatches("foobar", NameMatch::Contains, "bar"));
- EXPECT_TRUE(NameMatches("foobar", NameMatch::Contains, "foobar"));
- EXPECT_TRUE(NameMatches("", NameMatch::Contains, ""));
- EXPECT_FALSE(NameMatches("", NameMatch::Contains, "foo"));
- EXPECT_FALSE(NameMatches("foobar", NameMatch::Contains, "baz"));
-}
-
-TEST(NameMatchesTest, StartsWith) {
- EXPECT_TRUE(NameMatches("foo", NameMatch::StartsWith, "f"));
- EXPECT_TRUE(NameMatches("foo", NameMatch::StartsWith, ""));
- EXPECT_TRUE(NameMatches("", NameMatch::StartsWith, ""));
- EXPECT_FALSE(NameMatches("foo", NameMatch::StartsWith, "b"));
- EXPECT_FALSE(NameMatches("", NameMatch::StartsWith, "b"));
-}
-
-TEST(NameMatchesTest, EndsWith) {
- EXPECT_TRUE(NameMatches("foo", NameMatch::EndsWith, "o"));
- EXPECT_TRUE(NameMatches("foo", NameMatch::EndsWith, ""));
- EXPECT_TRUE(NameMatches("", NameMatch::EndsWith, ""));
- EXPECT_FALSE(NameMatches("foo", NameMatch::EndsWith, "b"));
- EXPECT_FALSE(NameMatches("", NameMatch::EndsWith, "b"));
-}
-
-TEST(NameMatchesTest, RegularExpression) {
- EXPECT_TRUE(NameMatches("foobar", NameMatch::RegularExpression, "foo"));
- EXPECT_TRUE(NameMatches("foobar", NameMatch::RegularExpression, "f[oa]o"));
- EXPECT_FALSE(NameMatches("foo", NameMatch::RegularExpression, ""));
- EXPECT_FALSE(NameMatches("", NameMatch::RegularExpression, ""));
- EXPECT_FALSE(NameMatches("foo", NameMatch::RegularExpression, "b"));
- EXPECT_FALSE(NameMatches("", NameMatch::RegularExpression, "b"));
- EXPECT_FALSE(NameMatches("^a", NameMatch::RegularExpression, "^a"));
-}
+++ /dev/null
-//===-- OptionsWithRawTest.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/Args.h"
-#include "lldb/Utility/StringList.h"
-
-using namespace lldb_private;
-
-TEST(OptionsWithRawTest, EmptyInput) {
- // An empty string is just an empty suffix without any arguments.
- OptionsWithRaw args("");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), "");
-}
-
-TEST(OptionsWithRawTest, SingleWhitespaceInput) {
- // Only whitespace is just a suffix.
- OptionsWithRaw args(" ");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), " ");
-}
-
-TEST(OptionsWithRawTest, WhitespaceInput) {
- // Only whitespace is just a suffix.
- OptionsWithRaw args(" ");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), " ");
-}
-
-TEST(OptionsWithRawTest, ArgsButNoDelimiter) {
- // This counts as a suffix because there is no -- at the end.
- OptionsWithRaw args("-foo bar");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), "-foo bar");
-}
-
-TEST(OptionsWithRawTest, ArgsButNoLeadingDash) {
- // No leading dash means we have no arguments.
- OptionsWithRaw args("foo bar --");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), "foo bar --");
-}
-
-TEST(OptionsWithRawTest, QuotedSuffix) {
- // We need to have a way to escape the -- to make it usable as an argument.
- OptionsWithRaw args("-foo \"--\" bar");
- ASSERT_FALSE(args.HasArgs());
- ASSERT_STREQ(args.GetRawPart().c_str(), "-foo \"--\" bar");
-}
-
-TEST(OptionsWithRawTest, EmptySuffix) {
- // An empty suffix with arguments.
- OptionsWithRaw args("-foo --");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo --");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "");
-}
-
-TEST(OptionsWithRawTest, EmptySuffixSingleWhitespace) {
- // A single whitespace also countas as an empty suffix (because that usually
- // separates the suffix from the double dash.
- OptionsWithRaw args("-foo -- ");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "");
-}
-
-TEST(OptionsWithRawTest, WhitespaceSuffix) {
- // A single whtiespace character as a suffix.
- OptionsWithRaw args("-foo -- ");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), " ");
-}
-
-TEST(OptionsWithRawTest, LeadingSpaceArgs) {
- // Whitespace before the first dash needs to be ignored.
- OptionsWithRaw args(" -foo -- bar");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), " -foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), " -foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar");
-}
-
-TEST(OptionsWithRawTest, SingleWordSuffix) {
- // A single word as a suffix.
- OptionsWithRaw args("-foo -- bar");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar");
-}
-
-TEST(OptionsWithRawTest, MultiWordSuffix) {
- // Multiple words as a suffix.
- OptionsWithRaw args("-foo -- bar baz");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar baz");
-}
-
-TEST(OptionsWithRawTest, UnterminatedQuote) {
- // A quote character in the suffix shouldn't influence the parsing.
- OptionsWithRaw args("-foo -- bar \" ");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar \" ");
-}
-
-TEST(OptionsWithRawTest, TerminatedQuote) {
- // A part of the suffix is quoted, which shouldn't influence the parsing.
- OptionsWithRaw args("-foo -- bar \"a\" ");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "-foo ");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-foo -- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(1u, ref.size());
- EXPECT_STREQ("-foo", ref[0]);
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar \"a\" ");
-}
-
-TEST(OptionsWithRawTest, EmptyArgsOnlySuffix) {
- // Empty argument list, but we have a suffix.
- OptionsWithRaw args("-- bar");
- ASSERT_TRUE(args.HasArgs());
- ASSERT_EQ(args.GetArgString(), "");
- ASSERT_EQ(args.GetArgStringWithDelimiter(), "-- ");
-
- auto ref = args.GetArgs().GetArgumentArrayRef();
- ASSERT_EQ(0u, ref.size());
-
- ASSERT_STREQ(args.GetRawPart().c_str(), "bar");
-}
+++ /dev/null
-//===-- PredicateTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Predicate.h"
-#include "gtest/gtest.h"
-#include <thread>
-
-using namespace lldb_private;
-
-TEST(Predicate, WaitForValueEqualTo) {
- Predicate<int> P(0);
- EXPECT_TRUE(P.WaitForValueEqualTo(0));
- EXPECT_FALSE(P.WaitForValueEqualTo(1, std::chrono::milliseconds(10)));
-
- std::thread Setter([&P] {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- P.SetValue(1, eBroadcastAlways);
- });
- EXPECT_TRUE(P.WaitForValueEqualTo(1));
- Setter.join();
-}
-
-TEST(Predicate, WaitForValueNotEqualTo) {
- Predicate<int> P(0);
- EXPECT_EQ(0, P.WaitForValueNotEqualTo(1));
- EXPECT_EQ(llvm::None,
- P.WaitForValueNotEqualTo(0, std::chrono::milliseconds(10)));
-}
+++ /dev/null
-//===-- ProcessInfoTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/ProcessInfo.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(ProcessInfoTest, Constructor) {
- ProcessInfo Info("foo", ArchSpec("x86_64-pc-linux"), 47);
- EXPECT_STREQ("foo", Info.GetName());
- EXPECT_EQ(ArchSpec("x86_64-pc-linux"), Info.GetArchitecture());
- EXPECT_EQ(47u, Info.GetProcessID());
-}
+++ /dev/null
-//===-- ProcessInstanceInfoTest.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Target/Process.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-/// A very simple resolver which fails for even ids and returns a simple string
-/// for odd ones.
-class DummyUserIDResolver : public UserIDResolver {
-protected:
- llvm::Optional<std::string> DoGetUserName(id_t uid) override {
- if (uid % 2)
- return ("user" + llvm::Twine(uid)).str();
- return llvm::None;
- }
-
- llvm::Optional<std::string> DoGetGroupName(id_t gid) override {
- if (gid % 2)
- return ("group" + llvm::Twine(gid)).str();
- return llvm::None;
- }
-};
-} // namespace
-
-TEST(ProcessInstanceInfo, Dump) {
- ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47);
- info.SetUserID(1);
- info.SetEffectiveUserID(2);
- info.SetGroupID(3);
- info.SetEffectiveGroupID(4);
-
- DummyUserIDResolver resolver;
- StreamString s;
- info.Dump(s, resolver);
- EXPECT_STREQ(R"( pid = 47
- name = a.out
- file = a.out
- arch = x86_64-pc-linux
- uid = 1 (user1)
- gid = 3 (group3)
- euid = 2 ()
- egid = 4 ()
-)",
- s.GetData());
-}
-
-TEST(ProcessInstanceInfo, DumpTable) {
- ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47);
- info.SetUserID(1);
- info.SetEffectiveUserID(2);
- info.SetGroupID(3);
- info.SetEffectiveGroupID(4);
-
- DummyUserIDResolver resolver;
- StreamString s;
-
- const bool show_args = false;
- const bool verbose = true;
- ProcessInstanceInfo::DumpTableHeader(s, show_args, verbose);
- info.DumpAsTableRow(s, resolver, show_args, verbose);
- EXPECT_STREQ(
- R"(PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE ARGUMENTS
-====== ====== ========== ========== ========== ========== ============================== ============================
-47 0 user1 group3 2 4 x86_64-pc-linux
-)",
- s.GetData());
-}
-
-TEST(ProcessInstanceInfo, DumpTable_invalidUID) {
- ProcessInstanceInfo info("a.out", ArchSpec("aarch64-unknown-linux-android"), 47);
-
- DummyUserIDResolver resolver;
- StreamString s;
-
- const bool show_args = false;
- const bool verbose = false;
- ProcessInstanceInfo::DumpTableHeader(s, show_args, verbose);
- info.DumpAsTableRow(s, resolver, show_args, verbose);
- EXPECT_STREQ(
- R"(PID PARENT USER TRIPLE NAME
-====== ====== ========== ============================== ============================
-47 0 aarch64-unknown-linux-android a.out
-)",
- s.GetData());
-}
-
-TEST(ProcessInstanceInfoMatch, Name) {
- ProcessInstanceInfo info_bar, info_empty;
- info_bar.GetExecutableFile().SetFile("/foo/bar", FileSpec::Style::posix);
-
- ProcessInstanceInfoMatch match;
- match.SetNameMatchType(NameMatch::Equals);
- match.GetProcessInfo().GetExecutableFile().SetFile("bar",
- FileSpec::Style::posix);
-
- EXPECT_TRUE(match.Matches(info_bar));
- EXPECT_FALSE(match.Matches(info_empty));
-
- match.GetProcessInfo().GetExecutableFile() = FileSpec();
- EXPECT_TRUE(match.Matches(info_bar));
- EXPECT_TRUE(match.Matches(info_empty));
-}
-
-TEST(ProcessInstanceInfo, Yaml) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47);
- info.SetUserID(1);
- info.SetEffectiveUserID(2);
- info.SetGroupID(3);
- info.SetEffectiveGroupID(4);
- llvm::yaml::Output yout(os);
- yout << info;
- os.flush();
-
- // Deserialize.
- ProcessInstanceInfo deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- EXPECT_EQ(deserialized.GetNameAsStringRef(), info.GetNameAsStringRef());
- EXPECT_EQ(deserialized.GetArchitecture(), info.GetArchitecture());
- EXPECT_EQ(deserialized.GetUserID(), info.GetUserID());
- EXPECT_EQ(deserialized.GetGroupID(), info.GetGroupID());
- EXPECT_EQ(deserialized.GetEffectiveUserID(), info.GetEffectiveUserID());
- EXPECT_EQ(deserialized.GetEffectiveGroupID(), info.GetEffectiveGroupID());
-}
-
-TEST(ProcessInstanceInfoList, Yaml) {
- std::string buffer;
- llvm::raw_string_ostream os(buffer);
-
- // Serialize.
- ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47);
- info.SetUserID(1);
- info.SetEffectiveUserID(2);
- info.SetGroupID(3);
- info.SetEffectiveGroupID(4);
- ProcessInstanceInfoList list;
- list.push_back(info);
- llvm::yaml::Output yout(os);
- yout << list;
- os.flush();
-
- // Deserialize.
- ProcessInstanceInfoList deserialized;
- llvm::yaml::Input yin(buffer);
- yin >> deserialized;
-
- ASSERT_EQ(deserialized.size(), static_cast<size_t>(1));
- EXPECT_EQ(deserialized[0].GetNameAsStringRef(), info.GetNameAsStringRef());
- EXPECT_EQ(deserialized[0].GetArchitecture(), info.GetArchitecture());
- EXPECT_EQ(deserialized[0].GetUserID(), info.GetUserID());
- EXPECT_EQ(deserialized[0].GetGroupID(), info.GetGroupID());
- EXPECT_EQ(deserialized[0].GetEffectiveUserID(), info.GetEffectiveUserID());
- EXPECT_EQ(deserialized[0].GetEffectiveGroupID(), info.GetEffectiveGroupID());
-}
+++ /dev/null
-//===-- RangeTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/RangeMap.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(RangeVector, CombineConsecutiveRanges) {
- using RangeVector = RangeVector<uint32_t, uint32_t>;
- using Entry = RangeVector::Entry;
-
- RangeVector V;
- V.Append(0, 1);
- V.Append(5, 1);
- V.Append(6, 1);
- V.Append(10, 9);
- V.Append(15, 1);
- V.Append(20, 9);
- V.Append(21, 9);
- V.Sort();
- V.CombineConsecutiveRanges();
- EXPECT_THAT(V, testing::ElementsAre(Entry(0, 1), Entry(5, 2), Entry(10, 9),
- Entry(20, 10)));
-
- V.Clear();
- V.Append(0, 20);
- V.Append(5, 1);
- V.Append(10, 1);
- V.Sort();
- V.CombineConsecutiveRanges();
- EXPECT_THAT(V, testing::ElementsAre(Entry(0, 20)));
-}
-
-using RangeDataVectorT = RangeDataVector<uint32_t, uint32_t, uint32_t>;
-using EntryT = RangeDataVectorT::Entry;
-
-static testing::Matcher<const EntryT *> EntryIs(uint32_t ID) {
- return testing::Pointee(testing::Field(&EntryT::data, ID));
-}
-
-std::vector<uint32_t> FindEntryIndexes(uint32_t address, RangeDataVectorT map) {
- std::vector<uint32_t> result;
- map.FindEntryIndexesThatContain(address, result);
- return result;
-}
-
-TEST(RangeDataVector, FindEntryThatContains) {
- RangeDataVectorT Map;
- uint32_t NextID = 0;
- Map.Append(EntryT(0, 10, NextID++));
- Map.Append(EntryT(10, 10, NextID++));
- Map.Append(EntryT(20, 10, NextID++));
- Map.Sort();
-
- EXPECT_THAT(Map.FindEntryThatContains(0), EntryIs(0));
- EXPECT_THAT(Map.FindEntryThatContains(9), EntryIs(0));
- EXPECT_THAT(Map.FindEntryThatContains(10), EntryIs(1));
- EXPECT_THAT(Map.FindEntryThatContains(19), EntryIs(1));
- EXPECT_THAT(Map.FindEntryThatContains(20), EntryIs(2));
- EXPECT_THAT(Map.FindEntryThatContains(29), EntryIs(2));
- EXPECT_THAT(Map.FindEntryThatContains(30), nullptr);
-}
-
-TEST(RangeDataVector, FindEntryThatContains_Overlap) {
- RangeDataVectorT Map;
- uint32_t NextID = 0;
- Map.Append(EntryT(0, 40, NextID++));
- Map.Append(EntryT(10, 20, NextID++));
- Map.Append(EntryT(20, 10, NextID++));
- Map.Sort();
-
- // With overlapping intervals, the intention seems to be to return the first
- // interval which contains the address.
- EXPECT_THAT(Map.FindEntryThatContains(25), EntryIs(0));
-
- // However, this does not always succeed.
- // TODO: This should probably return the range (0, 40) as well.
- EXPECT_THAT(Map.FindEntryThatContains(35), nullptr);
-}
-
-TEST(RangeDataVector, CustomSort) {
- // First the default ascending order sorting of the data field.
- auto Map = RangeDataVectorT();
- Map.Append(EntryT(0, 10, 50));
- Map.Append(EntryT(0, 10, 52));
- Map.Append(EntryT(0, 10, 53));
- Map.Append(EntryT(0, 10, 51));
- Map.Sort();
-
- EXPECT_THAT(Map.GetSize(), 4);
- EXPECT_THAT(Map.GetEntryRef(0).data, 50);
- EXPECT_THAT(Map.GetEntryRef(1).data, 51);
- EXPECT_THAT(Map.GetEntryRef(2).data, 52);
- EXPECT_THAT(Map.GetEntryRef(3).data, 53);
-
- // And then a custom descending order sorting of the data field.
- class CtorParam {};
- class CustomSort {
- public:
- CustomSort(CtorParam) {}
- bool operator()(const uint32_t a_data, const uint32_t b_data) {
- return a_data > b_data;
- }
- };
- using RangeDataVectorCustomSortT =
- RangeDataVector<uint32_t, uint32_t, uint32_t, 0, CustomSort>;
- using EntryT = RangeDataVectorT::Entry;
-
- auto MapC = RangeDataVectorCustomSortT(CtorParam());
- MapC.Append(EntryT(0, 10, 50));
- MapC.Append(EntryT(0, 10, 52));
- MapC.Append(EntryT(0, 10, 53));
- MapC.Append(EntryT(0, 10, 51));
- MapC.Sort();
-
- EXPECT_THAT(MapC.GetSize(), 4);
- EXPECT_THAT(MapC.GetEntryRef(0).data, 53);
- EXPECT_THAT(MapC.GetEntryRef(1).data, 52);
- EXPECT_THAT(MapC.GetEntryRef(2).data, 51);
- EXPECT_THAT(MapC.GetEntryRef(3).data, 50);
-}
-
-TEST(RangeDataVector, FindEntryIndexesThatContain) {
- RangeDataVectorT Map;
- Map.Append(EntryT(0, 10, 10));
- Map.Append(EntryT(10, 10, 11));
- Map.Append(EntryT(20, 10, 12));
- Map.Sort();
-
- EXPECT_THAT(FindEntryIndexes(0, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(9, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(10, Map), testing::ElementsAre(11));
- EXPECT_THAT(FindEntryIndexes(19, Map), testing::ElementsAre(11));
- EXPECT_THAT(FindEntryIndexes(20, Map), testing::ElementsAre(12));
- EXPECT_THAT(FindEntryIndexes(29, Map), testing::ElementsAre(12));
- EXPECT_THAT(FindEntryIndexes(30, Map), testing::ElementsAre());
-}
-
-TEST(RangeDataVector, FindEntryIndexesThatContain_Overlap) {
- RangeDataVectorT Map;
- Map.Append(EntryT(0, 40, 10));
- Map.Append(EntryT(10, 20, 11));
- Map.Append(EntryT(20, 10, 12));
- Map.Sort();
-
- EXPECT_THAT(FindEntryIndexes(0, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(9, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(10, Map), testing::ElementsAre(10, 11));
- EXPECT_THAT(FindEntryIndexes(19, Map), testing::ElementsAre(10, 11));
- EXPECT_THAT(FindEntryIndexes(20, Map), testing::ElementsAre(10, 11, 12));
- EXPECT_THAT(FindEntryIndexes(29, Map), testing::ElementsAre(10, 11, 12));
- EXPECT_THAT(FindEntryIndexes(30, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(39, Map), testing::ElementsAre(10));
- EXPECT_THAT(FindEntryIndexes(40, Map), testing::ElementsAre());
-}
+++ /dev/null
-//===-- RangeTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/RangeMap.h"
-#include <cstdint>
-#include <type_traits>
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(RangeTest, SizeTypes) {
- Range<lldb::addr_t, uint32_t> r;
- static_assert(std::is_same<lldb::addr_t, decltype(r.GetRangeBase())>::value,
- "RangeBase type is not equal to the given one.");
- static_assert(std::is_same<lldb::addr_t, decltype(r.GetRangeEnd())>::value,
- "RangeEnd type is not equal to the given one.");
- static_assert(std::is_same<uint32_t, decltype(r.GetByteSize())>::value,
- "Size type is not equal to the given one.");
-}
-
-typedef Range<lldb::addr_t, uint32_t> RangeT;
-
-TEST(RangeTest, DefaultConstructor) {
- RangeT r;
- EXPECT_FALSE(r.IsValid());
- EXPECT_EQ(0U, r.GetByteSize());
- EXPECT_EQ(0U, r.GetRangeBase());
- EXPECT_EQ(0U, r.GetRangeEnd());
-}
-
-TEST(RangeTest, Constructor) {
- RangeT r(3, 5);
- EXPECT_TRUE(r.IsValid());
- EXPECT_EQ(5U, r.GetByteSize());
- EXPECT_EQ(3U, r.GetRangeBase());
- EXPECT_EQ(8U, r.GetRangeEnd());
-}
-
-TEST(RangeTest, Copy) {
- RangeT orig(3, 5);
- RangeT r = orig;
- EXPECT_TRUE(r.IsValid());
- EXPECT_EQ(5U, r.GetByteSize());
- EXPECT_EQ(3U, r.GetRangeBase());
- EXPECT_EQ(8U, r.GetRangeEnd());
-}
-
-TEST(RangeTest, Clear) {
- RangeT r(3, 5);
- r.Clear();
- EXPECT_TRUE(r == RangeT());
-}
-
-TEST(RangeTest, ClearWithStarAddress) {
- RangeT r(3, 5);
- r.Clear(4);
- EXPECT_TRUE(r == RangeT(4, 0));
-}
-
-TEST(RangeTest, SetRangeBase) {
- RangeT r(3, 5);
- r.SetRangeBase(6);
- EXPECT_EQ(6U, r.GetRangeBase());
- EXPECT_EQ(11U, r.GetRangeEnd());
- EXPECT_EQ(5U, r.GetByteSize());
-}
-
-TEST(RangeTest, Slide) {
- RangeT r(3, 5);
- r.Slide(1);
- EXPECT_EQ(4U, r.GetRangeBase());
- EXPECT_EQ(9U, r.GetRangeEnd());
- EXPECT_EQ(5U, r.GetByteSize());
-
- r.Slide(2);
- EXPECT_EQ(6U, r.GetRangeBase());
- EXPECT_EQ(11U, r.GetRangeEnd());
- EXPECT_EQ(5U, r.GetByteSize());
-}
-
-TEST(RangeTest, SlideZero) {
- RangeT r(3, 5);
- r.Slide(0);
- EXPECT_EQ(3U, r.GetRangeBase());
- EXPECT_EQ(8U, r.GetRangeEnd());
- EXPECT_EQ(5U, r.GetByteSize());
-}
-
-TEST(RangeTest, ContainsAddr) {
- RangeT r(3, 5);
- EXPECT_FALSE(r.Contains(0));
- EXPECT_FALSE(r.Contains(1));
- EXPECT_FALSE(r.Contains(2));
- EXPECT_TRUE(r.Contains(3));
- EXPECT_TRUE(r.Contains(4));
- EXPECT_TRUE(r.Contains(5));
- EXPECT_TRUE(r.Contains(6));
- EXPECT_TRUE(r.Contains(7));
- EXPECT_FALSE(r.Contains(8));
- EXPECT_FALSE(r.Contains(9));
- EXPECT_FALSE(r.Contains(10));
-}
-
-TEST(RangeTest, ContainsAddrInvalid) {
- RangeT r;
- EXPECT_FALSE(r.Contains(0));
- EXPECT_FALSE(r.Contains(1));
- EXPECT_FALSE(r.Contains(2));
- EXPECT_FALSE(r.Contains(3));
- EXPECT_FALSE(r.Contains(4));
-}
-
-TEST(RangeTest, ContainsEndInclusive) {
- RangeT r(3, 5);
- EXPECT_FALSE(r.ContainsEndInclusive(0));
- EXPECT_FALSE(r.ContainsEndInclusive(1));
- EXPECT_FALSE(r.ContainsEndInclusive(2));
- EXPECT_TRUE(r.ContainsEndInclusive(3));
- EXPECT_TRUE(r.ContainsEndInclusive(4));
- EXPECT_TRUE(r.ContainsEndInclusive(5));
- EXPECT_TRUE(r.ContainsEndInclusive(6));
- EXPECT_TRUE(r.ContainsEndInclusive(7));
- EXPECT_TRUE(r.ContainsEndInclusive(8));
- EXPECT_FALSE(r.ContainsEndInclusive(9));
- EXPECT_FALSE(r.ContainsEndInclusive(10));
-}
-
-TEST(RangeTest, ContainsEndInclusiveInvalid) {
- RangeT r;
- // FIXME: This is probably not intended.
- EXPECT_TRUE(r.ContainsEndInclusive(0));
-
- EXPECT_FALSE(r.ContainsEndInclusive(1));
- EXPECT_FALSE(r.ContainsEndInclusive(2));
-}
-
-TEST(RangeTest, ContainsRange) {
- RangeT r(3, 5);
-
- // Range always contains itself.
- EXPECT_TRUE(r.Contains(r));
- // Invalid range.
- EXPECT_FALSE(r.Contains(RangeT()));
- // Range starts and ends before.
- EXPECT_FALSE(r.Contains(RangeT(0, 3)));
- // Range starts before but contains beginning.
- EXPECT_FALSE(r.Contains(RangeT(0, 4)));
- // Range starts before but contains beginning and more.
- EXPECT_FALSE(r.Contains(RangeT(0, 5)));
- // Range starts before and contains the other.
- EXPECT_FALSE(r.Contains(RangeT(0, 9)));
- // Range is fully inside.
- EXPECT_TRUE(r.Contains(RangeT(4, 3)));
- // Range has same start, but not as large.
- EXPECT_TRUE(r.Contains(RangeT(3, 4)));
- // Range has same end, but starts earlier.
- EXPECT_TRUE(r.Contains(RangeT(4, 4)));
- // Range starts inside, but stops after the end of r.
- EXPECT_FALSE(r.Contains(RangeT(4, 5)));
- // Range starts directly after r.
- EXPECT_FALSE(r.Contains(RangeT(8, 2)));
- // Range starts directly after r.
- EXPECT_FALSE(r.Contains(RangeT(9, 2)));
-
- // Invalid range with different start.
- // FIXME: The first two probably not intended.
- EXPECT_TRUE(r.Contains(RangeT(3, 0)));
- EXPECT_TRUE(r.Contains(RangeT(4, 0)));
- EXPECT_FALSE(r.Contains(RangeT(8, 0)));
-}
-
-TEST(RangeTest, ContainsRangeStartingFromZero) {
- RangeT r(0, 3);
- EXPECT_TRUE(r.Contains(r));
-
- // FIXME: This is probably not intended.
- EXPECT_TRUE(r.Contains(RangeT()));
-}
-
-TEST(RangeTest, Union) {
- RangeT r(3, 5);
-
- // Ranges that we can't merge because it's not adjoin/intersecting.
- EXPECT_FALSE(r.Union(RangeT(9, 1)));
- // Check that we didn't modify our range.
- EXPECT_EQ(r, RangeT(3, 5));
-
- // Another range we can't merge, but before r.
- EXPECT_FALSE(r.Union(RangeT(1, 1)));
- EXPECT_EQ(r, RangeT(3, 5));
-
- // Merge an adjoin range after.
- EXPECT_TRUE(r.Union(RangeT(8, 2)));
- EXPECT_EQ(r, RangeT(3, 7));
-
- // Merge an adjoin range before.
- EXPECT_TRUE(r.Union(RangeT(1, 2)));
- EXPECT_EQ(r, RangeT(1, 9));
-
- // Merge an intersecting range after.
- EXPECT_TRUE(r.Union(RangeT(8, 3)));
- EXPECT_EQ(r, RangeT(1, 10));
-
- // Merge an intersecting range before.
- EXPECT_TRUE(r.Union(RangeT(0, 1)));
- EXPECT_EQ(r, RangeT(0, 11));
-
- // Merge a few ranges inside that shouldn't do anything.
- EXPECT_TRUE(r.Union(RangeT(0, 3)));
- EXPECT_EQ(r, RangeT(0, 11));
- EXPECT_TRUE(r.Union(RangeT(5, 1)));
- EXPECT_EQ(r, RangeT(0, 11));
- EXPECT_TRUE(r.Union(RangeT(9, 2)));
- EXPECT_EQ(r, RangeT(0, 11));
-}
-
-TEST(RangeTest, DoesAdjoinOrIntersect) {
- RangeT r(3, 4);
-
- EXPECT_FALSE(r.DoesAdjoinOrIntersect(RangeT(1, 1)));
- EXPECT_TRUE(r.DoesAdjoinOrIntersect(RangeT(1, 2)));
- EXPECT_TRUE(r.DoesAdjoinOrIntersect(RangeT(2, 2)));
- EXPECT_TRUE(r.DoesAdjoinOrIntersect(RangeT(4, 2)));
- EXPECT_TRUE(r.DoesAdjoinOrIntersect(RangeT(6, 2)));
- EXPECT_TRUE(r.DoesAdjoinOrIntersect(RangeT(7, 2)));
- EXPECT_FALSE(r.DoesAdjoinOrIntersect(RangeT(8, 2)));
-}
-
-TEST(RangeTest, DoesIntersect) {
- RangeT r(3, 4);
-
- EXPECT_FALSE(r.DoesIntersect(RangeT(1, 1)));
- EXPECT_FALSE(r.DoesIntersect(RangeT(1, 2)));
- EXPECT_TRUE(r.DoesIntersect(RangeT(2, 2)));
- EXPECT_TRUE(r.DoesIntersect(RangeT(4, 2)));
- EXPECT_TRUE(r.DoesIntersect(RangeT(6, 2)));
- EXPECT_FALSE(r.DoesIntersect(RangeT(7, 2)));
- EXPECT_FALSE(r.DoesIntersect(RangeT(8, 2)));
-}
-
-TEST(RangeTest, LessThan) {
- RangeT r(10, 20);
-
- // Equal range.
- EXPECT_FALSE(r < RangeT(10, 20));
- EXPECT_FALSE(RangeT(10, 20) < r);
-
- auto expect_ordered_less_than = [](RangeT r1, RangeT r2) {
- EXPECT_TRUE(r1 < r2);
- EXPECT_FALSE(r2 < r1);
- };
-
- // Same start, but bigger size.
- expect_ordered_less_than(r, RangeT(10, 21));
-
- // Start before and ends before.
- expect_ordered_less_than(RangeT(9, 20), r);
-
- // Start before and equal size.
- expect_ordered_less_than(RangeT(9, 21), r);
-
- // Start before and bigger size.
- expect_ordered_less_than(RangeT(9, 22), r);
-
- // Start after and ends before.
- expect_ordered_less_than(r, RangeT(11, 18));
-
- // Start after and equal size.
- expect_ordered_less_than(r, RangeT(11, 19));
-
- // Start after and bigger size.
- expect_ordered_less_than(r, RangeT(11, 20));
-}
-
-TEST(RangeTest, Equal) {
- RangeT r(10, 20);
-
- // Equal range.
- EXPECT_TRUE(r == RangeT(10, 20));
-
- // Same start, different size.
- EXPECT_FALSE(r == RangeT(10, 21));
-
- // Different start, same size.
- EXPECT_FALSE(r == RangeT(9, 20));
-
- // Different start, different size.
- EXPECT_FALSE(r == RangeT(9, 21));
- EXPECT_FALSE(r == RangeT(11, 19));
-}
-
-TEST(RangeTest, NotEqual) {
- RangeT r(10, 20);
-
- EXPECT_FALSE(r != RangeT(10, 20));
-
- EXPECT_TRUE(r != RangeT(10, 21));
- EXPECT_TRUE(r != RangeT(9, 20));
- EXPECT_TRUE(r != RangeT(9, 21));
-}
-
-// Comparison tests for invalid ranges (size == 0).
-
-TEST(RangeTest, LessThanInvalid) {
- EXPECT_TRUE(RangeT() < RangeT(1, 0));
- EXPECT_TRUE(RangeT() < RangeT(2, 0));
- EXPECT_TRUE(RangeT(1, 0) < RangeT(2, 0));
-}
-
-TEST(RangeTest, EqualInvalid) {
- RangeT r;
- EXPECT_TRUE(r == RangeT());
- // Another invalid range, but with a different start.
- EXPECT_FALSE(r == RangeT(3, 0));
-}
-
-TEST(RangeTest, NotEqualInvalid) {
- RangeT r;
- EXPECT_FALSE(r != RangeT());
- EXPECT_FALSE(r == RangeT(3, 0));
-}
+++ /dev/null
-//===-- RegisterValueTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/RegisterValue.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using llvm::APInt;
-
-TEST(RegisterValueTest, GetSet8) {
- RegisterValue R8(uint8_t(47));
- EXPECT_EQ(47u, R8.GetAsUInt8());
- R8 = uint8_t(42);
- EXPECT_EQ(42u, R8.GetAsUInt8());
- EXPECT_EQ(42u, R8.GetAsUInt16());
- EXPECT_EQ(42u, R8.GetAsUInt32());
- EXPECT_EQ(42u, R8.GetAsUInt64());
-}
-
-TEST(RegisterValueTest, GetScalarValue) {
- using RV = RegisterValue;
- const auto &Get = [](const RV &V) -> llvm::Optional<Scalar> {
- Scalar S;
- if (V.GetScalarValue(S))
- return S;
- return llvm::None;
- };
- EXPECT_EQ(Get(RV(uint8_t(47))), Scalar(47));
- EXPECT_EQ(Get(RV(uint16_t(4747))), Scalar(4747));
- EXPECT_EQ(Get(RV(uint32_t(47474242))), Scalar(47474242));
- EXPECT_EQ(Get(RV(uint64_t(4747424247474242))), Scalar(4747424247474242));
- EXPECT_EQ(Get(RV(APInt::getMaxValue(128))), Scalar(APInt::getMaxValue(128)));
- EXPECT_EQ(Get(RV(47.5f)), Scalar(47.5f));
- EXPECT_EQ(Get(RV(47.5)), Scalar(47.5));
- EXPECT_EQ(Get(RV(47.5L)), Scalar(47.5L));
- EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc}, lldb::eByteOrderLittle)),
- Scalar(0xccddeeff));
- EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc}, lldb::eByteOrderBig)),
- Scalar(0xffeeddcc));
- EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66,
- 0x55, 0x44, 0x33, 0x22, 0x11, 0x00},
- lldb::eByteOrderLittle)),
- Scalar((APInt(128, 0x0011223344556677ull) << 64) |
- APInt(128, 0x8899aabbccddeeff)));
- EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66,
- 0x55, 0x44, 0x33, 0x22, 0x11, 0x00},
- lldb::eByteOrderBig)),
- Scalar((APInt(128, 0xffeeddccbbaa9988ull) << 64) |
- APInt(128, 0x7766554433221100)));
-}
+++ /dev/null
-//===-- RegularExpressionTest.cpp -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/RegularExpression.h"
-#include "llvm/ADT/SmallVector.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace llvm;
-
-TEST(RegularExpression, Valid) {
- RegularExpression r1("^[0-9]+$");
- cantFail(r1.GetError());
- EXPECT_TRUE(r1.IsValid());
- EXPECT_EQ("^[0-9]+$", r1.GetText());
- EXPECT_TRUE(r1.Execute("916"));
-}
-
-TEST(RegularExpression, CopyAssignment) {
- RegularExpression r1("^[0-9]+$");
- RegularExpression r2 = r1;
- cantFail(r2.GetError());
- EXPECT_TRUE(r2.IsValid());
- EXPECT_EQ("^[0-9]+$", r2.GetText());
- EXPECT_TRUE(r2.Execute("916"));
-}
-
-TEST(RegularExpression, Empty) {
- RegularExpression r1("");
- Error err = r1.GetError();
- EXPECT_TRUE(static_cast<bool>(err));
- consumeError(std::move(err));
- EXPECT_FALSE(r1.IsValid());
- EXPECT_EQ("", r1.GetText());
- EXPECT_FALSE(r1.Execute("916"));
-}
-
-TEST(RegularExpression, Invalid) {
- RegularExpression r1("a[b-");
- Error err = r1.GetError();
- EXPECT_TRUE(static_cast<bool>(err));
- consumeError(std::move(err));
- EXPECT_FALSE(r1.IsValid());
- EXPECT_EQ("a[b-", r1.GetText());
- EXPECT_FALSE(r1.Execute("ab"));
-}
-
-TEST(RegularExpression, Match) {
- RegularExpression r1("[0-9]+([a-f])?:([0-9]+)");
- cantFail(r1.GetError());
- EXPECT_TRUE(r1.IsValid());
- EXPECT_EQ("[0-9]+([a-f])?:([0-9]+)", r1.GetText());
-
- SmallVector<StringRef, 3> matches;
- EXPECT_TRUE(r1.Execute("9a:513b", &matches));
- EXPECT_EQ(3u, matches.size());
- EXPECT_EQ("9a:513", matches[0].str());
- EXPECT_EQ("a", matches[1].str());
- EXPECT_EQ("513", matches[2].str());
-}
+++ /dev/null
-//===-- ReproducerInstrumentationTest.cpp ---------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include <cmath>
-#include <limits>
-
-#include "lldb/Utility/ReproducerInstrumentation.h"
-
-using namespace lldb_private;
-using namespace lldb_private::repro;
-
-struct Foo {
- int m = 1;
-};
-struct Bar {
- double m = 2;
-};
-
-bool operator==(const Foo &LHS, const Foo &RHS) { return LHS.m == RHS.m; }
-bool operator==(const Bar &LHS, const Bar &RHS) { return LHS.m == RHS.m; }
-
-struct Pod {
- bool a = true;
- bool b = false;
- char c = 'a';
- float d = 1.1f;
- int e = 2;
- long long f = 3;
- long g = 4;
- short h = 5;
- unsigned char i = 'b';
- unsigned int j = 6;
- unsigned long long k = 7;
- unsigned long l = 8;
- unsigned short m = 9;
-
- Pod() {}
-};
-
-class TestingRegistry : public Registry {
-public:
- TestingRegistry();
-};
-
-static std::unique_ptr<TestingRegistry> g_registry;
-static llvm::Optional<Serializer> g_serializer;
-static llvm::Optional<Deserializer> g_deserializer;
-
-class TestInstrumentationData : public InstrumentationData {
-public:
- TestInstrumentationData() : InstrumentationData() {}
- TestInstrumentationData(Serializer &serializer, Registry ®istry)
- : InstrumentationData(serializer, registry) {}
- TestInstrumentationData(Deserializer &deserializer, Registry ®istry)
- : InstrumentationData(deserializer, registry) {}
-};
-
-inline TestInstrumentationData GetTestInstrumentationData() {
- assert(!(g_serializer && g_deserializer));
- if (g_serializer)
- return TestInstrumentationData(*g_serializer, *g_registry);
- if (g_deserializer)
- return TestInstrumentationData(*g_deserializer, *g_registry);
- return TestInstrumentationData();
-}
-
-class TestInstrumentationDataRAII {
-public:
- TestInstrumentationDataRAII(llvm::raw_string_ostream &os) {
- g_registry = std::make_unique<TestingRegistry>();
- g_serializer.emplace(os);
- g_deserializer.reset();
- }
-
- TestInstrumentationDataRAII(llvm::StringRef buffer) {
- g_registry = std::make_unique<TestingRegistry>();
- g_serializer.reset();
- g_deserializer.emplace(buffer);
- }
-
- ~TestInstrumentationDataRAII() { Reset(); }
-
- void Reset() {
- g_registry.reset();
- g_serializer.reset();
- g_deserializer.reset();
- }
-
- static std::unique_ptr<TestInstrumentationDataRAII>
- GetRecordingData(llvm::raw_string_ostream &os) {
- return std::make_unique<TestInstrumentationDataRAII>(os);
- }
-
- static std::unique_ptr<TestInstrumentationDataRAII>
- GetReplayData(llvm::StringRef buffer) {
- return std::make_unique<TestInstrumentationDataRAII>(buffer);
- }
-};
-
-#define LLDB_GET_INSTRUMENTATION_DATA() GetTestInstrumentationData()
-
-enum class Class {
- Foo,
- Bar,
-};
-
-class Instrumented {
-public:
- virtual ~Instrumented() = default;
- virtual void Validate() = 0;
- virtual bool IsA(Class c) = 0;
-};
-
-class InstrumentedFoo : public Instrumented {
-public:
- InstrumentedFoo() = default;
- /// Instrumented methods.
- /// {
- InstrumentedFoo(int i);
- InstrumentedFoo(const InstrumentedFoo &foo);
- InstrumentedFoo &operator=(const InstrumentedFoo &foo);
- void A(int a);
- int GetA();
- void B(int &b) const;
- int &GetB();
- int C(float *c);
- float GetC();
- int D(const char *d) const;
- size_t GetD(char *buffer, size_t length);
- static void E(double e);
- double GetE();
- static int F();
- bool GetF();
- void Validate() override;
- //// }
- virtual bool IsA(Class c) override { return c == Class::Foo; }
-
-private:
- int m_a = 0;
- mutable int m_b = 0;
- float m_c = 0;
- mutable std::string m_d = {};
- static double g_e;
- static bool g_f;
- mutable int m_called = 0;
-};
-
-class InstrumentedBar : public Instrumented {
-public:
- /// Instrumented methods.
- /// {
- InstrumentedBar();
- InstrumentedFoo GetInstrumentedFoo();
- InstrumentedFoo &GetInstrumentedFooRef();
- InstrumentedFoo *GetInstrumentedFooPtr();
- void SetInstrumentedFoo(InstrumentedFoo *foo);
- void SetInstrumentedFoo(InstrumentedFoo &foo);
- void Validate() override;
- /// }
- virtual bool IsA(Class c) override { return c == Class::Bar; }
-
-private:
- bool m_get_instrumend_foo_called = false;
- InstrumentedFoo *m_foo_set_by_ptr = nullptr;
- InstrumentedFoo *m_foo_set_by_ref = nullptr;
-};
-
-double InstrumentedFoo::g_e = 0;
-bool InstrumentedFoo::g_f = false;
-
-struct Validator {
- enum Validation { valid, invalid };
- Validator(Class clazz, Validation validation)
- : clazz(clazz), validation(validation) {}
- Class clazz;
- Validation validation;
-};
-
-void ValidateObjects(std::vector<void *> objects,
- std::vector<Validator> validators) {
- ASSERT_EQ(validators.size(), objects.size());
- for (size_t i = 0; i < validators.size(); ++i) {
- Validator &validator = validators[i];
- Instrumented *instrumented = static_cast<Instrumented *>(objects[i]);
- EXPECT_TRUE(instrumented->IsA(validator.clazz));
- switch (validator.validation) {
- case Validator::valid:
- instrumented->Validate();
- break;
- case Validator::invalid:
- break;
- }
- }
-}
-
-InstrumentedFoo::InstrumentedFoo(int i) {
- LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (int), i);
-}
-
-InstrumentedFoo::InstrumentedFoo(const InstrumentedFoo &foo) {
- LLDB_RECORD_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &), foo);
-}
-
-InstrumentedFoo &InstrumentedFoo::operator=(const InstrumentedFoo &foo) {
- LLDB_RECORD_METHOD(InstrumentedFoo &,
- InstrumentedFoo, operator=,(const InstrumentedFoo &), foo);
- return *this;
-}
-
-void InstrumentedFoo::A(int a) {
- LLDB_RECORD_METHOD(void, InstrumentedFoo, A, (int), a);
- B(a);
- m_a = a;
-}
-
-int InstrumentedFoo::GetA() {
- LLDB_RECORD_METHOD_NO_ARGS(int, InstrumentedFoo, GetA);
-
- return m_a;
-}
-
-void InstrumentedFoo::B(int &b) const {
- LLDB_RECORD_METHOD_CONST(void, InstrumentedFoo, B, (int &), b);
- m_called++;
- m_b = b;
-}
-
-int &InstrumentedFoo::GetB() {
- LLDB_RECORD_METHOD_NO_ARGS(int &, InstrumentedFoo, GetB);
-
- return m_b;
-}
-
-int InstrumentedFoo::C(float *c) {
- LLDB_RECORD_METHOD(int, InstrumentedFoo, C, (float *), c);
- m_c = *c;
- return 1;
-}
-
-float InstrumentedFoo::GetC() {
- LLDB_RECORD_METHOD_NO_ARGS(float, InstrumentedFoo, GetC);
-
- return m_c;
-}
-
-int InstrumentedFoo::D(const char *d) const {
- LLDB_RECORD_METHOD_CONST(int, InstrumentedFoo, D, (const char *), d);
- m_d = std::string(d);
- return 2;
-}
-
-size_t InstrumentedFoo::GetD(char *buffer, size_t length) {
- LLDB_RECORD_CHAR_PTR_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t),
- buffer, "", length);
- ::snprintf(buffer, length, "%s", m_d.c_str());
- return m_d.size();
-}
-
-void InstrumentedFoo::E(double e) {
- LLDB_RECORD_STATIC_METHOD(void, InstrumentedFoo, E, (double), e);
- g_e = e;
-}
-
-double InstrumentedFoo::GetE() {
- LLDB_RECORD_METHOD_NO_ARGS(double, InstrumentedFoo, GetE);
-
- return g_e;
-}
-
-int InstrumentedFoo::F() {
- LLDB_RECORD_STATIC_METHOD_NO_ARGS(int, InstrumentedFoo, F);
- g_f = true;
- return 3;
-}
-
-bool InstrumentedFoo::GetF() {
- LLDB_RECORD_METHOD_NO_ARGS(bool, InstrumentedFoo, GetF);
-
- return g_f;
-}
-
-void InstrumentedFoo::Validate() {
- LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedFoo, Validate);
- EXPECT_EQ(m_a, 100);
- EXPECT_EQ(m_b, 200);
- EXPECT_NEAR(m_c, 300.3, 0.01);
- EXPECT_EQ(m_d, "bar");
- EXPECT_NEAR(g_e, 400.4, 0.01);
- EXPECT_EQ(g_f, true);
- EXPECT_EQ(2, m_called);
-}
-
-InstrumentedBar::InstrumentedBar() {
- LLDB_RECORD_CONSTRUCTOR_NO_ARGS(InstrumentedBar);
-}
-
-InstrumentedFoo InstrumentedBar::GetInstrumentedFoo() {
- LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo, InstrumentedBar,
- GetInstrumentedFoo);
- m_get_instrumend_foo_called = true;
- return LLDB_RECORD_RESULT(InstrumentedFoo(0));
-}
-
-InstrumentedFoo &InstrumentedBar::GetInstrumentedFooRef() {
- LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo &, InstrumentedBar,
- GetInstrumentedFooRef);
- InstrumentedFoo *foo = new InstrumentedFoo(0);
- m_get_instrumend_foo_called = true;
- return LLDB_RECORD_RESULT(*foo);
-}
-
-InstrumentedFoo *InstrumentedBar::GetInstrumentedFooPtr() {
- LLDB_RECORD_METHOD_NO_ARGS(InstrumentedFoo *, InstrumentedBar,
- GetInstrumentedFooPtr);
- InstrumentedFoo *foo = new InstrumentedFoo(0);
- m_get_instrumend_foo_called = true;
- return LLDB_RECORD_RESULT(foo);
-}
-
-void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo *foo) {
- LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
- (InstrumentedFoo *), foo);
- m_foo_set_by_ptr = foo;
-}
-
-void InstrumentedBar::SetInstrumentedFoo(InstrumentedFoo &foo) {
- LLDB_RECORD_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
- (InstrumentedFoo &), foo);
- m_foo_set_by_ref = &foo;
-}
-
-void InstrumentedBar::Validate() {
- LLDB_RECORD_METHOD_NO_ARGS(void, InstrumentedBar, Validate);
-
- EXPECT_TRUE(m_get_instrumend_foo_called);
- EXPECT_NE(m_foo_set_by_ptr, nullptr);
- EXPECT_EQ(m_foo_set_by_ptr, m_foo_set_by_ref);
-}
-
-TestingRegistry::TestingRegistry() {
- Registry &R = *this;
-
- LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (int i));
- LLDB_REGISTER_CONSTRUCTOR(InstrumentedFoo, (const InstrumentedFoo &));
- LLDB_REGISTER_METHOD(InstrumentedFoo &,
- InstrumentedFoo, operator=,(const InstrumentedFoo &));
- LLDB_REGISTER_METHOD(void, InstrumentedFoo, A, (int));
- LLDB_REGISTER_METHOD_CONST(void, InstrumentedFoo, B, (int &));
- LLDB_REGISTER_METHOD(int, InstrumentedFoo, C, (float *));
- LLDB_REGISTER_METHOD_CONST(int, InstrumentedFoo, D, (const char *));
- LLDB_REGISTER_STATIC_METHOD(void, InstrumentedFoo, E, (double));
- LLDB_REGISTER_STATIC_METHOD(int, InstrumentedFoo, F, ());
- LLDB_REGISTER_METHOD(void, InstrumentedFoo, Validate, ());
-
- LLDB_REGISTER_CONSTRUCTOR(InstrumentedBar, ());
- LLDB_REGISTER_METHOD(InstrumentedFoo, InstrumentedBar, GetInstrumentedFoo,
- ());
- LLDB_REGISTER_METHOD(InstrumentedFoo &, InstrumentedBar,
- GetInstrumentedFooRef, ());
- LLDB_REGISTER_METHOD(InstrumentedFoo *, InstrumentedBar,
- GetInstrumentedFooPtr, ());
- LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
- (InstrumentedFoo *));
- LLDB_REGISTER_METHOD(void, InstrumentedBar, SetInstrumentedFoo,
- (InstrumentedFoo &));
- LLDB_REGISTER_METHOD(void, InstrumentedBar, Validate, ());
- LLDB_REGISTER_METHOD(int, InstrumentedFoo, GetA, ());
- LLDB_REGISTER_METHOD(int &, InstrumentedFoo, GetB, ());
- LLDB_REGISTER_METHOD(float, InstrumentedFoo, GetC, ());
- LLDB_REGISTER_METHOD(size_t, InstrumentedFoo, GetD, (char *, size_t));
- LLDB_REGISTER_METHOD(double, InstrumentedFoo, GetE, ());
- LLDB_REGISTER_METHOD(bool, InstrumentedFoo, GetF, ());
-}
-
-static const Pod p;
-
-TEST(IndexToObjectTest, ObjectForIndex) {
- IndexToObject index_to_object;
- Foo foo;
- Bar bar;
-
- EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Foo>(1));
- EXPECT_EQ(nullptr, index_to_object.GetObjectForIndex<Bar>(2));
-
- index_to_object.AddObjectForIndex<Foo>(1, foo);
- index_to_object.AddObjectForIndex<Bar>(2, &bar);
-
- EXPECT_EQ(&foo, index_to_object.GetObjectForIndex<Foo>(1));
- EXPECT_EQ(&bar, index_to_object.GetObjectForIndex<Bar>(2));
-}
-
-TEST(DeserializerTest, HasData) {
- {
- Deserializer deserializer("");
- EXPECT_FALSE(deserializer.HasData(1));
- }
-
- {
- Deserializer deserializer("a");
- EXPECT_TRUE(deserializer.HasData(1));
- EXPECT_FALSE(deserializer.HasData(2));
- }
-}
-
-TEST(SerializationRountripTest, SerializeDeserializePod) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
- p.l, p.m);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- EXPECT_EQ(p.a, deserializer.Deserialize<bool>());
- EXPECT_EQ(p.b, deserializer.Deserialize<bool>());
- EXPECT_EQ(p.c, deserializer.Deserialize<char>());
- EXPECT_EQ(p.d, deserializer.Deserialize<float>());
- EXPECT_EQ(p.e, deserializer.Deserialize<int>());
- EXPECT_EQ(p.f, deserializer.Deserialize<long long>());
- EXPECT_EQ(p.g, deserializer.Deserialize<long>());
- EXPECT_EQ(p.h, deserializer.Deserialize<short>());
- EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char>());
- EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int>());
- EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long>());
- EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long>());
- EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializePodPointers) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(&p.a, &p.b, &p.c, &p.d, &p.e, &p.f, &p.g, &p.h, &p.i,
- &p.j, &p.k, &p.l, &p.m);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- EXPECT_EQ(p.a, *deserializer.Deserialize<bool *>());
- EXPECT_EQ(p.b, *deserializer.Deserialize<bool *>());
- EXPECT_EQ(p.c, *deserializer.Deserialize<char *>());
- EXPECT_EQ(p.d, *deserializer.Deserialize<float *>());
- EXPECT_EQ(p.e, *deserializer.Deserialize<int *>());
- EXPECT_EQ(p.f, *deserializer.Deserialize<long long *>());
- EXPECT_EQ(p.g, *deserializer.Deserialize<long *>());
- EXPECT_EQ(p.h, *deserializer.Deserialize<short *>());
- EXPECT_EQ(p.i, *deserializer.Deserialize<unsigned char *>());
- EXPECT_EQ(p.j, *deserializer.Deserialize<unsigned int *>());
- EXPECT_EQ(p.k, *deserializer.Deserialize<unsigned long long *>());
- EXPECT_EQ(p.l, *deserializer.Deserialize<unsigned long *>());
- EXPECT_EQ(p.m, *deserializer.Deserialize<unsigned short *>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializePodReferences) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(p.a, p.b, p.c, p.d, p.e, p.f, p.g, p.h, p.i, p.j, p.k,
- p.l, p.m);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- EXPECT_EQ(p.a, deserializer.Deserialize<bool &>());
- EXPECT_EQ(p.b, deserializer.Deserialize<bool &>());
- EXPECT_EQ(p.c, deserializer.Deserialize<char &>());
- EXPECT_EQ(p.d, deserializer.Deserialize<float &>());
- EXPECT_EQ(p.e, deserializer.Deserialize<int &>());
- EXPECT_EQ(p.f, deserializer.Deserialize<long long &>());
- EXPECT_EQ(p.g, deserializer.Deserialize<long &>());
- EXPECT_EQ(p.h, deserializer.Deserialize<short &>());
- EXPECT_EQ(p.i, deserializer.Deserialize<unsigned char &>());
- EXPECT_EQ(p.j, deserializer.Deserialize<unsigned int &>());
- EXPECT_EQ(p.k, deserializer.Deserialize<unsigned long long &>());
- EXPECT_EQ(p.l, deserializer.Deserialize<unsigned long &>());
- EXPECT_EQ(p.m, deserializer.Deserialize<unsigned short &>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeCString) {
- const char *cstr = "string";
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(cstr);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- EXPECT_STREQ(cstr, deserializer.Deserialize<const char *>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeCStringNull) {
- const char *cstr = nullptr;
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(cstr);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- EXPECT_EQ(nullptr, deserializer.Deserialize<const char *>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeCStringArray) {
- const char *foo = "foo";
- const char *bar = "bar";
- const char *baz = "baz";
- const char *arr[4] = {foo, bar, baz, nullptr};
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(static_cast<const char **>(arr));
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- const char **deserialized = deserializer.Deserialize<const char **>();
- EXPECT_STREQ("foo", deserialized[0]);
- EXPECT_STREQ("bar", deserialized[1]);
- EXPECT_STREQ("baz", deserialized[2]);
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeCStringArrayNullptrElem) {
- const char *arr[1] = {nullptr};
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(static_cast<const char **>(arr));
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- const char **deserialized = deserializer.Deserialize<const char **>();
- EXPECT_EQ(nullptr, deserialized);
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeCStringArrayNullptr) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- Serializer serializer(os);
- serializer.SerializeAll(static_cast<const char **>(nullptr));
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- const char **deserialized = deserializer.Deserialize<const char **>();
- EXPECT_EQ(nullptr, deserialized);
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeObjectPointer) {
- Foo foo;
- Bar bar;
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- unsigned sequence = 123;
-
- Serializer serializer(os);
- serializer.SerializeAll(sequence, static_cast<unsigned>(1));
- serializer.SerializeAll(sequence, static_cast<unsigned>(2));
- serializer.SerializeAll(&foo, &bar);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- deserializer.HandleReplayResult(&foo);
- deserializer.HandleReplayResult(&bar);
-
- EXPECT_EQ(foo, *deserializer.Deserialize<Foo *>());
- EXPECT_EQ(bar, *deserializer.Deserialize<Bar *>());
-}
-
-TEST(SerializationRountripTest, SerializeDeserializeObjectReference) {
- Foo foo;
- Bar bar;
-
- std::string str;
- llvm::raw_string_ostream os(str);
-
- unsigned sequence = 123;
-
- Serializer serializer(os);
- serializer.SerializeAll(sequence, static_cast<unsigned>(1));
- serializer.SerializeAll(sequence, static_cast<unsigned>(2));
- serializer.SerializeAll(foo, bar);
-
- llvm::StringRef buffer(os.str());
- Deserializer deserializer(buffer);
-
- deserializer.HandleReplayResult(&foo);
- deserializer.HandleReplayResult(&bar);
-
- EXPECT_EQ(foo, deserializer.Deserialize<Foo &>());
- EXPECT_EQ(bar, deserializer.Deserialize<Bar &>());
-}
-
-TEST(RecordReplayTest, InstrumentedFoo) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- InstrumentedFoo foo(0);
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-
- ValidateObjects(deserializer.GetAllObjects(),
- {{Class::Foo, Validator::valid}});
-}
-
-TEST(RecordReplayTest, InstrumentedFooSameThis) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- InstrumentedFoo *foo = new InstrumentedFoo(0);
- foo->A(100);
- foo->B(b);
- foo->C(&c);
- foo->D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo->Validate();
- foo->~InstrumentedFoo();
-
- InstrumentedFoo *foo2 = new (foo) InstrumentedFoo(0);
- foo2->A(100);
- foo2->B(b);
- foo2->C(&c);
- foo2->D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo2->Validate();
- delete foo2;
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-
- ValidateObjects(deserializer.GetAllObjects(),
- {{Class::Foo, Validator::valid}});
-}
-
-TEST(RecordReplayTest, InstrumentedBar) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo foo = bar.GetInstrumentedFoo();
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-
- ValidateObjects(
- deserializer.GetAllObjects(),
- {
- {Class::Bar, Validator::valid}, // bar
- {Class::Foo, Validator::invalid}, // bar.GetInstrumentedFoo()
- {Class::Foo, Validator::valid}, // foo
- });
-}
-
-TEST(RecordReplayTest, InstrumentedBarRef) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-
- ValidateObjects(
- deserializer.GetAllObjects(),
- {{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
-}
-
-TEST(RecordReplayTest, InstrumentedBarPtr) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-
- ValidateObjects(
- deserializer.GetAllObjects(),
- {{Class::Bar, Validator::valid}, {Class::Foo, Validator::valid}});
-}
-
-TEST(PassiveReplayTest, InstrumentedFoo) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- InstrumentedFoo foo(0);
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
- }
-
- std::string buffer = os.str();
-
- {
- auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
-
- int b = 999;
- float c = 999.9f;
- double e = 999.9;
-
- InstrumentedFoo foo(9);
- foo.A(999);
- foo.B(b);
- foo.C(&c);
- foo.D("999");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
- }
-}
-
-TEST(PassiveReplayTest, InstrumentedFooInvalid) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- InstrumentedFoo foo(0);
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
- }
-
- std::string buffer = os.str();
-
- {
- auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
-
- int b = 999;
- float c = 999.9f;
- double e = 999.9;
-
- InstrumentedFoo foo(9);
- foo.A(999);
- foo.B(b);
- foo.C(&c);
- foo.D("999");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- // Detect divergence.
- EXPECT_DEATH(foo.GetA(), "");
- }
-}
-
-TEST(PassiveReplayTest, InstrumentedBar) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo foo = bar.GetInstrumentedFoo();
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- std::string buffer = os.str();
-
- {
- auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
-
- InstrumentedBar bar;
- InstrumentedFoo foo = bar.GetInstrumentedFoo();
-
- int b = 99;
- float c = 999.9f;
- double e = 999.9;
-
- foo.A(999);
- foo.B(b);
- foo.C(&c);
- foo.D("999");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-}
-
-TEST(PassiveReplayTest, InstrumentedBarRef) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- std::string buffer = os.str();
-
- {
- auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = bar.GetInstrumentedFooRef();
-
- int b = 99;
- float c = 999.9f;
- double e = 999.9;
-
- foo.A(999);
- foo.B(b);
- foo.C(&c);
- foo.D("999");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-}
-
-TEST(PassiveReplayTest, InstrumentedBarPtr) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
-
- int b = 200;
- float c = 300.3f;
- double e = 400.4;
-
- foo.A(100);
- foo.B(b);
- foo.C(&c);
- foo.D("bar");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-
- std::string buffer = os.str();
-
- {
- auto data = TestInstrumentationDataRAII::GetReplayData(buffer);
-
- InstrumentedBar bar;
- InstrumentedFoo &foo = *(bar.GetInstrumentedFooPtr());
-
- int b = 99;
- float c = 999.9f;
- double e = 999.9;
-
- foo.A(999);
- foo.B(b);
- foo.C(&c);
- foo.D("999");
- InstrumentedFoo::E(e);
- InstrumentedFoo::F();
- foo.Validate();
-
- EXPECT_EQ(foo.GetA(), 100);
- EXPECT_EQ(foo.GetB(), 200);
- EXPECT_NEAR(foo.GetC(), 300.3, 0.01);
- char buffer[100];
- foo.GetD(buffer, 100);
- EXPECT_STREQ(buffer, "bar");
- EXPECT_NEAR(foo.GetE(), 400.4, 0.01);
- EXPECT_EQ(foo.GetF(), true);
-
- bar.SetInstrumentedFoo(foo);
- bar.SetInstrumentedFoo(&foo);
- bar.Validate();
- }
-}
-
-TEST(RecordReplayTest, ValidSequence) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- unsigned sequence = 1;
- int (*f)() = &lldb_private::repro::invoke<int (*)()>::method<
- InstrumentedFoo::F>::record;
- unsigned id = g_registry->GetID(uintptr_t(f));
- g_serializer->SerializeAll(sequence, id);
-
- unsigned result = 0;
- g_serializer->SerializeAll(sequence, result);
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- registry.Replay(deserializer);
-}
-
-TEST(RecordReplayTest, InvalidSequence) {
- std::string str;
- llvm::raw_string_ostream os(str);
-
- {
- auto data = TestInstrumentationDataRAII::GetRecordingData(os);
-
- unsigned sequence = 1;
- int (*f)() = &lldb_private::repro::invoke<int (*)()>::method<
- InstrumentedFoo::F>::record;
- unsigned id = g_registry->GetID(uintptr_t(f));
- g_serializer->SerializeAll(sequence, id);
-
- unsigned result = 0;
- unsigned invalid_sequence = 2;
- g_serializer->SerializeAll(invalid_sequence, result);
- }
-
- TestingRegistry registry;
- Deserializer deserializer(os.str());
- EXPECT_DEATH(registry.Replay(deserializer), "");
-}
+++ /dev/null
-//===-- ReproducerTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Reproducer.h"
-#include "lldb/Utility/ReproducerProvider.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace llvm;
-using namespace lldb_private;
-using namespace lldb_private::repro;
-
-class DummyProvider : public repro::Provider<DummyProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- DummyProvider(const FileSpec &directory) : Provider(directory) {}
-
- static char ID;
-};
-
-class YamlMultiProvider
- : public MultiProvider<YamlRecorder, YamlMultiProvider> {
-public:
- struct Info {
- static const char *name;
- static const char *file;
- };
-
- YamlMultiProvider(const FileSpec &directory) : MultiProvider(directory) {}
-
- static char ID;
-};
-
-const char *DummyProvider::Info::name = "dummy";
-const char *DummyProvider::Info::file = "dummy.yaml";
-const char *YamlMultiProvider::Info::name = "mutli";
-const char *YamlMultiProvider::Info::file = "mutli.yaml";
-char DummyProvider::ID = 0;
-char YamlMultiProvider::ID = 0;
-
-class DummyReproducer : public Reproducer {
-public:
- DummyReproducer() : Reproducer(){};
-
- using Reproducer::SetCapture;
- using Reproducer::SetReplay;
-};
-
-struct YamlData {
- YamlData() : i(-1) {}
- YamlData(int i) : i(i) {}
- int i;
-};
-
-inline bool operator==(const YamlData &LHS, const YamlData &RHS) {
- return LHS.i == RHS.i;
-}
-
-LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(YamlData)
-
-namespace llvm {
-namespace yaml {
-template <> struct MappingTraits<YamlData> {
- static void mapping(IO &io, YamlData &Y) { io.mapRequired("i", Y.i); };
-};
-} // namespace yaml
-} // namespace llvm
-
-TEST(ReproducerTest, SetCapture) {
- DummyReproducer reproducer;
-
- // Initially both generator and loader are unset.
- EXPECT_EQ(nullptr, reproducer.GetGenerator());
- EXPECT_EQ(nullptr, reproducer.GetLoader());
-
- // Enable capture and check that means we have a generator.
- EXPECT_THAT_ERROR(
- reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Succeeded());
- EXPECT_NE(nullptr, reproducer.GetGenerator());
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- reproducer.GetGenerator()->GetRoot());
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- reproducer.GetReproducerPath());
-
- // Ensure that we cannot enable replay.
- EXPECT_THAT_ERROR(
- reproducer.SetReplay(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Failed());
- EXPECT_EQ(nullptr, reproducer.GetLoader());
-
- // Ensure we can disable the generator again.
- EXPECT_THAT_ERROR(reproducer.SetCapture(llvm::None), Succeeded());
- EXPECT_EQ(nullptr, reproducer.GetGenerator());
- EXPECT_EQ(nullptr, reproducer.GetLoader());
-}
-
-TEST(ReproducerTest, SetReplay) {
- DummyReproducer reproducer;
-
- // Initially both generator and loader are unset.
- EXPECT_EQ(nullptr, reproducer.GetGenerator());
- EXPECT_EQ(nullptr, reproducer.GetLoader());
-
- // Expected to fail because we can't load the index.
- EXPECT_THAT_ERROR(
- reproducer.SetReplay(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Failed());
- // However the loader should still be set, which we check here.
- EXPECT_NE(nullptr, reproducer.GetLoader());
-
- // Make sure the bogus path is correctly set.
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- reproducer.GetLoader()->GetRoot());
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- reproducer.GetReproducerPath());
-
- // Ensure that we cannot enable replay.
- EXPECT_THAT_ERROR(
- reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Failed());
- EXPECT_EQ(nullptr, reproducer.GetGenerator());
-}
-
-TEST(GeneratorTest, Create) {
- DummyReproducer reproducer;
-
- EXPECT_THAT_ERROR(
- reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Succeeded());
- auto &generator = *reproducer.GetGenerator();
-
- auto *provider = generator.Create<DummyProvider>();
- EXPECT_NE(nullptr, provider);
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- provider->GetRoot());
-}
-
-TEST(GeneratorTest, Get) {
- DummyReproducer reproducer;
-
- EXPECT_THAT_ERROR(
- reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Succeeded());
- auto &generator = *reproducer.GetGenerator();
-
- auto *provider = generator.Create<DummyProvider>();
- EXPECT_NE(nullptr, provider);
-
- auto *provider_alt = generator.Get<DummyProvider>();
- EXPECT_EQ(provider, provider_alt);
-}
-
-TEST(GeneratorTest, GetOrCreate) {
- DummyReproducer reproducer;
-
- EXPECT_THAT_ERROR(
- reproducer.SetCapture(FileSpec("//bogus/path", FileSpec::Style::posix)),
- Succeeded());
- auto &generator = *reproducer.GetGenerator();
-
- auto &provider = generator.GetOrCreate<DummyProvider>();
- EXPECT_EQ(FileSpec("//bogus/path", FileSpec::Style::posix),
- provider.GetRoot());
-
- auto &provider_alt = generator.GetOrCreate<DummyProvider>();
- EXPECT_EQ(&provider, &provider_alt);
-}
-
-TEST(GeneratorTest, YamlMultiProvider) {
- SmallString<128> root;
- std::error_code ec = llvm::sys::fs::createUniqueDirectory("reproducer", root);
- ASSERT_FALSE(static_cast<bool>(ec));
-
- auto cleanup = llvm::make_scope_exit(
- [&] { EXPECT_FALSE(llvm::sys::fs::remove_directories(root.str())); });
-
- YamlData data0(0);
- YamlData data1(1);
- YamlData data2(2);
- YamlData data3(3);
-
- {
- DummyReproducer reproducer;
- EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec(root.str())), Succeeded());
-
- auto &generator = *reproducer.GetGenerator();
- auto *provider = generator.Create<YamlMultiProvider>();
- ASSERT_NE(nullptr, provider);
-
- auto *recorder = provider->GetNewRecorder();
- ASSERT_NE(nullptr, recorder);
- recorder->Record(data0);
- recorder->Record(data1);
-
- recorder = provider->GetNewRecorder();
- ASSERT_NE(nullptr, recorder);
- recorder->Record(data2);
- recorder->Record(data3);
-
- generator.Keep();
- }
-
- {
- DummyReproducer reproducer;
- EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec(root.str())), Succeeded());
-
- auto &loader = *reproducer.GetLoader();
- std::unique_ptr<repro::MultiLoader<YamlMultiProvider>> multi_loader =
- repro::MultiLoader<YamlMultiProvider>::Create(&loader);
-
- // Read the first file.
- {
- llvm::Optional<std::string> file = multi_loader->GetNextFile();
- EXPECT_TRUE(static_cast<bool>(file));
-
- auto buffer = llvm::MemoryBuffer::getFile(*file);
- EXPECT_TRUE(static_cast<bool>(buffer));
-
- yaml::Input yin((*buffer)->getBuffer());
- std::vector<YamlData> data;
- yin >> data;
-
- ASSERT_EQ(data.size(), 2U);
- EXPECT_THAT(data, testing::ElementsAre(data0, data1));
- }
-
- // Read the second file.
- {
- llvm::Optional<std::string> file = multi_loader->GetNextFile();
- EXPECT_TRUE(static_cast<bool>(file));
-
- auto buffer = llvm::MemoryBuffer::getFile(*file);
- EXPECT_TRUE(static_cast<bool>(buffer));
-
- yaml::Input yin((*buffer)->getBuffer());
- std::vector<YamlData> data;
- yin >> data;
-
- ASSERT_EQ(data.size(), 2U);
- EXPECT_THAT(data, testing::ElementsAre(data2, data3));
- }
-
- // There is no third file.
- llvm::Optional<std::string> file = multi_loader->GetNextFile();
- EXPECT_FALSE(static_cast<bool>(file));
- }
-}
+++ /dev/null
-//===-- ScalarTest.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/Endian.h"
-#include "lldb/Utility/Scalar.h"
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/StreamString.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private;
-using llvm::APFloat;
-using llvm::APInt;
-using llvm::Failed;
-using llvm::Succeeded;
-
-template <typename T>
-bool checkInequality(T c1, T c2) {
- return (Scalar(c1) != Scalar(c2));
-}
-
-template <typename T>
-bool checkEquality(T c1, T c2) {
- return (Scalar(c1) == Scalar(c2));
-}
-
-TEST(ScalarTest, Equality) {
- ASSERT_TRUE(checkInequality<int>(23, 24));
- ASSERT_TRUE(checkEquality<int>(96, 96));
- ASSERT_TRUE(checkInequality<float>(4.0f, 4.5f));
- ASSERT_TRUE(checkEquality<float>(4.0f, 4.0f));
-
- auto apint1 = APInt(64, 234);
- auto apint2 = APInt(64, 246);
- ASSERT_TRUE(checkInequality<APInt>(apint1, apint2));
- ASSERT_TRUE(checkEquality<APInt>(apint1, apint1));
-
- Scalar void1;
- Scalar void2;
- float f1 = 2.0;
- ASSERT_TRUE(void1 == void2);
- ASSERT_FALSE(void1 == Scalar(f1));
-}
-
-TEST(ScalarTest, Comparison) {
- auto s1 = Scalar(23);
- auto s2 = Scalar(46);
- ASSERT_TRUE(s1 < s2);
- ASSERT_TRUE(s1 <= s2);
- ASSERT_TRUE(s2 > s1);
- ASSERT_TRUE(s2 >= s1);
-}
-
-TEST(ScalarTest, ComparisonFloat) {
- auto s1 = Scalar(23.0f);
- auto s2 = Scalar(46.0f);
- ASSERT_TRUE(s1 < s2);
- ASSERT_TRUE(s1 <= s2);
- ASSERT_TRUE(s2 > s1);
- ASSERT_TRUE(s2 >= s1);
-}
-
-template <typename T> static void CheckConversion(T val) {
- SCOPED_TRACE("val = " + std::to_string(val));
- EXPECT_EQ((signed char)val, Scalar(val).SChar());
- EXPECT_EQ((unsigned char)val, Scalar(val).UChar());
- EXPECT_EQ((short)val, Scalar(val).SShort());
- EXPECT_EQ((unsigned short)val, Scalar(val).UShort());
- EXPECT_EQ((int)val, Scalar(val).SInt());
- EXPECT_EQ((unsigned)val, Scalar(val).UInt());
- EXPECT_EQ((long)val, Scalar(val).SLong());
- EXPECT_EQ((unsigned long)val, Scalar(val).ULong());
- EXPECT_EQ((long long)val, Scalar(val).SLongLong());
- EXPECT_EQ((unsigned long long)val, Scalar(val).ULongLong());
- EXPECT_NEAR((float)val, Scalar(val).Float(), std::abs(val / 1e6));
- EXPECT_NEAR((double)val, Scalar(val).Double(), std::abs(val / 1e12));
- EXPECT_NEAR((long double)val, Scalar(val).LongDouble(), std::abs(val / 1e12));
-}
-
-TEST(ScalarTest, Getters) {
- CheckConversion<int>(0x87654321);
- CheckConversion<unsigned int>(0x87654321u);
- CheckConversion<long>(0x87654321l);
- CheckConversion<unsigned long>(0x87654321ul);
- CheckConversion<long long>(0x8765432112345678ll);
- CheckConversion<unsigned long long>(0x8765432112345678ull);
- CheckConversion<float>(42.25f);
- CheckConversion<double>(42.25);
- CheckConversion<long double>(42.25L);
-
- EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0f, 70.0f)).SInt128(APInt()));
- EXPECT_EQ(APInt(128, -1, true) << 70,
- Scalar(-std::pow(2.0f, 70.0f)).SInt128(APInt()));
- EXPECT_EQ(APInt(128, 1) << 70,
- Scalar(std::pow(2.0f, 70.0f)).UInt128(APInt()));
- EXPECT_EQ(APInt(128, 0), Scalar(-std::pow(2.0f, 70.0f)).UInt128(APInt()));
-
- EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0, 70.0)).SInt128(APInt()));
- EXPECT_EQ(APInt(128, -1, true) << 70,
- Scalar(-std::pow(2.0, 70.0)).SInt128(APInt()));
- EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0, 70.0)).UInt128(APInt()));
- EXPECT_EQ(APInt(128, 0), Scalar(-std::pow(2.0, 70.0)).UInt128(APInt()));
-}
-
-TEST(ScalarTest, RightShiftOperator) {
- int a = 0x00001000;
- int b = 0xFFFFFFFF;
- int c = 4;
- Scalar a_scalar(a);
- Scalar b_scalar(b);
- Scalar c_scalar(c);
- ASSERT_EQ(a >> c, a_scalar >> c_scalar);
- ASSERT_EQ(b >> c, b_scalar >> c_scalar);
-}
-
-TEST(ScalarTest, GetBytes) {
- uint8_t Storage[256];
- int a = 0x01020304;
- long long b = 0x0102030405060708LL;
- float c = 1234567.89e32f;
- double d = 1234567.89e42;
- char e[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- char f[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
- Scalar a_scalar(a);
- Scalar b_scalar(b);
- Scalar c_scalar(c);
- Scalar d_scalar(d);
- Scalar e_scalar;
- Scalar f_scalar;
- DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(),
- sizeof(void *));
- DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(),
- sizeof(void *));
- a_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(&a, Storage, sizeof(a)));
- b_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(&b, Storage, sizeof(b)));
- c_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(&c, Storage, sizeof(c)));
- d_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(&d, Storage, sizeof(d)));
- ASSERT_THAT_ERROR(
- e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e))
- .ToError(),
- llvm::Succeeded());
- e_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(e, Storage, sizeof(e)));
- ASSERT_THAT_ERROR(
- f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f))
- .ToError(),
- llvm::Succeeded());
- f_scalar.GetBytes(Storage);
- ASSERT_EQ(0, memcmp(f, Storage, sizeof(f)));
-}
-
-TEST(ScalarTest, SetValueFromData) {
- uint8_t a[] = {1, 2, 3, 4};
- Scalar s;
- ASSERT_THAT_ERROR(
- s.SetValueFromData(
- DataExtractor(a, sizeof(a), lldb::eByteOrderLittle, sizeof(void *)),
- lldb::eEncodingSint, sizeof(a))
- .ToError(),
- llvm::Succeeded());
- EXPECT_EQ(0x04030201, s);
- ASSERT_THAT_ERROR(
- s.SetValueFromData(
- DataExtractor(a, sizeof(a), lldb::eByteOrderBig, sizeof(void *)),
- lldb::eEncodingSint, sizeof(a))
- .ToError(),
- llvm::Succeeded());
- EXPECT_EQ(0x01020304, s);
-}
-
-TEST(ScalarTest, CastOperations) {
- long long a = 0xf1f2f3f4f5f6f7f8LL;
- Scalar a_scalar(a);
- EXPECT_EQ((signed char)a, a_scalar.SChar());
- EXPECT_EQ((unsigned char)a, a_scalar.UChar());
- EXPECT_EQ((signed short)a, a_scalar.SShort());
- EXPECT_EQ((unsigned short)a, a_scalar.UShort());
- EXPECT_EQ((signed int)a, a_scalar.SInt());
- EXPECT_EQ((unsigned int)a, a_scalar.UInt());
- EXPECT_EQ((signed long)a, a_scalar.SLong());
- EXPECT_EQ((unsigned long)a, a_scalar.ULong());
- EXPECT_EQ((signed long long)a, a_scalar.SLongLong());
- EXPECT_EQ((unsigned long long)a, a_scalar.ULongLong());
-
- int a2 = 23;
- Scalar a2_scalar(a2);
- EXPECT_EQ((float)a2, a2_scalar.Float());
- EXPECT_EQ((double)a2, a2_scalar.Double());
- EXPECT_EQ((long double)a2, a2_scalar.LongDouble());
-
- EXPECT_EQ(std::numeric_limits<unsigned int>::min(), Scalar(-1.0f).UInt());
- EXPECT_EQ(std::numeric_limits<unsigned int>::max(), Scalar(1e11f).UInt());
- EXPECT_EQ(std::numeric_limits<unsigned long long>::min(),
- Scalar(-1.0).ULongLong());
- EXPECT_EQ(std::numeric_limits<unsigned long long>::max(),
- Scalar(1e22).ULongLong());
-
- EXPECT_EQ(std::numeric_limits<int>::min(), Scalar(-1e11f).SInt());
- EXPECT_EQ(std::numeric_limits<int>::max(), Scalar(1e11f).SInt());
- EXPECT_EQ(std::numeric_limits<long long>::min(), Scalar(-1e22).SLongLong());
- EXPECT_EQ(std::numeric_limits<long long>::max(), Scalar(1e22).SLongLong());
-}
-
-TEST(ScalarTest, ExtractBitfield) {
- uint32_t len = sizeof(long long) * 8;
-
- long long a1 = 0xf1f2f3f4f5f6f7f8LL;
- long long b1 = 0xff1f2f3f4f5f6f7fLL;
- Scalar s_scalar(a1);
- ASSERT_TRUE(s_scalar.ExtractBitfield(0, 0));
- EXPECT_EQ(s_scalar, a1);
- ASSERT_TRUE(s_scalar.ExtractBitfield(len, 0));
- EXPECT_EQ(s_scalar, a1);
- ASSERT_TRUE(s_scalar.ExtractBitfield(len - 4, 4));
- EXPECT_EQ(s_scalar, b1);
-
- unsigned long long a2 = 0xf1f2f3f4f5f6f7f8ULL;
- unsigned long long b2 = 0x0f1f2f3f4f5f6f7fULL;
- Scalar u_scalar(a2);
- ASSERT_TRUE(u_scalar.ExtractBitfield(0, 0));
- EXPECT_EQ(u_scalar, a2);
- ASSERT_TRUE(u_scalar.ExtractBitfield(len, 0));
- EXPECT_EQ(u_scalar, a2);
- ASSERT_TRUE(u_scalar.ExtractBitfield(len - 4, 4));
- EXPECT_EQ(u_scalar, b2);
-}
-
-template <typename T> static std::string ScalarGetValue(T value) {
- StreamString stream;
- Scalar(value).GetValue(&stream, false);
- return std::string(stream.GetString());
-}
-
-TEST(ScalarTest, GetValue) {
- EXPECT_EQ("12345", ScalarGetValue<signed short>(12345));
- EXPECT_EQ("-12345", ScalarGetValue<signed short>(-12345));
- EXPECT_EQ("12345", ScalarGetValue<unsigned short>(12345));
- EXPECT_EQ(std::to_string(std::numeric_limits<unsigned short>::max()),
- ScalarGetValue(std::numeric_limits<unsigned short>::max()));
-
- EXPECT_EQ("12345", ScalarGetValue<signed int>(12345));
- EXPECT_EQ("-12345", ScalarGetValue<signed int>(-12345));
- EXPECT_EQ("12345", ScalarGetValue<unsigned int>(12345));
- EXPECT_EQ(std::to_string(std::numeric_limits<unsigned int>::max()),
- ScalarGetValue(std::numeric_limits<unsigned int>::max()));
-
- EXPECT_EQ("12345678", ScalarGetValue<signed long>(12345678L));
- EXPECT_EQ("-12345678", ScalarGetValue<signed long>(-12345678L));
- EXPECT_EQ("12345678", ScalarGetValue<unsigned long>(12345678UL));
- EXPECT_EQ(std::to_string(std::numeric_limits<unsigned long>::max()),
- ScalarGetValue(std::numeric_limits<unsigned long>::max()));
-
- EXPECT_EQ("1234567890123", ScalarGetValue<signed long long>(1234567890123LL));
- EXPECT_EQ("-1234567890123",
- ScalarGetValue<signed long long>(-1234567890123LL));
- EXPECT_EQ("1234567890123",
- ScalarGetValue<unsigned long long>(1234567890123ULL));
- EXPECT_EQ(std::to_string(std::numeric_limits<unsigned long long>::max()),
- ScalarGetValue(std::numeric_limits<unsigned long long>::max()));
-}
-
-TEST(ScalarTest, LongLongAssigmentOperator) {
- Scalar ull;
- ull = std::numeric_limits<unsigned long long>::max();
- EXPECT_EQ(std::numeric_limits<unsigned long long>::max(), ull.ULongLong());
-
- Scalar sll;
- sll = std::numeric_limits<signed long long>::max();
- EXPECT_EQ(std::numeric_limits<signed long long>::max(), sll.SLongLong());
-}
-
-TEST(ScalarTest, Division) {
- Scalar lhs(5.0);
- Scalar rhs(2.0);
- Scalar r = lhs / rhs;
- EXPECT_TRUE(r.IsValid());
- EXPECT_EQ(r, Scalar(2.5));
-}
-
-TEST(ScalarTest, Promotion) {
- Scalar a(47);
- EXPECT_TRUE(a.IntegralPromote(64, true));
- EXPECT_TRUE(a.IsSigned());
- EXPECT_EQ(APInt(64, 47), a.UInt128(APInt()));
-
- EXPECT_FALSE(a.IntegralPromote(32, true));
- EXPECT_FALSE(a.IntegralPromote(32, false));
- EXPECT_TRUE(a.IsSigned());
-
- EXPECT_TRUE(a.IntegralPromote(64, false));
- EXPECT_FALSE(a.IsSigned());
- EXPECT_EQ(APInt(64, 47), a.UInt128(APInt()));
-
- EXPECT_FALSE(a.IntegralPromote(64, true));
-
- EXPECT_TRUE(a.FloatPromote(APFloat::IEEEdouble()));
- EXPECT_EQ(Scalar::e_float, a.GetType());
- EXPECT_EQ(47.0, a.Double());
-
- EXPECT_FALSE(a.FloatPromote(APFloat::IEEEsingle()));
- EXPECT_TRUE(a.FloatPromote(APFloat::x87DoubleExtended()));
- EXPECT_EQ(47.0L, a.LongDouble());
-}
-
-TEST(ScalarTest, SetValueFromCString) {
- Scalar a;
-
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("1234567890123", lldb::eEncodingUint, 8).ToError(),
- Succeeded());
- EXPECT_EQ(1234567890123ull, a);
-
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("-1234567890123", lldb::eEncodingSint, 8).ToError(),
- Succeeded());
- EXPECT_EQ(-1234567890123ll, a);
-
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("asdf", lldb::eEncodingSint, 8).ToError(),
- Failed());
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("asdf", lldb::eEncodingUint, 8).ToError(),
- Failed());
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("1234567890123", lldb::eEncodingUint, 4).ToError(),
- Failed());
- EXPECT_THAT_ERROR(a.SetValueFromCString("123456789012345678901234567890",
- lldb::eEncodingUint, 8)
- .ToError(),
- Failed());
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("-123", lldb::eEncodingUint, 8).ToError(),
- Failed());
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("-2147483648", lldb::eEncodingSint, 4).ToError(),
- Succeeded());
- EXPECT_EQ(-2147483648, a);
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("-2147483649", lldb::eEncodingSint, 4).ToError(),
- Failed());
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("47.25", lldb::eEncodingIEEE754, 4).ToError(),
- Succeeded());
- EXPECT_EQ(47.25f, a);
- EXPECT_THAT_ERROR(
- a.SetValueFromCString("asdf", lldb::eEncodingIEEE754, 4).ToError(),
- Failed());
-}
-
-TEST(ScalarTest, APIntConstructor) {
- for (auto &width : {8, 16, 32}) {
- Scalar A(APInt(width, 24));
- EXPECT_TRUE(A.IsSigned());
- EXPECT_EQ(A.GetType(), Scalar::e_int);
- EXPECT_EQ(APInt(width, 24), A.UInt128(APInt()));
- }
-}
-
-TEST(ScalarTest, Scalar_512) {
- Scalar Z(APInt(512, 0));
- ASSERT_TRUE(Z.IsZero());
- Z.MakeUnsigned();
- ASSERT_TRUE(Z.IsZero());
-
- Scalar S(APInt(512, 2000));
- ASSERT_STREQ(S.GetTypeAsCString(), "int");
-
- ASSERT_TRUE(S.MakeUnsigned());
- EXPECT_EQ(S.GetType(), Scalar::e_int);
- EXPECT_FALSE(S.IsSigned());
- ASSERT_STREQ(S.GetTypeAsCString(), "int");
- EXPECT_EQ(S.GetByteSize(), 64U);
-
- ASSERT_TRUE(S.MakeSigned());
- EXPECT_EQ(S.GetType(), Scalar::e_int);
- EXPECT_TRUE(S.IsSigned());
- EXPECT_EQ(S.GetByteSize(), 64U);
-}
-
-TEST(ScalarTest, TruncOrExtendTo) {
- Scalar S(0xffff);
- S.TruncOrExtendTo(12, true);
- EXPECT_EQ(S.UInt128(APInt()), APInt(12, 0xfffu));
- S.TruncOrExtendTo(20, true);
- EXPECT_EQ(S.UInt128(APInt()), APInt(20, 0xfffffu));
- S.TruncOrExtendTo(24, false);
- EXPECT_EQ(S.UInt128(APInt()), APInt(24, 0x0fffffu));
- S.TruncOrExtendTo(16, false);
- EXPECT_EQ(S.UInt128(APInt()), APInt(16, 0xffffu));
-}
+++ /dev/null
-//===-- SharedClusterTest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/SharedCluster.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-class DestructNotifier {
-public:
- DestructNotifier(std::vector<int> &Queue, int Key) : Queue(Queue), Key(Key) {}
- ~DestructNotifier() { Queue.push_back(Key); }
-
- std::vector<int> &Queue;
- const int Key;
-};
-} // namespace
-
-TEST(SharedCluster, ClusterManager) {
- std::vector<int> Queue;
- {
- auto CM = ClusterManager<DestructNotifier>::Create();
- auto *One = new DestructNotifier(Queue, 1);
- auto *Two = new DestructNotifier(Queue, 2);
- CM->ManageObject(One);
- CM->ManageObject(Two);
-
- ASSERT_THAT(Queue, testing::IsEmpty());
- {
- std::shared_ptr<DestructNotifier> OnePtr = CM->GetSharedPointer(One);
- ASSERT_EQ(OnePtr->Key, 1);
- ASSERT_THAT(Queue, testing::IsEmpty());
-
- {
- std::shared_ptr<DestructNotifier> OnePtrCopy = OnePtr;
- ASSERT_EQ(OnePtrCopy->Key, 1);
- ASSERT_THAT(Queue, testing::IsEmpty());
- }
-
- {
- std::shared_ptr<DestructNotifier> TwoPtr = CM->GetSharedPointer(Two);
- ASSERT_EQ(TwoPtr->Key, 2);
- ASSERT_THAT(Queue, testing::IsEmpty());
- }
-
- ASSERT_THAT(Queue, testing::IsEmpty());
- }
- ASSERT_THAT(Queue, testing::IsEmpty());
- }
- ASSERT_THAT(Queue, testing::ElementsAre(1, 2));
-}
+++ /dev/null
-//===-- StateTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/State.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(StateTest, Formatv) {
- EXPECT_EQ("invalid", llvm::formatv("{0}", eStateInvalid).str());
- EXPECT_EQ("unloaded", llvm::formatv("{0}", eStateUnloaded).str());
- EXPECT_EQ("connected", llvm::formatv("{0}", eStateConnected).str());
- EXPECT_EQ("attaching", llvm::formatv("{0}", eStateAttaching).str());
- EXPECT_EQ("launching", llvm::formatv("{0}", eStateLaunching).str());
- EXPECT_EQ("stopped", llvm::formatv("{0}", eStateStopped).str());
- EXPECT_EQ("running", llvm::formatv("{0}", eStateRunning).str());
- EXPECT_EQ("stepping", llvm::formatv("{0}", eStateStepping).str());
- EXPECT_EQ("crashed", llvm::formatv("{0}", eStateCrashed).str());
- EXPECT_EQ("detached", llvm::formatv("{0}", eStateDetached).str());
- EXPECT_EQ("exited", llvm::formatv("{0}", eStateExited).str());
- EXPECT_EQ("suspended", llvm::formatv("{0}", eStateSuspended).str());
-
-}
+++ /dev/null
-//===-- StatusTest.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Status.h"
-#include "gtest/gtest.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-using namespace lldb_private;
-using namespace lldb;
-
-TEST(StatusTest, Formatv) {
- EXPECT_EQ("", llvm::formatv("{0}", Status()).str());
- EXPECT_EQ("Hello Status", llvm::formatv("{0}", Status("Hello Status")).str());
- EXPECT_EQ("Hello", llvm::formatv("{0:5}", Status("Hello Error")).str());
-}
-
-TEST(StatusTest, ErrorConstructor) {
- EXPECT_TRUE(Status(llvm::Error::success()).Success());
-
- Status eagain(
- llvm::errorCodeToError(std::error_code(EAGAIN, std::generic_category())));
- EXPECT_TRUE(eagain.Fail());
- EXPECT_EQ(eErrorTypePOSIX, eagain.GetType());
- EXPECT_EQ(Status::ValueType(EAGAIN), eagain.GetError());
-
- Status foo(llvm::make_error<llvm::StringError>(
- "foo", llvm::inconvertibleErrorCode()));
- EXPECT_TRUE(foo.Fail());
- EXPECT_EQ(eErrorTypeGeneric, foo.GetType());
- EXPECT_STREQ("foo", foo.AsCString());
-
- foo = llvm::Error::success();
- EXPECT_TRUE(foo.Success());
-}
-
-TEST(StatusTest, ErrorCodeConstructor) {
- EXPECT_TRUE(Status(std::error_code()).Success());
-
- Status eagain = std::error_code(EAGAIN, std::generic_category());
- EXPECT_TRUE(eagain.Fail());
- EXPECT_EQ(eErrorTypePOSIX, eagain.GetType());
- EXPECT_EQ(Status::ValueType(EAGAIN), eagain.GetError());
-}
-
-TEST(StatusTest, ErrorConversion) {
- EXPECT_FALSE(bool(Status().ToError()));
-
- llvm::Error eagain = Status(EAGAIN, ErrorType::eErrorTypePOSIX).ToError();
- EXPECT_TRUE(bool(eagain));
- std::error_code ec = llvm::errorToErrorCode(std::move(eagain));
- EXPECT_EQ(EAGAIN, ec.value());
- EXPECT_EQ(std::generic_category(), ec.category());
-
- llvm::Error foo = Status("foo").ToError();
- EXPECT_TRUE(bool(foo));
- EXPECT_EQ("foo", llvm::toString(std::move(foo)));
-}
-
-#ifdef _WIN32
-TEST(StatusTest, ErrorWin32) {
- auto success = Status(NO_ERROR, ErrorType::eErrorTypeWin32);
- EXPECT_STREQ(NULL, success.AsCString());
- EXPECT_FALSE(success.ToError());
- EXPECT_TRUE(success.Success());
-
- WCHAR name[128]{};
- ULONG nameLen = llvm::array_lengthof(name);
- ULONG langs = 0;
- GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langs,
- reinterpret_cast<PZZWSTR>(&name), &nameLen);
- // Skip the following tests on non-English, non-US, locales because the
- // formatted messages will be different.
- bool skip = wcscmp(L"en-US", name) != 0;
-
- auto s = Status(ERROR_ACCESS_DENIED, ErrorType::eErrorTypeWin32);
- EXPECT_TRUE(s.Fail());
- if (!skip)
- EXPECT_STREQ("Access is denied. ", s.AsCString());
-
- s.SetError(ERROR_IPSEC_IKE_TIMED_OUT, ErrorType::eErrorTypeWin32);
- if (!skip)
- EXPECT_STREQ("Negotiation timed out ", s.AsCString());
-
- s.SetError(16000, ErrorType::eErrorTypeWin32);
- if (!skip)
- EXPECT_STREQ("unknown error", s.AsCString());
-}
-#endif
+++ /dev/null
-//===-- StreamTeeTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StreamTee.h"
-#include "lldb/Utility/StreamString.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(StreamTeeTest, DefaultConstructor) {
- // Test the default constructor.
- StreamTee tee;
- ASSERT_EQ(0U, tee.GetNumStreams());
-}
-
-TEST(StreamTeeTest, Constructor1Stream) {
- // Test the constructor for a single stream.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- StreamTee tee(s1);
-
- ASSERT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
-}
-
-TEST(StreamTeeTest, Constructor2Streams) {
- // Test the constructor for two streams.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- lldb::StreamSP s2(std::make_shared<StreamString>());
- StreamTee tee(s1, s2);
-
- ASSERT_EQ(2U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
- EXPECT_EQ(s2, tee.GetStreamAtIndex(1U));
-}
-
-TEST(StreamTeeTest, CopyConstructor) {
- // Test the copy constructor.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- lldb::StreamSP s2(std::make_shared<StreamString>());
- StreamTee tee1(s1, s2);
- StreamTee tee2(tee1);
-
- ASSERT_EQ(2U, tee2.GetNumStreams());
- EXPECT_EQ(s1, tee2.GetStreamAtIndex(0U));
- EXPECT_EQ(s2, tee2.GetStreamAtIndex(1U));
-}
-
-TEST(StreamTeeTest, Assignment) {
- // Test the assignment of StreamTee.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- lldb::StreamSP s2(std::make_shared<StreamString>());
- StreamTee tee1(s1, s2);
- StreamTee tee2 = tee1;
-
- ASSERT_EQ(2U, tee2.GetNumStreams());
- EXPECT_EQ(s1, tee2.GetStreamAtIndex(0U));
- EXPECT_EQ(s2, tee2.GetStreamAtIndex(1U));
-}
-
-TEST(StreamTeeTest, Write) {
- // Test that write is sent out to all children.
- auto ss1 = new StreamString();
- auto ss2 = new StreamString();
- lldb::StreamSP s1(ss1);
- lldb::StreamSP s2(ss2);
- StreamTee tee(s1, s2);
-
- tee << "foo";
- tee.Flush();
-
- ASSERT_EQ(2U, tee.GetNumStreams());
- EXPECT_EQ("foo", ss1->GetString().str());
- EXPECT_EQ("foo", ss2->GetString().str());
-
- tee << "bar";
- tee.Flush();
- EXPECT_EQ("foobar", ss1->GetString().str());
- EXPECT_EQ("foobar", ss2->GetString().str());
-}
-
-namespace {
- struct FlushTestStream : public Stream {
- unsigned m_flush_count = false;
- void Flush() override {
- ++m_flush_count;
- }
- size_t WriteImpl(const void *src, size_t src_len) override {
- return src_len;
- }
- };
-}
-
-TEST(StreamTeeTest, Flush) {
- // Check that Flush is distributed to all streams.
- auto fs1 = new FlushTestStream();
- auto fs2 = new FlushTestStream();
- lldb::StreamSP s1(fs1);
- lldb::StreamSP s2(fs2);
- StreamTee tee(s1, s2);
-
- tee << "foo";
- tee.Flush();
-
- ASSERT_EQ(2U, tee.GetNumStreams());
- EXPECT_EQ(1U, fs1->m_flush_count);
- EXPECT_EQ(1U, fs2->m_flush_count);
-
- tee << "bar";
- tee.Flush();
- EXPECT_EQ(2U, fs1->m_flush_count);
- EXPECT_EQ(2U, fs2->m_flush_count);
-}
-
-TEST(StreamTeeTest, AppendStream) {
- // Append new streams to our StreamTee.
- auto ss1 = new StreamString();
- auto ss2 = new StreamString();
- lldb::StreamSP s1(ss1);
- lldb::StreamSP s2(ss2);
-
- StreamTee tee;
-
- ASSERT_EQ(0U, tee.GetNumStreams());
-
- tee.AppendStream(s1);
- ASSERT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
-
- tee.AppendStream(s2);
- ASSERT_EQ(2U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
- EXPECT_EQ(s2, tee.GetStreamAtIndex(1U));
-}
-
-TEST(StreamTeeTest, GetStreamAtIndexOutOfBounds) {
- // The index we check for is not in the bounds of the StreamTee.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- StreamTee tee(s1);
-
- ASSERT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1));
-}
-
-TEST(StreamTeeTest, GetStreamAtIndexOutOfBoundsEmpty) {
- // Same as above, but with an empty StreamTee.
- StreamTee tee;
- ASSERT_EQ(0U, tee.GetNumStreams());
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(0U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U));
-}
-
-TEST(StreamTeeTest, SetStreamAtIndexOverwrite) {
- // We overwrite an existing stream at a given index.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- StreamTee tee(s1);
-
- ASSERT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U));
-
- lldb::StreamSP s2(std::make_shared<StreamString>());
- tee.SetStreamAtIndex(0U, s2);
- EXPECT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(s2, tee.GetStreamAtIndex(0U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1));
-}
-
-TEST(StreamTeeTest, SetStreamAtIndexOutOfBounds) {
- // We place a new stream out of the bounds of the current StreamTee.
- lldb::StreamSP s1(std::make_shared<StreamString>());
- StreamTee tee(s1);
-
- ASSERT_EQ(1U, tee.GetNumStreams());
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U));
-
- // Place a new stream out of bounds of the current array. The StreamTee should
- // resize itself until it can contain this index.
- lldb::StreamSP s2(std::make_shared<StreamString>());
- tee.SetStreamAtIndex(4U, s2);
- // Check that the vector has been resized.
- EXPECT_EQ(5U, tee.GetNumStreams());
- // Is our stream at the right place?
- EXPECT_EQ(s2, tee.GetStreamAtIndex(4U));
-
- // Existing stream should still be there.
- EXPECT_EQ(s1, tee.GetStreamAtIndex(0U));
- // Other elements are all invalid StreamSPs.
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(1U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(2U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(3U));
- EXPECT_EQ(lldb::StreamSP(), tee.GetStreamAtIndex(5U));
-}
+++ /dev/null
-//===-- StreamTest.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StreamString.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-namespace {
-struct StreamTest : ::testing::Test {
- // Note: Stream is an abstract class, so we use StreamString to test it. To
- // make it easier to change this later, only methods in this class explicitly
- // refer to the StringStream class.
- StreamString s;
- // We return here a std::string because that way gtest can print better
- // assertion messages.
- std::string TakeValue() {
- std::string result = s.GetString().str();
- s.Clear();
- return result;
- }
-};
-}
-
-namespace {
-// A StreamTest where we expect the Stream output to be binary.
-struct BinaryStreamTest : StreamTest {
- void SetUp() override {
- s.GetFlags().Set(Stream::eBinary);
- }
-};
-}
-
-TEST_F(StreamTest, AddressPrefix) {
- DumpAddress(s.AsRawOstream(), 0x1, 1, "foo");
- EXPECT_EQ("foo0x01", TakeValue());
-}
-
-TEST_F(StreamTest, AddressEmptyPrefix) {
- DumpAddress(s.AsRawOstream(), 0x1, 1, nullptr);
- EXPECT_EQ("0x01", TakeValue());
- DumpAddress(s.AsRawOstream(), 0x1, 1, "");
- EXPECT_EQ("0x01", TakeValue());
-}
-
-TEST_F(StreamTest, AddressSuffix) {
- DumpAddress(s.AsRawOstream(), 0x1, 1, nullptr, "foo");
- EXPECT_EQ("0x01foo", TakeValue());
-}
-
-TEST_F(StreamTest, AddressNoSuffix) {
- DumpAddress(s.AsRawOstream(), 0x1, 1, nullptr, nullptr);
- EXPECT_EQ("0x01", TakeValue());
- DumpAddress(s.AsRawOstream(), 0x1, 1, nullptr, "");
- EXPECT_EQ("0x01", TakeValue());
-}
-
-TEST_F(StreamTest, AddressPrefixAndSuffix) {
- DumpAddress(s.AsRawOstream(), 0x1, 1, "foo", "bar");
- EXPECT_EQ("foo0x01bar", TakeValue());
-}
-
-TEST_F(StreamTest, AddressSize) {
- DumpAddress(s.AsRawOstream(), 0x0, 0);
- EXPECT_EQ("0x0", TakeValue());
- DumpAddress(s.AsRawOstream(), 0x1, 0);
- EXPECT_EQ("0x1", TakeValue());
-
- DumpAddress(s.AsRawOstream(), 0x1, 1);
- EXPECT_EQ("0x01", TakeValue());
- DumpAddress(s.AsRawOstream(), 0xf1, 1);
- EXPECT_EQ("0xf1", TakeValue());
- DumpAddress(s.AsRawOstream(), 0xff, 1);
- EXPECT_EQ("0xff", TakeValue());
- DumpAddress(s.AsRawOstream(), 0x100, 1);
- EXPECT_EQ("0x100", TakeValue());
-
- DumpAddress(s.AsRawOstream(), 0xf00, 4);
- EXPECT_EQ("0x00000f00", TakeValue());
- DumpAddress(s.AsRawOstream(), 0x100, 8);
- EXPECT_EQ("0x0000000000000100", TakeValue());
-}
-
-TEST_F(StreamTest, AddressRange) {
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x101, 2);
- EXPECT_EQ("[0x0100-0x0101)", TakeValue());
-}
-
-TEST_F(StreamTest, AddressRangeEmptyRange) {
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x100, 2);
- EXPECT_EQ("[0x0100-0x0100)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x0, 0x0, 2);
- EXPECT_EQ("[0x0000-0x0000)", TakeValue());
-}
-
-TEST_F(StreamTest, AddressRangeInvalidRange) {
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x0FF, 2);
- EXPECT_EQ("[0x0100-0x00ff)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x0, 2);
- EXPECT_EQ("[0x0100-0x0000)", TakeValue());
-}
-
-TEST_F(StreamTest, AddressRangeSize) {
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x101, 0);
- EXPECT_EQ("[0x100-0x101)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x101, 2);
- EXPECT_EQ("[0x0100-0x0101)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x101, 4);
- EXPECT_EQ("[0x00000100-0x00000101)", TakeValue());
-
- DumpAddressRange(s.AsRawOstream(), 0x100, 0x101, 4);
- EXPECT_EQ("[0x00000100-0x00000101)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x1, 0x101, 4);
- EXPECT_EQ("[0x00000001-0x00000101)", TakeValue());
- DumpAddressRange(s.AsRawOstream(), 0x101, 0x1, 4);
- EXPECT_EQ("[0x00000101-0x00000001)", TakeValue());
-
- DumpAddressRange(s.AsRawOstream(), 0x1, 0x101, 1);
- EXPECT_EQ("[0x01-0x101)", TakeValue());
-}
-
-TEST_F(StreamTest, ChangingByteOrder) {
- s.SetByteOrder(lldb::eByteOrderPDP);
- EXPECT_EQ(lldb::eByteOrderPDP, s.GetByteOrder());
-}
-
-TEST_F(StreamTest, SetIndentLevel) {
- s.Indent("a");
- EXPECT_EQ("a", TakeValue());
-
- s.SetIndentLevel(3);
- s.Indent("a");
- EXPECT_EQ(" a", TakeValue());
-
- s.SetIndentLevel(2);
- s.Indent("a");
- EXPECT_EQ(" a", TakeValue());
-
- s.SetIndentLevel(0);
- s.Indent("a");
- EXPECT_EQ("a", TakeValue());
-}
-
-TEST_F(StreamTest, Indent) {
- s.SetIndentLevel(2);
- const char *nullptr_cstring = nullptr;
- s.Indent(nullptr_cstring);
- EXPECT_EQ(" ", TakeValue());
-
- s.Indent("");
- EXPECT_EQ(" ", TakeValue());
-
- s.Indent(" ");
- EXPECT_EQ(" ", TakeValue());
-
- s.Indent(" aa");
- EXPECT_EQ(" aa", TakeValue());
-}
-
-TEST_F(StreamTest, PutChar) {
- s.PutChar('a');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("a", TakeValue());
-
- s.PutChar('1');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("1", TakeValue());
-}
-
-TEST_F(StreamTest, PutCharWhitespace) {
- s.PutChar(' ');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(" ", TakeValue());
-
- s.PutChar('\n');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("\n", TakeValue());
-
- s.PutChar('\r');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("\r", TakeValue());
-
- s.PutChar('\t');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("\t", TakeValue());
-}
-
-TEST_F(StreamTest, PutCString) {
- s.PutCString("");
- EXPECT_EQ(0U, s.GetWrittenBytes());
- EXPECT_EQ("", TakeValue());
-
- s.PutCString("foobar");
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ("foobar", TakeValue());
-
- s.PutCString(" ");
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(" ", TakeValue());
-}
-
-TEST_F(StreamTest, PutCStringWithStringRef) {
- s.PutCString(llvm::StringRef(""));
- EXPECT_EQ(0U, s.GetWrittenBytes());
- EXPECT_EQ("", TakeValue());
-
- s.PutCString(llvm::StringRef("foobar"));
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ("foobar", TakeValue());
-
- s.PutCString(llvm::StringRef(" "));
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(" ", TakeValue());
-}
-
-TEST_F(StreamTest, QuotedCString) {
- s.QuotedCString("foo");
- EXPECT_EQ(5U, s.GetWrittenBytes());
- EXPECT_EQ(R"("foo")", TakeValue());
-
- s.QuotedCString("ba r");
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ(R"("ba r")", TakeValue());
-
- s.QuotedCString(" ");
- EXPECT_EQ(3U, s.GetWrittenBytes());
- EXPECT_EQ(R"(" ")", TakeValue());
-}
-
-TEST_F(StreamTest, PutCharNull) {
- s.PutChar('\0');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\0", 1), TakeValue());
-
- s.PutChar('a');
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("a", 1), TakeValue());
-}
-
-TEST_F(StreamTest, PutStringAsRawHex8) {
- s.PutStringAsRawHex8("");
- EXPECT_EQ(0U, s.GetWrittenBytes());
- EXPECT_EQ("", TakeValue());
-
- s.PutStringAsRawHex8("foobar");
- EXPECT_EQ(12U, s.GetWrittenBytes());
- EXPECT_EQ("666f6f626172", TakeValue());
-
- s.PutStringAsRawHex8(" ");
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("20", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex8) {
- s.PutHex8((uint8_t)55);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("37", TakeValue());
-
- s.PutHex8(std::numeric_limits<uint8_t>::max());
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("ff", TakeValue());
-
- s.PutHex8((uint8_t)0);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("00", TakeValue());
-}
-
-TEST_F(StreamTest, PutNHex8) {
- s.PutNHex8(0, (uint8_t)55);
- EXPECT_EQ(0U, s.GetWrittenBytes());
- EXPECT_EQ("", TakeValue());
-
- s.PutNHex8(1, (uint8_t)55);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("37", TakeValue());
-
- s.PutNHex8(2, (uint8_t)55);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("3737", TakeValue());
-
- s.PutNHex8(1, (uint8_t)56);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("38", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex16ByteOrderLittle) {
- s.PutHex16(0x1234U, lldb::eByteOrderLittle);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("3412", TakeValue());
-
- s.PutHex16(std::numeric_limits<uint16_t>::max(), lldb::eByteOrderLittle);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("ffff", TakeValue());
-
- s.PutHex16(0U, lldb::eByteOrderLittle);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("0000", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex16ByteOrderBig) {
- s.PutHex16(0x1234U, lldb::eByteOrderBig);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("1234", TakeValue());
-
- s.PutHex16(std::numeric_limits<uint16_t>::max(), lldb::eByteOrderBig);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("ffff", TakeValue());
-
- s.PutHex16(0U, lldb::eByteOrderBig);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("0000", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex32ByteOrderLittle) {
- s.PutHex32(0x12345678U, lldb::eByteOrderLittle);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("78563412", TakeValue());
-
- s.PutHex32(std::numeric_limits<uint32_t>::max(), lldb::eByteOrderLittle);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("ffffffff", TakeValue());
-
- s.PutHex32(0U, lldb::eByteOrderLittle);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("00000000", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex32ByteOrderBig) {
- s.PutHex32(0x12345678U, lldb::eByteOrderBig);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("12345678", TakeValue());
-
- s.PutHex32(std::numeric_limits<uint32_t>::max(), lldb::eByteOrderBig);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("ffffffff", TakeValue());
-
- s.PutHex32(0U, lldb::eByteOrderBig);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("00000000", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex64ByteOrderLittle) {
- s.PutHex64(0x1234567890ABCDEFU, lldb::eByteOrderLittle);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("efcdab9078563412", TakeValue());
-
- s.PutHex64(std::numeric_limits<uint64_t>::max(), lldb::eByteOrderLittle);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("ffffffffffffffff", TakeValue());
-
- s.PutHex64(0U, lldb::eByteOrderLittle);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("0000000000000000", TakeValue());
-}
-
-TEST_F(StreamTest, PutHex64ByteOrderBig) {
- s.PutHex64(0x1234567890ABCDEFU, lldb::eByteOrderBig);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("1234567890abcdef", TakeValue());
-
- s.PutHex64(std::numeric_limits<uint64_t>::max(), lldb::eByteOrderBig);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("ffffffffffffffff", TakeValue());
-
- s.PutHex64(0U, lldb::eByteOrderBig);
- EXPECT_EQ(16U, s.GetWrittenBytes());
- EXPECT_EQ("0000000000000000", TakeValue());
-}
-
-TEST_F(StreamTest, PutMaxHex64ByteOrderBig) {
- std::size_t bytes;
- bytes = s.PutMaxHex64(0x12U, 1, lldb::eByteOrderBig);
- EXPECT_EQ(2U, bytes);
- bytes = s.PutMaxHex64(0x1234U, 2, lldb::eByteOrderBig);
- EXPECT_EQ(4U, bytes);
- bytes = s.PutMaxHex64(0x12345678U, 4, lldb::eByteOrderBig);
- EXPECT_EQ(8U, bytes);
- bytes = s.PutMaxHex64(0x1234567890ABCDEFU, 8, lldb::eByteOrderBig);
- EXPECT_EQ(16U, bytes);
- EXPECT_EQ(30U, s.GetWrittenBytes());
- EXPECT_EQ("121234123456781234567890abcdef", TakeValue());
-}
-
-TEST_F(StreamTest, PutMaxHex64ByteOrderLittle) {
- std::size_t bytes;
- bytes = s.PutMaxHex64(0x12U, 1, lldb::eByteOrderLittle);
- EXPECT_EQ(2U, bytes);
- bytes = s.PutMaxHex64(0x1234U, 2, lldb::eByteOrderLittle);
- EXPECT_EQ(4U, bytes);
- bytes = s.PutMaxHex64(0x12345678U, 4, lldb::eByteOrderLittle);
- EXPECT_EQ(8U, bytes);
- bytes = s.PutMaxHex64(0x1234567890ABCDEFU, 8, lldb::eByteOrderLittle);
- EXPECT_EQ(16U, bytes);
- EXPECT_EQ(30U, s.GetWrittenBytes());
- EXPECT_EQ("12341278563412efcdab9078563412", TakeValue());
-}
-
-// Shift operator tests.
-
-TEST_F(StreamTest, ShiftOperatorChars) {
- s << 'a' << 'b';
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("ab", TakeValue());
-}
-
-TEST_F(StreamTest, ShiftOperatorStrings) {
- s << "cstring\n";
- EXPECT_EQ(8U, s.GetWrittenBytes());
- s << llvm::StringRef("llvm::StringRef\n");
- EXPECT_EQ(24U, s.GetWrittenBytes());
- EXPECT_EQ("cstring\nllvm::StringRef\n", TakeValue());
-}
-
-TEST_F(StreamTest, ShiftOperatorPtr) {
- // This test is a bit tricky because pretty much everything related to
- // pointer printing seems to lead to UB or IB. So let's make the most basic
- // test that just checks that we print *something*. This way we at least know
- // that pointer printing doesn't do really bad things (e.g. crashing, reading
- // OOB/uninitialized memory which the sanitizers would spot).
-
- // Shift our own pointer to the output.
- int i = 3;
- int *ptr = &i;
- s << ptr;
-
- EXPECT_NE(0U, s.GetWrittenBytes());
- EXPECT_TRUE(!TakeValue().empty());
-}
-
-TEST_F(StreamTest, PutPtr) {
- // See the ShiftOperatorPtr test for the rationale.
- int i = 3;
- int *ptr = &i;
- s.PutPointer(ptr);
-
- EXPECT_NE(0U, s.GetWrittenBytes());
- EXPECT_TRUE(!TakeValue().empty());
-}
-
-// Alias to make it more clear that 'invalid' means for the Stream interface
-// that it should use the host byte order.
-const static auto hostByteOrder = lldb::eByteOrderInvalid;
-
-// PutRawBytes/PutBytesAsRawHex tests.
-
-TEST_F(StreamTest, PutBytesAsRawHex8ToBigEndian) {
- uint32_t value = 0x12345678;
- s.PutBytesAsRawHex8(static_cast<void*>(&value), sizeof(value),
- hostByteOrder, lldb::eByteOrderBig);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("78563412", TakeValue());
-}
-
-TEST_F(StreamTest, PutRawBytesToBigEndian) {
- uint32_t value = 0x12345678;
- s.PutRawBytes(static_cast<void*>(&value), sizeof(value),
- hostByteOrder, lldb::eByteOrderBig);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("\x78\x56\x34\x12", TakeValue());
-}
-
-TEST_F(StreamTest, PutBytesAsRawHex8ToLittleEndian) {
- uint32_t value = 0x12345678;
- s.PutBytesAsRawHex8(static_cast<void*>(&value), sizeof(value),
- hostByteOrder, lldb::eByteOrderLittle);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("12345678", TakeValue());
-}
-
-TEST_F(StreamTest, PutRawBytesToLittleEndian) {
- uint32_t value = 0x12345678;
- s.PutRawBytes(static_cast<void*>(&value), sizeof(value),
- hostByteOrder, lldb::eByteOrderLittle);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("\x12\x34\x56\x78", TakeValue());
-}
-
-TEST_F(StreamTest, PutBytesAsRawHex8ToMixedEndian) {
- uint32_t value = 0x12345678;
- s.PutBytesAsRawHex8(static_cast<void*>(&value), sizeof(value),
- hostByteOrder, lldb::eByteOrderPDP);
-
- // FIXME: PDP byte order is not actually implemented but Stream just silently
- // prints the value in some random byte order...
-#if 0
- EXPECT_EQ("34127856", TakeValue());
-#endif
-}
-
-TEST_F(StreamTest, PutRawBytesToMixedEndian) {
- uint32_t value = 0x12345678;
- s.PutRawBytes(static_cast<void*>(&value), sizeof(value),
- lldb::eByteOrderInvalid, lldb::eByteOrderPDP);
-
- // FIXME: PDP byte order is not actually implemented but Stream just silently
- // prints the value in some random byte order...
-#if 0
- EXPECT_EQ("\x34\x12\x78\x56", TakeValue());
-#endif
-}
-
-// ULEB128 support for binary streams.
-
-TEST_F(BinaryStreamTest, PutULEB128OneByte) {
- auto bytes = s.PutULEB128(0x74ULL);
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("\x74", TakeValue());
- EXPECT_EQ(1U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128TwoBytes) {
- auto bytes = s.PutULEB128(0x1985ULL);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("\x85\x33", TakeValue());
- EXPECT_EQ(2U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128ThreeBytes) {
- auto bytes = s.PutULEB128(0x5023ULL);
- EXPECT_EQ(3U, s.GetWrittenBytes());
- EXPECT_EQ("\xA3\xA0\x1", TakeValue());
- EXPECT_EQ(3U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128FourBytes) {
- auto bytes = s.PutULEB128(0xA48032ULL);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("\xB2\x80\x92\x5", TakeValue());
- EXPECT_EQ(4U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128FiveBytes) {
- auto bytes = s.PutULEB128(0x12345678ULL);
- EXPECT_EQ(5U, s.GetWrittenBytes());
- EXPECT_EQ("\xF8\xAC\xD1\x91\x1", TakeValue());
- EXPECT_EQ(5U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128SixBytes) {
- auto bytes = s.PutULEB128(0xABFE3FAFDFULL);
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\x15", TakeValue());
- EXPECT_EQ(6U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128SevenBytes) {
- auto bytes = s.PutULEB128(0xDABFE3FAFDFULL);
- EXPECT_EQ(7U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\x3", TakeValue());
- EXPECT_EQ(7U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128EightBytes) {
- auto bytes = s.PutULEB128(0x7CDABFE3FAFDFULL);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\xF3\x3", TakeValue());
- EXPECT_EQ(8U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128NineBytes) {
- auto bytes = s.PutULEB128(0x327CDABFE3FAFDFULL);
- EXPECT_EQ(9U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\xF3\x93\x3", TakeValue());
- EXPECT_EQ(9U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128MaxValue) {
- auto bytes = s.PutULEB128(std::numeric_limits<uint64_t>::max());
- EXPECT_EQ(10U, s.GetWrittenBytes());
- EXPECT_EQ("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1", TakeValue());
- EXPECT_EQ(10U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128Zero) {
- auto bytes = s.PutULEB128(0x0U);
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\0", 1), TakeValue());
- EXPECT_EQ(1U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutULEB128One) {
- auto bytes = s.PutULEB128(0x1U);
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ("\x1", TakeValue());
- EXPECT_EQ(1U, bytes);
-}
-
-// SLEB128 support for binary streams.
-
-TEST_F(BinaryStreamTest, PutSLEB128OneByte) {
- auto bytes = s.PutSLEB128(0x74LL);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\xF4\0", 2), TakeValue());
- EXPECT_EQ(2U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128TwoBytes) {
- auto bytes = s.PutSLEB128(0x1985LL);
- EXPECT_EQ(2U, s.GetWrittenBytes());
- EXPECT_EQ("\x85\x33", TakeValue());
- EXPECT_EQ(2U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128ThreeBytes) {
- auto bytes = s.PutSLEB128(0x5023LL);
- EXPECT_EQ(3U, s.GetWrittenBytes());
- EXPECT_EQ("\xA3\xA0\x1", TakeValue());
- EXPECT_EQ(3U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128FourBytes) {
- auto bytes = s.PutSLEB128(0xA48032LL);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("\xB2\x80\x92\x5", TakeValue());
- EXPECT_EQ(4U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128FiveBytes) {
- auto bytes = s.PutSLEB128(0x12345678LL);
- EXPECT_EQ(5U, s.GetWrittenBytes());
- EXPECT_EQ("\xF8\xAC\xD1\x91\x1", TakeValue());
- EXPECT_EQ(5U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128SixBytes) {
- auto bytes = s.PutSLEB128(0xABFE3FAFDFLL);
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\x15", TakeValue());
- EXPECT_EQ(6U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128SevenBytes) {
- auto bytes = s.PutSLEB128(0xDABFE3FAFDFLL);
- EXPECT_EQ(7U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\x3", TakeValue());
- EXPECT_EQ(7U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128EightBytes) {
- auto bytes = s.PutSLEB128(0x7CDABFE3FAFDFLL);
- EXPECT_EQ(8U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\xF3\x3", TakeValue());
- EXPECT_EQ(8U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128NineBytes) {
- auto bytes = s.PutSLEB128(0x327CDABFE3FAFDFLL);
- EXPECT_EQ(9U, s.GetWrittenBytes());
- EXPECT_EQ("\xDF\xDF\xFE\xF1\xBF\xB5\xF3\x93\x3", TakeValue());
- EXPECT_EQ(9U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128MaxValue) {
- auto bytes = s.PutSLEB128(std::numeric_limits<int64_t>::max());
- EXPECT_EQ(10U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0", 10), TakeValue());
- EXPECT_EQ(10U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128Zero) {
- auto bytes = s.PutSLEB128(0x0);
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\0", 1), TakeValue());
- EXPECT_EQ(1U, bytes);
-}
-
-TEST_F(BinaryStreamTest, PutSLEB128One) {
- auto bytes = s.PutSLEB128(0x1);
- EXPECT_EQ(1U, s.GetWrittenBytes());
- EXPECT_EQ(std::string("\x1", 1), TakeValue());
- EXPECT_EQ(1U, bytes);
-}
-
-// SLEB128/ULEB128 support for non-binary streams.
-
-// The logic for this is very simple, so it should be enough to test some basic
-// use cases.
-
-TEST_F(StreamTest, PutULEB128) {
- auto bytes = s.PutULEB128(0x74ULL);
- EXPECT_EQ(4U, s.GetWrittenBytes());
- EXPECT_EQ("0x74", TakeValue());
- EXPECT_EQ(4U, bytes);
-}
-
-TEST_F(StreamTest, PutSLEB128) {
- auto bytes = s.PutSLEB128(0x1985LL);
- EXPECT_EQ(6U, s.GetWrittenBytes());
- EXPECT_EQ("0x6533", TakeValue());
- EXPECT_EQ(6U, bytes);
-}
+++ /dev/null
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <limits.h>
-
-#include "lldb/Utility/StringExtractorGDBRemote.h"
-#include "lldb/lldb-defines.h"
-
-TEST(StringExtractorGDBRemoteTest, GetPidTid) {
- StringExtractorGDBRemote ex("");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- // invalid/short values
-
- ex.Reset("narf");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset(";1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset(".1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("pnarf");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p;1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p.1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p1234.");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p1234.;1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("-2");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p1234.-2");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p-2");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p-2.1234");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- // overflow
-
- ex.Reset("p10000000000000000");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p10000000000000000.0");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("10000000000000000");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p0.10000000000000000");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- ex.Reset("p10000000000000000.10000000000000000");
- EXPECT_EQ(ex.GetPidTid(0), llvm::None);
-
- // invalid: all processes but specific thread
-
- ex.Reset("p-1.0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p-1.1234");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p-1.123456789ABCDEF0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- // unsupported: pid/tid 0
-
- ex.Reset("0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p0.0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p0.-1");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p0.1234");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p0.123456789ABCDEF0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p1234.0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- ex.Reset("p123456789ABCDEF0.0");
- EXPECT_EQ(ex.GetPidTid(100), llvm::None);
-
- // pure thread id
-
- ex.Reset("-1");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(100, StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("1234");
- EXPECT_THAT(ex.GetPidTid(100).getValue(), ::testing::Pair(100, 0x1234ULL));
-
- ex.Reset("123456789ABCDEF0");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(100, 0x123456789ABCDEF0ULL));
-
- // pure process id
-
- ex.Reset("p-1");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(StringExtractorGDBRemote::AllProcesses,
- StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("p1234");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("p123456789ABCDEF0");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x123456789ABCDEF0ULL,
- StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("pFFFFFFFFFFFFFFFF");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(StringExtractorGDBRemote::AllProcesses,
- StringExtractorGDBRemote::AllThreads));
-
- // combined thread id + process id
-
- ex.Reset("p-1.-1");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(StringExtractorGDBRemote::AllProcesses,
- StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("p1234.-1");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("p1234.123456789ABCDEF0");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x1234ULL, 0x123456789ABCDEF0ULL));
-
- ex.Reset("p123456789ABCDEF0.-1");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x123456789ABCDEF0ULL,
- StringExtractorGDBRemote::AllThreads));
-
- ex.Reset("p123456789ABCDEF0.1234");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x123456789ABCDEF0ULL, 0x1234ULL));
-
- ex.Reset("p123456789ABCDEF0.123456789ABCDEF0");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL));
-
- ex.Reset("p123456789ABCDEF0.123456789ABCDEF0");
- EXPECT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL));
-}
-
-TEST(StringExtractorGDBRemoteTest, GetPidTidMultipleValues) {
- StringExtractorGDBRemote ex("1234;p12;p1234.-1");
- ASSERT_THAT(ex.GetPidTid(100).getValue(), ::testing::Pair(100, 0x1234ULL));
- ASSERT_EQ(ex.GetChar(), ';');
- ASSERT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x12ULL, StringExtractorGDBRemote::AllThreads));
- ASSERT_EQ(ex.GetChar(), ';');
- ASSERT_THAT(ex.GetPidTid(100).getValue(),
- ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads));
-}
+++ /dev/null
-#include "gtest/gtest.h"
-#include <limits.h>
-
-#include "lldb/Utility/StringExtractor.h"
-
-namespace {
-class StringExtractorTest : public ::testing::Test {};
-} // namespace
-
-TEST_F(StringExtractorTest, InitEmpty) {
- llvm::StringRef kEmptyString = "";
- StringExtractor ex(kEmptyString);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(kEmptyString, ex.GetStringRef());
- ASSERT_EQ(true, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, InitMisc) {
- llvm::StringRef kInitMiscString = "Hello, StringExtractor!";
- StringExtractor ex(kInitMiscString);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(kInitMiscString, ex.GetStringRef());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(kInitMiscString.size(), ex.GetBytesLeft());
- ASSERT_EQ(kInitMiscString[0], *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_Underflow) {
- llvm::StringRef kEmptyString = "";
- StringExtractor ex(kEmptyString);
-
- ASSERT_EQ(-1, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(true, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_Underflow2) {
- StringExtractor ex("1");
-
- ASSERT_EQ(-1, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(1u, ex.GetBytesLeft());
- ASSERT_EQ('1', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_InvalidHex) {
- llvm::StringRef kInvalidHex = "xa";
- StringExtractor ex(kInvalidHex);
-
- ASSERT_EQ(-1, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_InvalidHex2) {
- llvm::StringRef kInvalidHex = "ax";
- StringExtractor ex(kInvalidHex);
-
- ASSERT_EQ(-1, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('a', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_Exact) {
- llvm::StringRef kValidHexPair = "12";
- StringExtractor ex(kValidHexPair);
-
- ASSERT_EQ(0x12, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, DecodeHexU8_Extra) {
- llvm::StringRef kValidHexPair = "1234";
- StringExtractor ex(kValidHexPair);
-
- ASSERT_EQ(0x12, ex.DecodeHexU8());
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('3', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Underflow) {
- llvm::StringRef kEmptyString = "";
- StringExtractor ex(kEmptyString);
-
- ASSERT_EQ(0xab, ex.GetHexU8(0xab));
- ASSERT_EQ(false, ex.IsGood());
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(true, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Underflow2) {
- llvm::StringRef kOneNibble = "1";
- StringExtractor ex(kOneNibble);
-
- ASSERT_EQ(0xbc, ex.GetHexU8(0xbc));
- ASSERT_EQ(false, ex.IsGood());
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_InvalidHex) {
- llvm::StringRef kInvalidHex = "xx";
- StringExtractor ex(kInvalidHex);
-
- ASSERT_EQ(0xcd, ex.GetHexU8(0xcd));
- ASSERT_EQ(false, ex.IsGood());
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Exact) {
- llvm::StringRef kValidHexPair = "12";
- StringExtractor ex(kValidHexPair);
-
- ASSERT_EQ(0x12, ex.GetHexU8(0x12));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Extra) {
- llvm::StringRef kValidHexPair = "1234";
- StringExtractor ex(kValidHexPair);
-
- ASSERT_EQ(0x12, ex.GetHexU8(0x12));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('3', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Underflow_NoEof) {
- llvm::StringRef kEmptyString = "";
- StringExtractor ex(kEmptyString);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ(0xab, ex.GetHexU8(0xab, kSetEofOnFail));
- ASSERT_EQ(false, ex.IsGood()); // this result seems inconsistent with
- // kSetEofOnFail == false
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(true, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Underflow2_NoEof) {
- llvm::StringRef kOneNibble = "1";
- StringExtractor ex(kOneNibble);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ(0xbc, ex.GetHexU8(0xbc, kSetEofOnFail));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(1u, ex.GetBytesLeft());
- ASSERT_EQ('1', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_InvalidHex_NoEof) {
- llvm::StringRef kInvalidHex = "xx";
- StringExtractor ex(kInvalidHex);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ(0xcd, ex.GetHexU8(0xcd, kSetEofOnFail));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(0u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Exact_NoEof) {
- llvm::StringRef kValidHexPair = "12";
- StringExtractor ex(kValidHexPair);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ(0x12, ex.GetHexU8(0x12, kSetEofOnFail));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexU8_Extra_NoEof) {
- llvm::StringRef kValidHexPair = "1234";
- StringExtractor ex(kValidHexPair);
- const bool kSetEofOnFail = false;
-
- ASSERT_EQ(0x12, ex.GetHexU8(0x12, kSetEofOnFail));
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2u, ex.GetFilePos());
- ASSERT_EQ(2u, ex.GetBytesLeft());
- ASSERT_EQ('3', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytes) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2 * kValidHexPairs, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytes_FullString) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytes_OddPair) {
- llvm::StringRef kHexEncodedBytes = "abcdef012345678w";
- const size_t kValidHexPairs = 7;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[8];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
-
- // This one should be invalid
- EXPECT_EQ(0xde, dst[7]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytes_OddPair2) {
- llvm::StringRef kHexEncodedBytes = "abcdef012345678";
- const size_t kValidHexPairs = 7;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[8];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
-
- EXPECT_EQ(0xde, dst[7]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytes_Underflow) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytes(dst, 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
- // these bytes should be filled with fail_fill_value 0xde
- EXPECT_EQ(0xde, dst[8]);
- EXPECT_EQ(0xde, dst[9]);
- EXPECT_EQ(0xde, dst[10]);
- EXPECT_EQ(0xde, dst[11]);
-
- ASSERT_EQ(false, ex.IsGood());
- ASSERT_EQ(UINT64_MAX, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(0u, ex.GetBytesLeft());
- ASSERT_EQ(nullptr, ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytes_Partial) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kReadBytes = 4;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xab, sizeof(dst));
- ASSERT_EQ(
- kReadBytes,
- ex.GetHexBytes(llvm::MutableArrayRef<uint8_t>(dst, kReadBytes), 0xde));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- // these bytes should be unchanged
- EXPECT_EQ(0xab, dst[4]);
- EXPECT_EQ(0xab, dst[5]);
- EXPECT_EQ(0xab, dst[6]);
- EXPECT_EQ(0xab, dst[7]);
- EXPECT_EQ(0xab, dst[8]);
- EXPECT_EQ(0xab, dst[9]);
- EXPECT_EQ(0xab, dst[10]);
- EXPECT_EQ(0xab, dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kReadBytes * 2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(12u, ex.GetBytesLeft());
- ASSERT_EQ('2', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(2 * kValidHexPairs, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail_FullString) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[kValidHexPairs];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail_OddPair) {
- llvm::StringRef kHexEncodedBytes = "abcdef012345678w";
- const size_t kValidHexPairs = 7;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[8];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail_OddPair2) {
- llvm::StringRef kHexEncodedBytes = "abcdef012345678";
- const size_t kValidHexPairs = 7;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[8];
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail_Underflow) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kValidHexPairs = 8;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xef, sizeof(dst));
- ASSERT_EQ(kValidHexPairs, ex.GetHexBytesAvail(dst));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- EXPECT_EQ(0x23, dst[4]);
- EXPECT_EQ(0x45, dst[5]);
- EXPECT_EQ(0x67, dst[6]);
- EXPECT_EQ(0x89, dst[7]);
- // these bytes should be unchanged
- EXPECT_EQ(0xef, dst[8]);
- EXPECT_EQ(0xef, dst[9]);
- EXPECT_EQ(0xef, dst[10]);
- EXPECT_EQ(0xef, dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kValidHexPairs * 2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(4u, ex.GetBytesLeft());
- ASSERT_EQ('x', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetHexBytesAvail_Partial) {
- llvm::StringRef kHexEncodedBytes = "abcdef0123456789xyzw";
- const size_t kReadBytes = 4;
- StringExtractor ex(kHexEncodedBytes);
-
- uint8_t dst[12];
- memset(dst, 0xab, sizeof(dst));
- ASSERT_EQ(kReadBytes, ex.GetHexBytesAvail(
- llvm::MutableArrayRef<uint8_t>(dst, kReadBytes)));
- EXPECT_EQ(0xab, dst[0]);
- EXPECT_EQ(0xcd, dst[1]);
- EXPECT_EQ(0xef, dst[2]);
- EXPECT_EQ(0x01, dst[3]);
- // these bytes should be unchanged
- EXPECT_EQ(0xab, dst[4]);
- EXPECT_EQ(0xab, dst[5]);
- EXPECT_EQ(0xab, dst[6]);
- EXPECT_EQ(0xab, dst[7]);
- EXPECT_EQ(0xab, dst[8]);
- EXPECT_EQ(0xab, dst[9]);
- EXPECT_EQ(0xab, dst[10]);
- EXPECT_EQ(0xab, dst[11]);
-
- ASSERT_EQ(true, ex.IsGood());
- ASSERT_EQ(kReadBytes * 2, ex.GetFilePos());
- ASSERT_EQ(false, ex.Empty());
- ASSERT_EQ(12u, ex.GetBytesLeft());
- ASSERT_EQ('2', *ex.Peek());
-}
-
-TEST_F(StringExtractorTest, GetNameColonValueSuccess) {
- llvm::StringRef kNameColonPairs = "key1:value1;key2:value2;";
- StringExtractor ex(kNameColonPairs);
-
- llvm::StringRef name;
- llvm::StringRef value;
- EXPECT_TRUE(ex.GetNameColonValue(name, value));
- EXPECT_EQ("key1", name);
- EXPECT_EQ("value1", value);
- EXPECT_TRUE(ex.GetNameColonValue(name, value));
- EXPECT_EQ("key2", name);
- EXPECT_EQ("value2", value);
- EXPECT_EQ(0u, ex.GetBytesLeft());
-}
-
-TEST_F(StringExtractorTest, GetNameColonValueContainsColon) {
- llvm::StringRef kNameColonPairs = "key1:value1:value2;key2:value3;";
- StringExtractor ex(kNameColonPairs);
-
- llvm::StringRef name;
- llvm::StringRef value;
- EXPECT_TRUE(ex.GetNameColonValue(name, value));
- EXPECT_EQ("key1", name);
- EXPECT_EQ("value1:value2", value);
- EXPECT_TRUE(ex.GetNameColonValue(name, value));
- EXPECT_EQ("key2", name);
- EXPECT_EQ("value3", value);
- EXPECT_EQ(0u, ex.GetBytesLeft());
-}
-
-TEST_F(StringExtractorTest, GetNameColonValueNoSemicolon) {
- llvm::StringRef kNameColonPairs = "key1:value1";
- StringExtractor ex(kNameColonPairs);
-
- llvm::StringRef name;
- llvm::StringRef value;
- EXPECT_FALSE(ex.GetNameColonValue(name, value));
- EXPECT_EQ(0u, ex.GetBytesLeft());
-}
-
-TEST_F(StringExtractorTest, GetNameColonValueNoColon) {
- llvm::StringRef kNameColonPairs = "key1value1;";
- StringExtractor ex(kNameColonPairs);
-
- llvm::StringRef name;
- llvm::StringRef value;
- EXPECT_FALSE(ex.GetNameColonValue(name, value));
- EXPECT_EQ(0u, ex.GetBytesLeft());
-}
-
-TEST_F(StringExtractorTest, GetU32LittleEndian) {
- StringExtractor ex("");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("0");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU32(true, 1));
-
- ex.Reset("1");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("01");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("001");
- EXPECT_EQ(0x100ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("12");
- EXPECT_EQ(0x12ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("123");
- EXPECT_EQ(0x312ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("1203");
- EXPECT_EQ(0x312ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("1234");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("12340");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("123400");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("12345670");
- EXPECT_EQ(0x70563412ull, ex.GetHexMaxU32(true, 0));
-
- ex.Reset("123456701");
- EXPECT_EQ(0ull, ex.GetHexMaxU32(true, 0));
-}
-
-TEST_F(StringExtractorTest, GetU32BigEndian) {
- StringExtractor ex("");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("0");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU32(false, 1));
-
- ex.Reset("1");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("01");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("001");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("12");
- EXPECT_EQ(0x12ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("123");
- EXPECT_EQ(0x123ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("1203");
- EXPECT_EQ(0x1203ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("1234");
- EXPECT_EQ(0x1234ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("12340");
- EXPECT_EQ(0x12340ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("123400");
- EXPECT_EQ(0x123400ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("12345670");
- EXPECT_EQ(0x12345670ull, ex.GetHexMaxU32(false, 0));
-
- ex.Reset("123456700");
- EXPECT_EQ(0ull, ex.GetHexMaxU32(false, 0));
-}
-
-TEST_F(StringExtractorTest, GetU64LittleEndian) {
- StringExtractor ex("");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("0");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU64(true, 1));
-
- ex.Reset("1");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("01");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("001");
- EXPECT_EQ(0x100ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("12");
- EXPECT_EQ(0x12ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("123");
- EXPECT_EQ(0x312ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("1203");
- EXPECT_EQ(0x312ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("1234");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("12340");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("123400");
- EXPECT_EQ(0x3412ull, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("123456789ABCDEF0");
- EXPECT_EQ(0xF0DEBC9A78563412ULL, ex.GetHexMaxU64(true, 0));
-
- ex.Reset("123456789ABCDEF01");
- EXPECT_EQ(0ull, ex.GetHexMaxU64(true, 0));
-}
-
-TEST_F(StringExtractorTest, GetU64BigEndian) {
- StringExtractor ex("");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("0");
- EXPECT_EQ(0x0ull, ex.GetHexMaxU64(false, 1));
-
- ex.Reset("1");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("01");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("001");
- EXPECT_EQ(0x1ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("12");
- EXPECT_EQ(0x12ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("123");
- EXPECT_EQ(0x123ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("1203");
- EXPECT_EQ(0x1203ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("1234");
- EXPECT_EQ(0x1234ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("12340");
- EXPECT_EQ(0x12340ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("123400");
- EXPECT_EQ(0x123400ull, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("123456789ABCDEF0");
- EXPECT_EQ(0x123456789ABCDEF0ULL, ex.GetHexMaxU64(false, 0));
-
- ex.Reset("123456789ABCDEF000");
- EXPECT_EQ(0ull, ex.GetHexMaxU64(false, 0));
-}
+++ /dev/null
-//===-- StringLexerTest.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StringLexer.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(StringLexerTest, GetUnlexed) {
- StringLexer l("foo");
- EXPECT_EQ("foo", l.GetUnlexed());
- l.Next();
- EXPECT_EQ("oo", l.GetUnlexed());
- l.Next();
- l.Next();
- EXPECT_EQ("", l.GetUnlexed());
-}
-
-TEST(StringLexerTest, HasAtLeast) {
- StringLexer l("foo");
- EXPECT_FALSE(l.HasAtLeast(5));
- EXPECT_FALSE(l.HasAtLeast(4));
- EXPECT_TRUE(l.HasAtLeast(3));
- EXPECT_TRUE(l.HasAtLeast(2));
- EXPECT_TRUE(l.HasAtLeast(1));
-
- l.Next();
- EXPECT_FALSE(l.HasAtLeast(5));
- EXPECT_FALSE(l.HasAtLeast(4));
- EXPECT_FALSE(l.HasAtLeast(3));
- EXPECT_TRUE(l.HasAtLeast(2));
- EXPECT_TRUE(l.HasAtLeast(1));
-
- l.Next();
- l.Next();
- EXPECT_FALSE(l.HasAtLeast(5));
- EXPECT_FALSE(l.HasAtLeast(4));
- EXPECT_FALSE(l.HasAtLeast(3));
- EXPECT_FALSE(l.HasAtLeast(2));
- EXPECT_FALSE(l.HasAtLeast(1));
-}
-
-TEST(StringLexerTest, AdvanceIf) {
- StringLexer l("foobar");
-
- EXPECT_FALSE(l.AdvanceIf("oo"));
- // Skip the "fo" part.
- EXPECT_TRUE(l.AdvanceIf("fo"));
- EXPECT_FALSE(l.AdvanceIf("obarz"));
- // Skip the remaining string.
- EXPECT_TRUE(l.AdvanceIf("obar"));
-
- EXPECT_FALSE(l.AdvanceIf("obarz"));
- EXPECT_FALSE(l.AdvanceIf("foo"));
- EXPECT_FALSE(l.AdvanceIf("o"));
- EXPECT_FALSE(l.AdvanceIf(" "));
-}
-
-TEST(StringLexerTest, PutBack) {
- StringLexer l("foo");
-
- l.Next();
- l.PutBack(1);
- EXPECT_EQ("foo", l.GetUnlexed());
-
- l.Next();
- l.Next();
- l.Next();
- l.PutBack(2);
- EXPECT_EQ("oo", l.GetUnlexed());
-
- l.PutBack(1);
- EXPECT_EQ("foo", l.GetUnlexed());
-}
-
-TEST(StringLexerTest, Peek) {
- StringLexer l("foo");
-
- EXPECT_EQ('f', l.Peek());
- l.Next();
- EXPECT_EQ('o', l.Peek());
- l.Next();
- EXPECT_EQ('o', l.Peek());
-}
-
-TEST(StringLexerTest, Next) {
- StringLexer l("foo");
- EXPECT_EQ('f', l.Next());
- EXPECT_EQ('o', l.Next());
- EXPECT_EQ('o', l.Next());
-}
-
-TEST(StringLexerTest, NextIf) {
- StringLexer l("foo");
-
- EXPECT_FALSE(l.NextIf('\0'));
- EXPECT_FALSE(l.NextIf(' '));
- EXPECT_FALSE(l.NextIf('o'));
-
- EXPECT_TRUE(l.NextIf('f'));
-
- EXPECT_FALSE(l.NextIf('\0'));
- EXPECT_FALSE(l.NextIf(' '));
- EXPECT_FALSE(l.NextIf('f'));
-
- EXPECT_TRUE(l.NextIf('o'));
-
- EXPECT_FALSE(l.NextIf('\0'));
- EXPECT_FALSE(l.NextIf(' '));
- EXPECT_FALSE(l.NextIf('f'));
-
- EXPECT_TRUE(l.NextIf('o'));
-}
-
-TEST(StringLexerTest, NextIfList) {
- StringLexer l("foo");
-
- EXPECT_FALSE(l.NextIf({'\0', ' ', 'o'}).first);
-
- auto r = l.NextIf({'f'});
- EXPECT_TRUE(r.first);
- EXPECT_EQ('f', r.second);
-
- EXPECT_FALSE(l.NextIf({'\0', ' ', 'f'}).first);
-
- r = l.NextIf({'f', 'o'});
- EXPECT_TRUE(r.first);
- EXPECT_EQ('o', r.second);
-
- EXPECT_FALSE(l.NextIf({'\0', ' ', 'f'}).first);
-
- r = l.NextIf({'*', 'f', 'o', 'o'});
- EXPECT_TRUE(r.first);
- EXPECT_EQ('o', r.second);
-}
+++ /dev/null
-//===-- StringListTest.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StringList.h"
-#include "lldb/Utility/StreamString.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-TEST(StringListTest, DefaultConstructor) {
- StringList s;
- EXPECT_EQ(0U, s.GetSize());
-}
-
-TEST(StringListTest, Assignment) {
- StringList orig;
- orig.AppendString("foo");
- orig.AppendString("bar");
-
- StringList s = orig;
-
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-
- ASSERT_EQ(2U, orig.GetSize());
- EXPECT_STREQ("foo", orig.GetStringAtIndex(0));
- EXPECT_STREQ("bar", orig.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, AppendStringStdString) {
- StringList s;
- s.AppendString("foo");
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s.AppendString("bar");
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, AppendStringCString) {
- StringList s;
- s.AppendString("foo", strlen("foo"));
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s.AppendString("bar", strlen("bar"));
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, AppendStringMove) {
- StringList s;
- std::string foo = "foo";
- std::string bar = "bar";
-
- s.AppendString(std::move(foo));
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s.AppendString(std::move(bar));
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, ShiftStdString) {
- StringList s;
- std::string foo = "foo";
- std::string bar = "bar";
-
- s << foo;
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s << bar;
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, ShiftCString) {
- StringList s;
- s << "foo";
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s << "bar";
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, ShiftMove) {
- StringList s;
- std::string foo = "foo";
- std::string bar = "bar";
-
- s << std::move(foo);
- ASSERT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s << std::move(bar);
- ASSERT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, AppendListCStringArrayEmpty) {
- StringList s;
- s.AppendList(nullptr, 0);
- EXPECT_EQ(0U, s.GetSize());
-}
-
-TEST(StringListTest, AppendListCStringArray) {
- StringList s;
- const char *items[3] = {"foo", "", "bar"};
- s.AppendList(items, 3);
-
- EXPECT_EQ(3U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("", s.GetStringAtIndex(1));
- EXPECT_STREQ("bar", s.GetStringAtIndex(2));
-}
-
-TEST(StringListTest, AppendList) {
- StringList other;
- other.AppendString("foo");
- other.AppendString("");
- other.AppendString("bar");
-
- StringList empty;
-
- StringList s;
- s.AppendList(other);
-
- EXPECT_EQ(3U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("", s.GetStringAtIndex(1));
- EXPECT_STREQ("bar", s.GetStringAtIndex(2));
-
- EXPECT_EQ(3U, other.GetSize());
- EXPECT_STREQ("foo", other.GetStringAtIndex(0));
- EXPECT_STREQ("", other.GetStringAtIndex(1));
- EXPECT_STREQ("bar", other.GetStringAtIndex(2));
-
- s.AppendList(empty);
- s.AppendList(other);
- EXPECT_EQ(6U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("", s.GetStringAtIndex(1));
- EXPECT_STREQ("bar", s.GetStringAtIndex(2));
- EXPECT_STREQ("foo", s.GetStringAtIndex(3));
- EXPECT_STREQ("", s.GetStringAtIndex(4));
- EXPECT_STREQ("bar", s.GetStringAtIndex(5));
-
- EXPECT_EQ(3U, other.GetSize());
- EXPECT_STREQ("foo", other.GetStringAtIndex(0));
- EXPECT_STREQ("", other.GetStringAtIndex(1));
- EXPECT_STREQ("bar", other.GetStringAtIndex(2));
-}
-
-TEST(StringListTest, GetSize) {
- StringList s;
- s.AppendString("foo");
- EXPECT_EQ(1U, s.GetSize());
-
- s.AppendString("foo");
- EXPECT_EQ(2U, s.GetSize());
-
- s.AppendString("foobar");
- EXPECT_EQ(3U, s.GetSize());
-}
-
-TEST(StringListTest, SetSize) {
- StringList s;
- s.SetSize(3);
- EXPECT_EQ(3U, s.GetSize());
- EXPECT_STREQ("", s.GetStringAtIndex(0));
- EXPECT_STREQ("", s.GetStringAtIndex(1));
- EXPECT_STREQ("", s.GetStringAtIndex(2));
-}
-
-TEST(StringListTest, SplitIntoLines) {
- StringList s;
- s.SplitIntoLines("\nfoo\nbar\n\n");
- EXPECT_EQ(4U, s.GetSize());
- EXPECT_STREQ("", s.GetStringAtIndex(0));
- EXPECT_STREQ("foo", s.GetStringAtIndex(1));
- EXPECT_STREQ("bar", s.GetStringAtIndex(2));
- EXPECT_STREQ("", s.GetStringAtIndex(3));
-}
-
-TEST(StringListTest, SplitIntoLinesSingleTrailingCR) {
- StringList s;
- s.SplitIntoLines("\r");
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("", s.GetStringAtIndex(0));
-}
-
-TEST(StringListTest, SplitIntoLinesEmpty) {
- StringList s;
- s.SplitIntoLines("");
- EXPECT_EQ(0U, s.GetSize());
-}
-
-TEST(StringListTest, LongestCommonPrefixEmpty) {
- StringList s;
- std::string prefix = s.LongestCommonPrefix();
- EXPECT_EQ("", prefix);
-}
-
-TEST(StringListTest, LongestCommonPrefix) {
- StringList s;
- s.AppendString("foo");
- s.AppendString("foobar");
- s.AppendString("foo");
- s.AppendString("foozar");
-
- std::string prefix = s.LongestCommonPrefix();
- EXPECT_EQ("foo", prefix);
-}
-
-TEST(StringListTest, LongestCommonPrefixSingleElement) {
- StringList s;
- s.AppendString("foo");
-
- std::string prefix = s.LongestCommonPrefix();
- EXPECT_EQ("foo", prefix);
-}
-
-TEST(StringListTest, LongestCommonPrefixDuplicateElement) {
- StringList s;
- s.AppendString("foo");
- s.AppendString("foo");
-
- std::string prefix = s.LongestCommonPrefix();
- EXPECT_EQ("foo", prefix);
-}
-
-TEST(StringListTest, LongestCommonPrefixNoPrefix) {
- StringList s;
- s.AppendString("foo");
- s.AppendString("1foobar");
- s.AppendString("2foo");
- s.AppendString("3foozar");
-
- std::string prefix = s.LongestCommonPrefix();
- EXPECT_EQ("", prefix);
-}
-
-TEST(StringListTest, Clear) {
- StringList s;
- s.Clear();
- EXPECT_EQ(0U, s.GetSize());
-
- s.AppendString("foo");
- s.Clear();
- EXPECT_EQ(0U, s.GetSize());
-
- s.AppendString("foo");
- s.AppendString("foo");
- s.Clear();
- EXPECT_EQ(0U, s.GetSize());
-}
-
-TEST(StringListTest, PopBack) {
- StringList s;
- s.AppendString("foo");
- s.AppendString("bar");
- s.AppendString("boo");
-
- s.PopBack();
- EXPECT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-
- s.PopBack();
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s.PopBack();
- EXPECT_EQ(0U, s.GetSize());
-}
-
-TEST(StringListTest, RemoveBlankLines) {
- StringList s;
-
- // Nothing to remove yet.
- s.RemoveBlankLines();
- EXPECT_EQ(0U, s.GetSize());
-
- // Add some lines.
- s.AppendString("");
- s.AppendString("");
- s.AppendString("\t");
- s.AppendString("");
- s.AppendString(" ");
- s.AppendString("");
- s.AppendString("");
- s.AppendString("f");
- s.AppendString("");
- s.AppendString("");
-
- // And remove all the empty ones again.
- s.RemoveBlankLines();
-
- EXPECT_EQ(3U, s.GetSize());
- EXPECT_STREQ("\t", s.GetStringAtIndex(0));
- EXPECT_STREQ(" ", s.GetStringAtIndex(1));
- EXPECT_STREQ("f", s.GetStringAtIndex(2));
-}
-
-TEST(StringListTest, InsertStringAtIndexStart) {
- StringList s;
-
- s.InsertStringAtIndex(0, "bar");
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("bar", s.GetStringAtIndex(0));
-
- s.InsertStringAtIndex(0, "foo");
- EXPECT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, InsertStringAtIndexEnd) {
- StringList s;
-
- s.InsertStringAtIndex(0, "foo");
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- s.InsertStringAtIndex(1, "bar");
- EXPECT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, InsertStringAtIndexOutOfBounds) {
- StringList s;
-
- s.InsertStringAtIndex(1, "foo");
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-
- // FIXME: Inserting at an OOB index will always just append to the list. This
- // seems not very intuitive.
- s.InsertStringAtIndex(3, "bar");
- EXPECT_EQ(2U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
- EXPECT_STREQ("bar", s.GetStringAtIndex(1));
-}
-
-TEST(StringListTest, InsertStringAtIndexStdString) {
- StringList s;
-
- std::string foo = "foo";
- s.InsertStringAtIndex(0, foo);
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-}
-
-TEST(StringListTest, InsertStringAtIndexMove) {
- StringList s;
-
- std::string foo = "foo";
- s.InsertStringAtIndex(0, std::move(foo));
- EXPECT_EQ(1U, s.GetSize());
- EXPECT_STREQ("foo", s.GetStringAtIndex(0));
-}
-
-TEST(StringListTest, CopyListEmpty) {
- StringList s;
-
- EXPECT_EQ("", s.CopyList());
- EXPECT_EQ("", s.CopyList("+"));
-}
-
-TEST(StringListTest, CopyListSingle) {
- StringList s;
- s.AppendString("ab");
-
- EXPECT_EQ("ab", s.CopyList());
- EXPECT_EQ("-ab", s.CopyList("-"));
-}
-
-TEST(StringListTest, CopyList) {
- StringList s;
- s.AppendString("ab");
- s.AppendString("cd");
-
- EXPECT_EQ("ab\ncd", s.CopyList());
- EXPECT_EQ("-ab\n-cd", s.CopyList("-"));
-}
-
-TEST(StringListTest, Join) {
- StringList s;
- s.AppendString("ab");
- s.AppendString("cd");
-
- StreamString ss;
- s.Join(" ", ss);
-
- EXPECT_EQ("ab cd", ss.GetString());
-}
-
-TEST(StringListTest, JoinEmpty) {
- StringList s;
-
- StreamString ss;
- s.Join(" ", ss);
-
- EXPECT_EQ("", ss.GetString());
-}
-
-TEST(StringListTest, JoinSingle) {
- StringList s;
- s.AppendString("foo");
-
- StreamString ss;
- s.Join(" ", ss);
-
- EXPECT_EQ("foo", ss.GetString());
-}
-
-TEST(StringListTest, JoinThree) {
- StringList s;
- s.AppendString("1");
- s.AppendString("2");
- s.AppendString("3");
-
- StreamString ss;
- s.Join(" ", ss);
-
- EXPECT_EQ("1 2 3", ss.GetString());
-}
-
-TEST(StringListTest, JoinNonSpace) {
- StringList s;
- s.AppendString("1");
- s.AppendString("2");
- s.AppendString("3");
-
- StreamString ss;
- s.Join(".", ss);
-
- EXPECT_EQ("1.2.3", ss.GetString());
-}
-
-TEST(StringListTest, JoinMultiCharSeparator) {
- StringList s;
- s.AppendString("1");
- s.AppendString("2");
- s.AppendString("3");
-
- StreamString ss;
- s.Join("--", ss);
-
- EXPECT_EQ("1--2--3", ss.GetString());
-}
-
-TEST(StringListTest, GetMaxStringLengthEqualSize) {
- StringList s;
- s.AppendString("123");
- s.AppendString("123");
- EXPECT_EQ(3U, s.GetMaxStringLength());
-}
-
-TEST(StringListTest, GetMaxStringLengthIncreasingSize) {
- StringList s;
- s.AppendString("123");
- s.AppendString("1234");
- EXPECT_EQ(4U, s.GetMaxStringLength());
-}
-
-TEST(StringListTest, GetMaxStringLengthDecreasingSize) {
- StringList s;
- s.AppendString("1234");
- s.AppendString("123");
- EXPECT_EQ(4U, s.GetMaxStringLength());
-}
-
-TEST(StringListTest, GetMaxStringLengthMixed) {
- StringList s;
- s.AppendString("123");
- s.AppendString("1");
- s.AppendString("123");
- s.AppendString("1234");
- s.AppendString("123");
- s.AppendString("1");
- EXPECT_EQ(4U, s.GetMaxStringLength());
-}
-
-TEST(StringListTest, GetMaxStringLengthEmpty) {
- StringList s;
- EXPECT_EQ(0U, s.GetMaxStringLength());
-}
-
-TEST(StringListTest, ForRangeEmpty) {
- StringList s;
- for (const std::string &e : s)
- FAIL() << "Shouldn't have hit an element in for range" << e;
-}
-
-TEST(StringListTest, ForRange) {
- StringList s;
- s.AppendString("a");
- s.AppendString("b");
- s.AppendString("c");
- std::vector<std::string> recorded;
- for (const std::string &e : s)
- recorded.push_back(e);
- EXPECT_THAT(recorded, testing::ElementsAre("a", "b", "c"));
-}
+++ /dev/null
-//===-- StructuredDataTest.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "TestingSupport/TestUtilities.h"
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/StructuredData.h"
-#include "llvm/Support/Path.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(StructuredDataTest, StringDump) {
- std::pair<llvm::StringRef, llvm::StringRef> TestCases[] = {
- {R"(asdfg)", R"("asdfg")"},
- {R"(as"df)", R"("as\"df")"},
- {R"(as\df)", R"("as\\df")"},
- };
- for (auto P : TestCases) {
- StreamString S;
- const bool pretty_print = false;
- StructuredData::String(P.first).Dump(S, pretty_print);
- EXPECT_EQ(P.second, S.GetString());
- }
-}
-
-TEST(StructuredDataTest, ParseJSONFromFile) {
- Status status;
- auto object_sp = StructuredData::ParseJSONFromFile(
- FileSpec("non-existing-file.json"), status);
- EXPECT_EQ(nullptr, object_sp);
-
- std::string input = GetInputFilePath("StructuredData-basic.json");
- object_sp = StructuredData::ParseJSONFromFile(FileSpec(input), status);
- ASSERT_NE(nullptr, object_sp);
-
- StreamString S;
- object_sp->Dump(S, false);
- EXPECT_EQ("[1,2,3]", S.GetString());
-}
+++ /dev/null
-//===-- SubsystemRAIITest.cpp ---------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest-spi.h"
-#include "gtest/gtest.h"
-
-#include "TestingSupport/SubsystemRAII.h"
-
-using namespace lldb_private;
-
-namespace {
-
-enum class SystemState {
- /// Start state of the subsystem.
- Start,
- /// Initialize has been called but Terminate hasn't been called yet.
- Initialized,
- /// Terminate has been called.
- Terminated
-};
-
-struct TestSubsystem {
- static SystemState state;
- static void Initialize() {
- assert(state == SystemState::Start);
- state = SystemState::Initialized;
- }
- static void Terminate() {
- assert(state == SystemState::Initialized);
- state = SystemState::Terminated;
- }
-};
-} // namespace
-
-SystemState TestSubsystem::state = SystemState::Start;
-
-TEST(SubsystemRAIITest, NormalSubsystem) {
- // Tests that SubsystemRAII handles Initialize functions that return void.
- EXPECT_EQ(SystemState::Start, TestSubsystem::state);
- {
- SubsystemRAII<TestSubsystem> subsystem;
- EXPECT_EQ(SystemState::Initialized, TestSubsystem::state);
- }
- EXPECT_EQ(SystemState::Terminated, TestSubsystem::state);
-}
-
-static const char *SubsystemErrorString = "Initialize failed";
-
-namespace {
-struct TestSubsystemWithError {
- static SystemState state;
- static bool will_fail;
- static llvm::Error Initialize() {
- assert(state == SystemState::Start);
- state = SystemState::Initialized;
- if (will_fail)
- return llvm::make_error<llvm::StringError>(
- SubsystemErrorString, llvm::inconvertibleErrorCode());
- return llvm::Error::success();
- }
- static void Terminate() {
- assert(state == SystemState::Initialized);
- state = SystemState::Terminated;
- }
- /// Reset the subsystem to the default state for testing.
- static void Reset() { state = SystemState::Start; }
-};
-} // namespace
-
-SystemState TestSubsystemWithError::state = SystemState::Start;
-bool TestSubsystemWithError::will_fail = false;
-
-TEST(SubsystemRAIITest, SubsystemWithErrorSuccess) {
- // Tests that SubsystemRAII handles llvm::success() returned from
- // Initialize.
- TestSubsystemWithError::Reset();
- EXPECT_EQ(SystemState::Start, TestSubsystemWithError::state);
- {
- TestSubsystemWithError::will_fail = false;
- SubsystemRAII<TestSubsystemWithError> subsystem;
- EXPECT_EQ(SystemState::Initialized, TestSubsystemWithError::state);
- }
- EXPECT_EQ(SystemState::Terminated, TestSubsystemWithError::state);
-}
-
-TEST(SubsystemRAIITest, SubsystemWithErrorFailure) {
- // Tests that SubsystemRAII handles any errors returned from
- // Initialize.
- TestSubsystemWithError::Reset();
- EXPECT_EQ(SystemState::Start, TestSubsystemWithError::state);
- TestSubsystemWithError::will_fail = true;
- EXPECT_FATAL_FAILURE(SubsystemRAII<TestSubsystemWithError> subsystem,
- SubsystemErrorString);
-}
+++ /dev/null
-#include "gtest/gtest.h"
-
-#include "TestingSupport/MockTildeExpressionResolver.h"
-#include "lldb/Utility/TildeExpressionResolver.h"
-
-#include "llvm/ADT/SmallString.h"
-
-using namespace llvm;
-using namespace lldb_private;
-
-TEST(TildeExpressionResolver, ResolveFullPath) {
- MockTildeExpressionResolver Resolver("James", "/james");
- Resolver.AddKnownUser("Kirk", "/kirk");
- Resolver.AddKnownUser("Lars", "/lars");
- Resolver.AddKnownUser("Jason", "/jason");
- Resolver.AddKnownUser("Larry", "/larry");
-
- SmallString<32> Result;
- ASSERT_TRUE(Resolver.ResolveFullPath("~", Result));
- EXPECT_EQ("/james", Result);
- ASSERT_TRUE(Resolver.ResolveFullPath("~/", Result));
- EXPECT_EQ("/james/", Result);
-
- ASSERT_TRUE(Resolver.ResolveFullPath("~James/bar/baz", Result));
- EXPECT_EQ("/james/bar/baz", Result);
-
- ASSERT_TRUE(Resolver.ResolveFullPath("~Jason/", Result));
- EXPECT_EQ("/jason/", Result);
-
- ASSERT_TRUE(Resolver.ResolveFullPath("~Lars", Result));
- EXPECT_EQ("/lars", Result);
-
- ASSERT_FALSE(Resolver.ResolveFullPath("~Jaso", Result));
- EXPECT_EQ("~Jaso", Result);
- ASSERT_FALSE(Resolver.ResolveFullPath("", Result));
- EXPECT_EQ("", Result);
- ASSERT_FALSE(Resolver.ResolveFullPath("Jason", Result));
- EXPECT_EQ("Jason", Result);
-}
+++ /dev/null
-//===-- TimeoutTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/Timeout.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace std::chrono;
-
-TEST(TimeoutTest, Construction) {
- EXPECT_FALSE(Timeout<std::micro>(llvm::None));
- EXPECT_TRUE(bool(Timeout<std::micro>(seconds(0))));
- EXPECT_EQ(seconds(0), *Timeout<std::micro>(seconds(0)));
- EXPECT_EQ(seconds(3), *Timeout<std::micro>(seconds(3)));
- EXPECT_TRUE(bool(Timeout<std::micro>(Timeout<std::milli>(seconds(0)))));
-}
-
-TEST(TimeoutTest, Format) {
- EXPECT_EQ("<infinite>",
- llvm::formatv("{0}", Timeout<std::milli>(llvm::None)).str());
- EXPECT_EQ("1000 ms",
- llvm::formatv("{0}", Timeout<std::milli>(seconds(1))).str());
-}
+++ /dev/null
-//===-- TimerTest.cpp -----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/Timer.h"
-#include "gtest/gtest.h"
-#include <thread>
-
-using namespace lldb_private;
-
-TEST(TimerTest, CategoryTimes) {
- Timer::ResetCategoryTimes();
- {
- static Timer::Category tcat("CAT1");
- Timer t(tcat, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- StreamString ss;
- Timer::DumpCategoryTimes(&ss);
- double seconds;
- ASSERT_EQ(1, sscanf(ss.GetData(), "%lf sec for CAT1", &seconds));
- EXPECT_LT(0.001, seconds);
- EXPECT_GT(0.1, seconds);
-}
-
-TEST(TimerTest, CategoryTimesNested) {
- Timer::ResetCategoryTimes();
- {
- static Timer::Category tcat1("CAT1");
- Timer t1(tcat1, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- // Explicitly testing the same category as above.
- Timer t2(tcat1, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- StreamString ss;
- Timer::DumpCategoryTimes(&ss);
- double seconds;
- // It should only appear once.
- ASSERT_EQ(ss.GetString().count("CAT1"), 1U);
- ASSERT_EQ(1, sscanf(ss.GetData(), "%lf sec for CAT1", &seconds));
- EXPECT_LT(0.002, seconds);
- EXPECT_GT(0.2, seconds);
-}
-
-TEST(TimerTest, CategoryTimes2) {
- Timer::ResetCategoryTimes();
- {
- static Timer::Category tcat1("CAT1");
- Timer t1(tcat1, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- static Timer::Category tcat2("CAT2");
- Timer t2(tcat2, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- StreamString ss;
- Timer::DumpCategoryTimes(&ss);
- double seconds1, seconds2;
- ASSERT_EQ(2, sscanf(ss.GetData(),
- "%lf sec (total: %*fs; child: %*fs; count: %*d) for "
- "CAT1%*[\n ]%lf sec for CAT2",
- &seconds1, &seconds2))
- << "String: " << ss.GetData();
- EXPECT_LT(0.01, seconds1);
- EXPECT_GT(1, seconds1);
- EXPECT_LT(0.001, seconds2);
- EXPECT_GT(0.1, seconds2);
-}
-
-TEST(TimerTest, CategoryTimesStats) {
- Timer::ResetCategoryTimes();
- {
- static Timer::Category tcat1("CAT1");
- Timer t1(tcat1, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- static Timer::Category tcat2("CAT2");
- {
- Timer t2(tcat2, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- {
- Timer t3(tcat2, ".");
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
- // Example output:
- // 0.105202764 sec (total: 0.132s; child: 0.027s; count: 1) for CAT1
- // 0.026772798 sec (total: 0.027s; child: 0.000s; count: 2) for CAT2
- StreamString ss;
- Timer::DumpCategoryTimes(&ss);
- double seconds1, total1, child1, seconds2;
- int count1, count2;
- ASSERT_EQ(
- 6, sscanf(ss.GetData(),
- "%lf sec (total: %lfs; child: %lfs; count: %d) for CAT1%*[\n\r ]"
- "%lf sec (total: %*fs; child: %*fs; count: %d) for CAT2",
- &seconds1, &total1, &child1, &count1, &seconds2, &count2))
- << "String: " << ss.GetData();
- EXPECT_NEAR(total1 - child1, seconds1, 0.002);
- EXPECT_EQ(1, count1);
- EXPECT_NEAR(child1, seconds2, 0.002);
- EXPECT_EQ(2, count2);
-}
+++ /dev/null
-//===-- UUIDTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/UUID.h"
-
-using namespace lldb_private;
-
-TEST(UUIDTest, RelationalOperators) {
- UUID empty;
- UUID a16 = UUID::fromData("1234567890123456", 16);
- UUID b16 = UUID::fromData("1234567890123457", 16);
- UUID a20 = UUID::fromData("12345678901234567890", 20);
- UUID b20 = UUID::fromData("12345678900987654321", 20);
-
- EXPECT_EQ(empty, empty);
- EXPECT_EQ(a16, a16);
- EXPECT_EQ(a20, a20);
-
- EXPECT_NE(a16, b16);
- EXPECT_NE(a20, b20);
- EXPECT_NE(a16, a20);
- EXPECT_NE(empty, a16);
-
- EXPECT_LT(empty, a16);
- EXPECT_LT(a16, a20);
- EXPECT_LT(a16, b16);
- EXPECT_GT(a20, b20);
-}
-
-TEST(UUIDTest, Validity) {
- UUID empty;
- std::vector<uint8_t> zeroes(20, 0);
- UUID a16 = UUID::fromData(zeroes.data(), 16);
- UUID a20 = UUID::fromData(zeroes.data(), 20);
- UUID a16_0 = UUID::fromOptionalData(zeroes.data(), 16);
- UUID a20_0 = UUID::fromOptionalData(zeroes.data(), 20);
- UUID from_str;
- from_str.SetFromStringRef("00000000-0000-0000-0000-000000000000");
- UUID opt_from_str;
- opt_from_str.SetFromOptionalStringRef("00000000-0000-0000-0000-000000000000");
-
- EXPECT_FALSE(empty);
- EXPECT_TRUE(a16);
- EXPECT_TRUE(a20);
- EXPECT_TRUE(from_str);
- EXPECT_FALSE(a16_0);
- EXPECT_FALSE(a20_0);
- EXPECT_FALSE(opt_from_str);
-}
-
-TEST(UUIDTest, SetFromStringRef) {
- UUID u;
- EXPECT_TRUE(u.SetFromStringRef("404142434445464748494a4b4c4d4e4f"));
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16), u);
-
- EXPECT_TRUE(u.SetFromStringRef("40-41-42-43-4445464748494a4b4c4d4e4f"));
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16), u);
-
- EXPECT_TRUE(
- u.SetFromStringRef("40-41-42-43-4445464748494a4b4c4d4e4f-50515253"));
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20), u);
-
- EXPECT_TRUE(u.SetFromStringRef("40-41-42-43-4445464748494a4b4c4d4e4f"));
-
- EXPECT_FALSE(u.SetFromStringRef("40xxxxx"));
- EXPECT_FALSE(u.SetFromStringRef(""));
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNO", 16), u)
- << "uuid was changed by failed parse calls";
-
- EXPECT_TRUE(u.SetFromStringRef("404142434445464748494a4b4c4d4e4f-50515253"));
- EXPECT_EQ(UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20), u);
-
- EXPECT_TRUE(u.SetFromStringRef("40414243"));
- EXPECT_EQ(UUID::fromData("@ABCD", 4), u);
-
- EXPECT_FALSE(u.SetFromStringRef("4"));
-}
-
-TEST(UUIDTest, StringConverion) {
- EXPECT_EQ("40414243", UUID::fromData("@ABC", 4).GetAsString());
- EXPECT_EQ("40414243-4445-4647", UUID::fromData("@ABCDEFG", 8).GetAsString());
- EXPECT_EQ("40414243-4445-4647-4849-4A4B",
- UUID::fromData("@ABCDEFGHIJK", 12).GetAsString());
- EXPECT_EQ("40414243-4445-4647-4849-4A4B4C4D4E4F",
- UUID::fromData("@ABCDEFGHIJKLMNO", 16).GetAsString());
- EXPECT_EQ("40414243-4445-4647-4849-4A4B4C4D4E4F-50515253",
- UUID::fromData("@ABCDEFGHIJKLMNOPQRS", 20).GetAsString());
-}
+++ /dev/null
-#include "lldb/Utility/UriParser.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-
-// result strings (scheme/hostname/port/path) passed into UriParser::Parse
-// are initialized to kAsdf so we can verify that they are unmodified if the
-// URI is invalid
-static const char *kAsdf = "asdf";
-
-class UriTestCase {
-public:
- UriTestCase(const char *uri, const char *scheme, const char *hostname,
- int port, const char *path)
- : m_uri(uri), m_result(true), m_scheme(scheme), m_hostname(hostname),
- m_port(port), m_path(path) {}
-
- UriTestCase(const char *uri)
- : m_uri(uri), m_result(false), m_scheme(kAsdf), m_hostname(kAsdf),
- m_port(1138), m_path(kAsdf) {}
-
- const char *m_uri;
- bool m_result;
- const char *m_scheme;
- const char *m_hostname;
- int m_port;
- const char *m_path;
-};
-
-#define VALIDATE \
- llvm::StringRef scheme(kAsdf); \
- llvm::StringRef hostname(kAsdf); \
- int port(1138); \
- llvm::StringRef path(kAsdf); \
- EXPECT_EQ(testCase.m_result, \
- UriParser::Parse(testCase.m_uri, scheme, hostname, port, path)); \
- EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str()); \
- EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str()); \
- EXPECT_EQ(testCase.m_port, port); \
- EXPECT_STREQ(testCase.m_path, path.str().c_str());
-
-TEST(UriParserTest, Minimal) {
- const UriTestCase testCase("x://y", "x", "y", -1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, MinimalPort) {
- const UriTestCase testCase("x://y:1", "x", "y", 1, "/");
- llvm::StringRef scheme(kAsdf);
- llvm::StringRef hostname(kAsdf);
- int port(1138);
- llvm::StringRef path(kAsdf);
- bool result = UriParser::Parse(testCase.m_uri, scheme, hostname, port, path);
- EXPECT_EQ(testCase.m_result, result);
-
- EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str());
- EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str());
- EXPECT_EQ(testCase.m_port, port);
- EXPECT_STREQ(testCase.m_path, path.str().c_str());
-}
-
-TEST(UriParserTest, MinimalPath) {
- const UriTestCase testCase("x://y/", "x", "y", -1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, MinimalPortPath) {
- const UriTestCase testCase("x://y:1/", "x", "y", 1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, LongPath) {
- const UriTestCase testCase("x://y/abc/def/xyz", "x", "y", -1, "/abc/def/xyz");
- VALIDATE
-}
-
-TEST(UriParserTest, TypicalPortPathIPv4) {
- const UriTestCase testCase("connect://192.168.100.132:5432/", "connect",
- "192.168.100.132", 5432, "/");
- VALIDATE;
-}
-
-TEST(UriParserTest, TypicalPortPathIPv6) {
- const UriTestCase testCase(
- "connect://[2601:600:107f:db64:a42b:4faa:284:3082]:5432/", "connect",
- "2601:600:107f:db64:a42b:4faa:284:3082", 5432, "/");
- VALIDATE;
-}
-
-TEST(UriParserTest, BracketedHostnamePort) {
- const UriTestCase testCase("connect://[192.168.100.132]:5432/", "connect",
- "192.168.100.132", 5432, "/");
- llvm::StringRef scheme(kAsdf);
- llvm::StringRef hostname(kAsdf);
- int port(1138);
- llvm::StringRef path(kAsdf);
- bool result = UriParser::Parse(testCase.m_uri, scheme, hostname, port, path);
- EXPECT_EQ(testCase.m_result, result);
-
- EXPECT_STREQ(testCase.m_scheme, scheme.str().c_str());
- EXPECT_STREQ(testCase.m_hostname, hostname.str().c_str());
- EXPECT_EQ(testCase.m_port, port);
- EXPECT_STREQ(testCase.m_path, path.str().c_str());
-}
-
-TEST(UriParserTest, BracketedHostname) {
- const UriTestCase testCase("connect://[192.168.100.132]", "connect",
- "192.168.100.132", -1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, BracketedHostnameWithPortIPv4) {
- // Android device over IPv4: port is a part of the hostname.
- const UriTestCase testCase("connect://[192.168.100.132:1234]", "connect",
- "192.168.100.132:1234", -1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, BracketedHostnameWithPortIPv6) {
- // Android device over IPv6: port is a part of the hostname.
- const UriTestCase testCase(
- "connect://[[2601:600:107f:db64:a42b:4faa:284]:1234]", "connect",
- "[2601:600:107f:db64:a42b:4faa:284]:1234", -1, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, BracketedHostnameWithColon) {
- const UriTestCase testCase("connect://[192.168.100.132:5555]:1234", "connect",
- "192.168.100.132:5555", 1234, "/");
- VALIDATE
-}
-
-TEST(UriParserTest, SchemeHostSeparator) {
- const UriTestCase testCase("x:/y");
- VALIDATE
-}
-
-TEST(UriParserTest, SchemeHostSeparator2) {
- const UriTestCase testCase("x:y");
- VALIDATE
-}
-
-TEST(UriParserTest, SchemeHostSeparator3) {
- const UriTestCase testCase("x//y");
- VALIDATE
-}
-
-TEST(UriParserTest, SchemeHostSeparator4) {
- const UriTestCase testCase("x/y");
- VALIDATE
-}
-
-TEST(UriParserTest, BadPort) {
- const UriTestCase testCase("x://y:a/");
- VALIDATE
-}
-
-TEST(UriParserTest, BadPort2) {
- const UriTestCase testCase("x://y:5432a/");
- VALIDATE
-}
-
-TEST(UriParserTest, Empty) {
- const UriTestCase testCase("");
- VALIDATE
-}
-
-TEST(UriParserTest, PortOverflow) {
- const UriTestCase testCase("x://"
- "y:"
- "0123456789012345678901234567890123456789012345678"
- "9012345678901234567890123456789012345678901234567"
- "89/");
- VALIDATE
-}
+++ /dev/null
-//===-- UserIDResolverTest.cpp --------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/UserIDResolver.h"
-#include "gmock/gmock.h"
-
-using namespace lldb_private;
-using namespace testing;
-
-namespace {
-class TestUserIDResolver : public UserIDResolver {
-public:
- MOCK_METHOD1(DoGetUserName, llvm::Optional<std::string>(id_t uid));
- MOCK_METHOD1(DoGetGroupName, llvm::Optional<std::string>(id_t gid));
-};
-} // namespace
-
-TEST(UserIDResolver, GetUserName) {
- StrictMock<TestUserIDResolver> r;
- llvm::StringRef user47("foo");
- EXPECT_CALL(r, DoGetUserName(47)).Times(1).WillOnce(Return(user47.str()));
- EXPECT_CALL(r, DoGetUserName(42)).Times(1).WillOnce(Return(llvm::None));
-
- // Call functions twice to make sure the caching works.
- EXPECT_EQ(user47, r.GetUserName(47));
- EXPECT_EQ(user47, r.GetUserName(47));
- EXPECT_EQ(llvm::None, r.GetUserName(42));
- EXPECT_EQ(llvm::None, r.GetUserName(42));
-}
-
-TEST(UserIDResolver, GetGroupName) {
- StrictMock<TestUserIDResolver> r;
- llvm::StringRef group47("foo");
- EXPECT_CALL(r, DoGetGroupName(47)).Times(1).WillOnce(Return(group47.str()));
- EXPECT_CALL(r, DoGetGroupName(42)).Times(1).WillOnce(Return(llvm::None));
-
- // Call functions twice to make sure the caching works.
- EXPECT_EQ(group47, r.GetGroupName(47));
- EXPECT_EQ(group47, r.GetGroupName(47));
- EXPECT_EQ(llvm::None, r.GetGroupName(42));
- EXPECT_EQ(llvm::None, r.GetGroupName(42));
-}
+++ /dev/null
-//===-- VASprintfTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Utility/VASPrintf.h"
-#include "llvm/ADT/SmallString.h"
-
-#include "gtest/gtest.h"
-
-#include <locale.h>
-
-#if defined (_WIN32)
-#define TEST_ENCODING ".932" // On Windows, test codepage 932
-#else
-#define TEST_ENCODING "C" // ...otherwise, any widely available uni-byte LC
-#endif
-
-using namespace lldb_private;
-using namespace llvm;
-
-static bool Sprintf(llvm::SmallVectorImpl<char> &Buffer, const char *Fmt, ...) {
- va_list args;
- va_start(args, Fmt);
- bool Result = VASprintf(Buffer, Fmt, args);
- va_end(args);
- return Result;
-}
-
-TEST(VASprintfTest, NoBufferResize) {
- std::string TestStr("small");
-
- llvm::SmallString<32> BigBuffer;
- ASSERT_TRUE(Sprintf(BigBuffer, "%s", TestStr.c_str()));
- EXPECT_STREQ(TestStr.c_str(), BigBuffer.c_str());
- EXPECT_EQ(TestStr.size(), BigBuffer.size());
-}
-
-TEST(VASprintfTest, BufferResize) {
- std::string TestStr("bigger");
- llvm::SmallString<4> SmallBuffer;
- ASSERT_TRUE(Sprintf(SmallBuffer, "%s", TestStr.c_str()));
- EXPECT_STREQ(TestStr.c_str(), SmallBuffer.c_str());
- EXPECT_EQ(TestStr.size(), SmallBuffer.size());
-}
-
-TEST(VASprintfTest, EncodingError) {
- // Save the current locale first.
- std::string Current(::setlocale(LC_ALL, nullptr));
-
- // Ensure tested locale is successfully set
- ASSERT_TRUE(setlocale(LC_ALL, TEST_ENCODING));
-
- wchar_t Invalid[2];
- Invalid[0] = 0x100;
- Invalid[1] = 0;
- llvm::SmallString<32> Buffer;
- EXPECT_FALSE(Sprintf(Buffer, "%ls", Invalid));
- EXPECT_EQ("<Encoding error>", Buffer);
-
- // Ensure we've restored the original locale once tested
- ASSERT_TRUE(setlocale(LC_ALL, Current.c_str()));
-}
+++ /dev/null
-//===-- VMRangeTest.cpp ---------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include <limits>
-
-#include "lldb/Utility/VMRange.h"
-
-using namespace lldb_private;
-
-namespace lldb_private {
-void PrintTo(const VMRange &v, std::ostream *os) {
- (*os) << "VMRange(" << v.GetBaseAddress() << ", " << v.GetEndAddress() << ")";
-}
-} // namespace lldb_private
-
-TEST(VMRange, IsValid) {
- VMRange range;
- EXPECT_FALSE(range.IsValid());
-
- range.Reset(0x1, 0x100);
- EXPECT_TRUE(range.IsValid());
-
- range.Reset(0x1, 0x1);
- EXPECT_FALSE(range.IsValid());
-}
-
-TEST(VMRange, Clear) {
- VMRange range(0x100, 0x200);
- EXPECT_NE(VMRange(), range);
- range.Clear();
- EXPECT_EQ(VMRange(), range);
-}
-
-TEST(VMRange, Comparison) {
- VMRange range1(0x100, 0x200);
- VMRange range2(0x100, 0x200);
- EXPECT_EQ(range1, range2);
-
- EXPECT_NE(VMRange(0x100, 0x1ff), range1);
- EXPECT_NE(VMRange(0x100, 0x201), range1);
- EXPECT_NE(VMRange(0x0ff, 0x200), range1);
- EXPECT_NE(VMRange(0x101, 0x200), range1);
-
- range2.Clear();
- EXPECT_NE(range1, range2);
-}
-
-TEST(VMRange, Reset) {
- VMRange range(0x100, 0x200);
- EXPECT_FALSE(VMRange(0x200, 0x200) == range);
- range.Reset(0x200, 0x200);
- EXPECT_TRUE(VMRange(0x200, 0x200) == range);
-}
-
-TEST(VMRange, SetEndAddress) {
- VMRange range(0x100, 0x200);
-
- range.SetEndAddress(0xFF);
- EXPECT_EQ(0U, range.GetByteSize());
- EXPECT_FALSE(range.IsValid());
-
- range.SetEndAddress(0x101);
- EXPECT_EQ(1U, range.GetByteSize());
- EXPECT_TRUE(range.IsValid());
-}
-
-TEST(VMRange, ContainsAddr) {
- VMRange range(0x100, 0x200);
-
- EXPECT_FALSE(range.Contains(0x00));
- EXPECT_FALSE(range.Contains(0xFF));
- EXPECT_TRUE(range.Contains(0x100));
- EXPECT_TRUE(range.Contains(0x101));
- EXPECT_TRUE(range.Contains(0x1FF));
- EXPECT_FALSE(range.Contains(0x200));
- EXPECT_FALSE(range.Contains(0x201));
- EXPECT_FALSE(range.Contains(0xFFF));
- EXPECT_FALSE(range.Contains(std::numeric_limits<lldb::addr_t>::max()));
-}
-
-TEST(VMRange, ContainsRange) {
- VMRange range(0x100, 0x200);
-
- EXPECT_FALSE(range.Contains(VMRange(0x0, 0x0)));
-
- EXPECT_FALSE(range.Contains(VMRange(0x0, 0x100)));
- EXPECT_FALSE(range.Contains(VMRange(0x0, 0x101)));
- EXPECT_TRUE(range.Contains(VMRange(0x100, 0x105)));
- EXPECT_TRUE(range.Contains(VMRange(0x101, 0x105)));
- EXPECT_TRUE(range.Contains(VMRange(0x100, 0x1FF)));
- EXPECT_TRUE(range.Contains(VMRange(0x105, 0x200)));
- EXPECT_FALSE(range.Contains(VMRange(0x105, 0x201)));
- EXPECT_FALSE(range.Contains(VMRange(0x200, 0x201)));
- EXPECT_TRUE(range.Contains(VMRange(0x100, 0x200)));
- EXPECT_FALSE(
- range.Contains(VMRange(0x105, std::numeric_limits<lldb::addr_t>::max())));
-
- // Empty range.
- EXPECT_TRUE(range.Contains(VMRange(0x100, 0x100)));
-
- range.Clear();
- EXPECT_FALSE(range.Contains(VMRange(0x0, 0x0)));
-}
-
-TEST(VMRange, Ordering) {
- VMRange range1(0x44, 0x200);
- VMRange range2(0x100, 0x1FF);
- VMRange range3(0x100, 0x200);
-
- EXPECT_LE(range1, range1);
- EXPECT_GE(range1, range1);
-
- EXPECT_LT(range1, range2);
- EXPECT_LT(range2, range3);
-
- EXPECT_GT(range2, range1);
- EXPECT_GT(range3, range2);
-
- // Ensure that < and > are always false when comparing ranges with themselves.
- EXPECT_FALSE(range1 < range1);
- EXPECT_FALSE(range2 < range2);
- EXPECT_FALSE(range3 < range3);
-
- EXPECT_FALSE(range1 > range1);
- EXPECT_FALSE(range2 > range2);
- EXPECT_FALSE(range3 > range3);
-}
-
-TEST(VMRange, CollectionContains) {
- VMRange::collection collection = {VMRange(0x100, 0x105),
- VMRange(0x108, 0x110)};
-
- EXPECT_FALSE(VMRange::ContainsValue(collection, 0xFF));
- EXPECT_TRUE(VMRange::ContainsValue(collection, 0x100));
- EXPECT_FALSE(VMRange::ContainsValue(collection, 0x105));
- EXPECT_TRUE(VMRange::ContainsValue(collection, 0x109));
-
- EXPECT_TRUE(VMRange::ContainsRange(collection, VMRange(0x100, 0x104)));
- EXPECT_TRUE(VMRange::ContainsRange(collection, VMRange(0x108, 0x100)));
- EXPECT_FALSE(VMRange::ContainsRange(collection, VMRange(0xFF, 0x100)));
-
- // TODO: Implement and test ContainsRange with values that span multiple
- // ranges in the collection.
-}
+++ /dev/null
-//===-- XcodeSDKTest.cpp --------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/XcodeSDK.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-
-#include <tuple>
-
-using namespace lldb_private;
-
-TEST(XcodeSDKTest, ParseTest) {
- EXPECT_EQ(XcodeSDK::GetAnyMacOS().GetType(), XcodeSDK::MacOSX);
- EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetType(), XcodeSDK::MacOSX);
- EXPECT_EQ(XcodeSDK("iPhoneSimulator.sdk").GetType(), XcodeSDK::iPhoneSimulator);
- EXPECT_EQ(XcodeSDK("iPhoneOS.sdk").GetType(), XcodeSDK::iPhoneOS);
- EXPECT_EQ(XcodeSDK("AppleTVSimulator.sdk").GetType(), XcodeSDK::AppleTVSimulator);
- EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS);
- EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator);
- EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS);
- EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux);
- EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple());
- EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9));
- EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15));
- EXPECT_EQ(XcodeSDK("MacOSX.sdk").IsAppleInternalSDK(), false);
- EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").GetType(), XcodeSDK::MacOSX);
- EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").GetVersion(),
- llvm::VersionTuple(10, 15));
- EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").IsAppleInternalSDK(), true);
- EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown);
- EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple());
-}
-
-TEST(XcodeSDKTest, MergeTest) {
- XcodeSDK sdk("MacOSX.sdk");
- sdk.Merge(XcodeSDK("WatchOS.sdk"));
- // This doesn't make any particular sense and shouldn't happen in practice, we
- // just want to guarantee a well-defined behavior when choosing one
- // SDK to fit all CUs in an lldb::Module.
- // -> The higher number wins.
- EXPECT_EQ(sdk.GetType(), XcodeSDK::watchOS);
- sdk.Merge(XcodeSDK("WatchOS1.1.sdk"));
- EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1));
- sdk.Merge(XcodeSDK("WatchOS2.0.sdk"));
- EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0));
- sdk.Merge(XcodeSDK("WatchOS1.1.Internal.sdk"));
- EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0));
- EXPECT_EQ(sdk.IsAppleInternalSDK(), true);
- XcodeSDK empty;
- empty.Merge(XcodeSDK("MacOSX10.14.Internal.sdk"));
- EXPECT_EQ(empty.GetString(), llvm::StringRef("MacOSX10.14.Internal.sdk"));
-}
-
-#ifndef _WIN32
-TEST(XcodeSDKTest, SDKSupportsModules) {
- std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/";
- EXPECT_TRUE(XcodeSDK::SDKSupportsModules(
- XcodeSDK::Type::iPhoneSimulator,
- FileSpec(
- base +
- "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk")));
- EXPECT_TRUE(XcodeSDK::SDKSupportsModules(
- XcodeSDK::Type::iPhoneSimulator,
- FileSpec(base + "iPhoneSimulator.platform/Developer/SDKs/"
- "iPhoneSimulator12.0.Internal.sdk")));
- EXPECT_FALSE(XcodeSDK::SDKSupportsModules(
- XcodeSDK::Type::iPhoneSimulator,
- FileSpec(
- base +
- "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk")));
- EXPECT_TRUE(XcodeSDK::SDKSupportsModules(
- XcodeSDK::Type::MacOSX,
- FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk")));
- EXPECT_FALSE(XcodeSDK::SDKSupportsModules(
- XcodeSDK::Type::MacOSX,
- FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk")));
-}
-#endif
-
-TEST(XcodeSDKTest, SDKSupportsSwift) {
- EXPECT_TRUE(XcodeSDK("iPhoneSimulator12.0.sdk").SupportsSwift());
- EXPECT_TRUE(XcodeSDK("iPhoneSimulator12.0.Internal.sdk").SupportsSwift());
- EXPECT_FALSE(XcodeSDK("iPhoneSimulator7.2.sdk").SupportsSwift());
- EXPECT_TRUE(XcodeSDK("MacOSX10.10.sdk").SupportsSwift());
- EXPECT_FALSE(XcodeSDK("MacOSX10.9.sdk").SupportsSwift());
- EXPECT_TRUE(XcodeSDK("Linux.sdk").SupportsSwift());
- EXPECT_TRUE(XcodeSDK("MacOSX.sdk").SupportsSwift());
- EXPECT_FALSE(XcodeSDK("EverythingElse.sdk").SupportsSwift());
-}
-
-TEST(XcodeSDKTest, GetCanonicalNameAndConstruct) {
- XcodeSDK::Info info;
- info.type = XcodeSDK::Type::MacOSX;
- EXPECT_EQ("macosx", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::iPhoneSimulator;
- EXPECT_EQ("iphonesimulator", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::iPhoneOS;
- EXPECT_EQ("iphoneos", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::AppleTVSimulator;
- EXPECT_EQ("appletvsimulator", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::AppleTVOS;
- EXPECT_EQ("appletvos", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::WatchSimulator;
- EXPECT_EQ("watchsimulator", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::watchOS;
- EXPECT_EQ("watchos", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::Linux;
- EXPECT_EQ("linux", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::unknown;
- EXPECT_EQ("", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.internal = true;
- info.type = XcodeSDK::Type::MacOSX;
- EXPECT_EQ("macosx.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::iPhoneSimulator;
- EXPECT_EQ("iphonesimulator.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::iPhoneOS;
- EXPECT_EQ("iphoneos.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::AppleTVSimulator;
- EXPECT_EQ("appletvsimulator.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::AppleTVOS;
- EXPECT_EQ("appletvos.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::WatchSimulator;
- EXPECT_EQ("watchsimulator.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::watchOS;
- EXPECT_EQ("watchos.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::MacOSX;
- info.version = llvm::VersionTuple(10, 9);
- EXPECT_EQ("macosx10.9.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-
- info.type = XcodeSDK::Type::iPhoneOS;
- info.version = llvm::VersionTuple(7, 0);
- EXPECT_EQ("iphoneos7.0.internal", XcodeSDK::GetCanonicalName(info));
- EXPECT_EQ(XcodeSDK(info).Parse(), info);
-}
-
-TEST(XcodeSDKTest, GetSDKTypeForTriple) {
- EXPECT_EQ(
- XcodeSDK::GetSDKTypeForTriple(llvm::Triple("x86_64-apple-macosx10.14")),
- XcodeSDK::Type::MacOSX);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("x86_64-apple-darwin")),
- XcodeSDK::Type::MacOSX);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(
- llvm::Triple("x86_64-apple-ios13.4-simulator")),
- XcodeSDK::Type::iPhoneSimulator);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("arm64-apple-ios13.4")),
- XcodeSDK::Type::iPhoneOS);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(
- llvm::Triple("x86_64-apple-ios13.4-macabi")),
- XcodeSDK::Type::MacOSX);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(
- llvm::Triple("x86_64-apple-tvos-simulator")),
- XcodeSDK::Type::AppleTVSimulator);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("arm64-apple-tvos")),
- XcodeSDK::Type::AppleTVOS);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(
- llvm::Triple("x86_64-apple-watchos-simulator")),
- XcodeSDK::Type::WatchSimulator);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("arm64-apple-watchos")),
- XcodeSDK::Type::watchOS);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("x86_64-unknown-linux")),
- XcodeSDK::Type::Linux);
- EXPECT_EQ(XcodeSDK::GetSDKTypeForTriple(llvm::Triple("i386-unknown-netbsd")),
- XcodeSDK::Type::unknown);
-}
-
-TEST(XcodeSDKTest, FindXcodeContentsDirectoryInPath) {
- std::string standard =
- "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX.sdk";
- EXPECT_EQ("/Applications/Xcode.app/Contents",
- XcodeSDK::FindXcodeContentsDirectoryInPath(standard));
-
- std::string standard_version =
- "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX10.15.sdk";
- EXPECT_EQ("/Applications/Xcode.app/Contents",
- XcodeSDK::FindXcodeContentsDirectoryInPath(standard_version));
-
- std::string beta = "/Applications/Xcode-beta.app/Contents/Developer/"
- "Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX10.15.sdk";
- EXPECT_EQ("/Applications/Xcode-beta.app/Contents",
- XcodeSDK::FindXcodeContentsDirectoryInPath(beta));
-
- std::string no_app =
- "/Applications/Xcode/Contents/Developer/Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX10.15.sdk";
- EXPECT_EQ("", XcodeSDK::FindXcodeContentsDirectoryInPath(no_app));
-
- std::string no_contents =
- "/Applications/Xcode.app/Developer/Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX10.15.sdk";
- EXPECT_EQ("", XcodeSDK::FindXcodeContentsDirectoryInPath(no_contents));
-
- std::string no_capitalization =
- "/Applications/Xcode.app/contents/Developer/Platforms/MacOSX.platform/"
- "Developer/SDKs/MacOSX10.15.sdk";
- EXPECT_EQ("", XcodeSDK::FindXcodeContentsDirectoryInPath(no_capitalization));
-}
+++ /dev/null
-# Note: debugserver is a Darwin-only implementation of a remote debugging
-# server. It is not intended to be used on other platforms. The tests are here
-# because using the LLDB Host API is convenient and allows testing of both parts
-# of the debugserver communication path. If you are looking for a non-darwin
-# remote debugging server, please use lldb-server.
-
-add_lldb_unittest(debugserverTests
- JSONTest.cpp
- RNBSocketTest.cpp
- debugserver_LogCallback.cpp
-
- LINK_LIBS
- lldbDebugserverCommon
- lldbHost
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
-
-target_include_directories(debugserverTests PRIVATE
- ${LLDB_SOURCE_DIR}/tools/debugserver/source
- ${LLDB_SOURCE_DIR}/tools/debugserver/source/MacOSX)
-
-if(APPLE_EMBEDDED)
- set_property(TARGET debugserverTests APPEND PROPERTY COMPILE_DEFINITIONS
- WITH_LOCKDOWN
- WITH_FBS
- WITH_BKS
- )
-
- add_lldb_unittest(debugserverNonUITests
- JSONTest.cpp
- RNBSocketTest.cpp
- debugserver_LogCallback.cpp
-
- LINK_LIBS
- lldbDebugserverCommon_NonUI
- lldbHost
- LINK_COMPONENTS
- Support
- )
-endif()
+++ /dev/null
-//===-- JSONTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "JSON.h"
-
-template <typename T>
-void TestJSON(JSONValue *json_val, const std::function<void(T &)> &test_func) {
- ASSERT_THAT(json_val, testing::NotNull());
- ASSERT_TRUE(T::classof(json_val));
- test_func(static_cast<T &>(*json_val));
-}
-
-JSONValue::SP ParseJSON(const char *json_string) {
- return JSONParser(json_string).ParseJSONValue();
-}
-
-template <typename T>
-void ParseAndTestJSON(
- const char *json_string,
- const std::function<void(T &)> &test_func = [](T &) {}) {
- auto json_val = ParseJSON(json_string);
- TestJSON<T>(json_val.get(), test_func);
-}
-
-TEST(JSON, Parse) {
- ParseAndTestJSON<JSONString>("\"foo\"", [](JSONString &string_val) {
- EXPECT_EQ(string_val.GetData(), "foo");
- });
- EXPECT_THAT(ParseJSON("\"foo"), testing::IsNull());
- ParseAndTestJSON<JSONNumber>("3", [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), 3);
- EXPECT_EQ(number_val.GetAsUnsigned(), 3u);
- EXPECT_EQ(number_val.GetAsDouble(), 3.0);
- });
- ParseAndTestJSON<JSONNumber>("-5", [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), -5);
- EXPECT_EQ(number_val.GetAsDouble(), -5.0);
- });
- ParseAndTestJSON<JSONNumber>("-6.4", [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), -6);
- EXPECT_EQ(number_val.GetAsDouble(), -6.4);
- });
- EXPECT_THAT(ParseJSON("-1.2.3"), testing::IsNull());
- ParseAndTestJSON<JSONTrue>("true");
- ParseAndTestJSON<JSONFalse>("false");
- ParseAndTestJSON<JSONNull>("null");
- ParseAndTestJSON<JSONObject>(
- "{ \"key1\": 4, \"key2\": \"foobar\" }", [](JSONObject &obj_val) {
- TestJSON<JSONNumber>(obj_val.GetObject("key1").get(),
- [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), 4);
- EXPECT_EQ(number_val.GetAsUnsigned(), 4u);
- EXPECT_EQ(number_val.GetAsDouble(), 4.0);
- });
- TestJSON<JSONString>(obj_val.GetObject("key2").get(),
- [](JSONString &string_val) {
- EXPECT_EQ(string_val.GetData(), "foobar");
- });
- });
- ParseAndTestJSON<JSONArray>("[1, \"bar\", 3.14]", [](JSONArray &array_val) {
- EXPECT_EQ(array_val.GetNumElements(), 3u);
- TestJSON<JSONNumber>(array_val.GetObject(0).get(),
- [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), 1);
- EXPECT_EQ(number_val.GetAsUnsigned(), 1u);
- EXPECT_EQ(number_val.GetAsDouble(), 1.0);
- });
- TestJSON<JSONString>(
- array_val.GetObject(1).get(),
- [](JSONString &string_val) { EXPECT_EQ(string_val.GetData(), "bar"); });
- TestJSON<JSONNumber>(array_val.GetObject(2).get(),
- [](JSONNumber &number_val) {
- EXPECT_EQ(number_val.GetAsSigned(), 3);
- EXPECT_EQ(number_val.GetAsUnsigned(), 3u);
- EXPECT_EQ(number_val.GetAsDouble(), 3.14);
- });
- });
- ParseAndTestJSON<JSONArray>("[]", [](JSONArray &array_val) {
- EXPECT_EQ(array_val.GetNumElements(), 0u);
- });
-}
+++ /dev/null
-//===-- RNBSocketTest.cpp -------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include <arpa/inet.h>
-#include <sys/sysctl.h>
-#include <unistd.h>
-
-#include "RNBDefs.h"
-#include "RNBSocket.h"
-#include "lldb/Host/Socket.h"
-#include "lldb/Host/StringConvert.h"
-#include "lldb/Host/common/TCPSocket.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace lldb_private;
-
-std::string hello = "Hello, world!";
-std::string goodbye = "Goodbye!";
-
-static void ServerCallbackv4(const void *baton, in_port_t port) {
- auto child_pid = fork();
- if (child_pid == 0) {
- char addr_buffer[256];
- sprintf(addr_buffer, "%s:%d", (const char *)baton, port);
- llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
- Socket::TcpConnect(addr_buffer, false);
- ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
- Socket *client_socket = socket_or_err->get();
-
- char buffer[32];
- size_t read_size = 32;
- Status err = client_socket->Read((void *)&buffer[0], read_size);
- if (err.Fail())
- abort();
- std::string Recv(&buffer[0], read_size);
- if (Recv != hello)
- abort();
- size_t write_size = goodbye.length();
- err = client_socket->Write(goodbye.c_str(), write_size);
- if (err.Fail())
- abort();
- if (write_size != goodbye.length())
- abort();
- delete client_socket;
- exit(0);
- }
-}
-
-void TestSocketListen(const char *addr) {
- // Skip IPv6 tests if there isn't a valid interafce
- auto addresses = lldb_private::SocketAddress::GetAddressInfo(
- addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
- if (addresses.size() == 0)
- return;
-
- char addr_wrap[256];
- if (addresses.front().GetFamily() == AF_INET6)
- sprintf(addr_wrap, "[%s]", addr);
- else
- sprintf(addr_wrap, "%s", addr);
-
- RNBSocket server_socket;
- auto result =
- server_socket.Listen(addr, 0, ServerCallbackv4, (const void *)addr_wrap);
- ASSERT_TRUE(result == rnb_success);
- result = server_socket.Write(hello.c_str(), hello.length());
- ASSERT_TRUE(result == rnb_success);
- std::string bye;
- result = server_socket.Read(bye);
- ASSERT_TRUE(result == rnb_success);
- ASSERT_EQ(bye, goodbye);
-
- int exit_status;
- wait(&exit_status);
- ASSERT_EQ(exit_status, 0);
-}
-
-TEST(RNBSocket, LoopBackListenIPv4) { TestSocketListen("127.0.0.1"); }
-
-TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen("::1"); }
-
-TEST(RNBSocket, AnyListen) { TestSocketListen("*"); }
-
-void TestSocketConnect(const char *addr) {
- // Skip IPv6 tests if there isn't a valid interafce
- auto addresses = lldb_private::SocketAddress::GetAddressInfo(
- addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
- if (addresses.size() == 0)
- return;
-
- char addr_wrap[256];
- if (addresses.front().GetFamily() == AF_INET6)
- sprintf(addr_wrap, "[%s]:0", addr);
- else
- sprintf(addr_wrap, "%s:0", addr);
-
- Socket *server_socket;
- Predicate<uint16_t> port_predicate;
- port_predicate.SetValue(0, eBroadcastNever);
- llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
- Socket::TcpListen(addr_wrap, false, &port_predicate);
- ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
- server_socket = socket_or_err->get();
-
- auto port = ((TCPSocket *)server_socket)->GetLocalPortNumber();
- auto child_pid = fork();
- if (child_pid != 0) {
- RNBSocket client_socket;
- auto result = client_socket.Connect(addr, port);
- ASSERT_TRUE(result == rnb_success);
- result = client_socket.Write(hello.c_str(), hello.length());
- ASSERT_TRUE(result == rnb_success);
- std::string bye;
- result = client_socket.Read(bye);
- ASSERT_TRUE(result == rnb_success);
- ASSERT_EQ(bye, goodbye);
- } else {
- Socket *connected_socket;
- Status err = server_socket->Accept(connected_socket);
- if (err.Fail()) {
- llvm::errs() << err.AsCString();
- abort();
- }
- char buffer[32];
- size_t read_size = 32;
- err = connected_socket->Read((void *)&buffer[0], read_size);
- if (err.Fail()) {
- llvm::errs() << err.AsCString();
- abort();
- }
- std::string Recv(&buffer[0], read_size);
- if (Recv != hello) {
- llvm::errs() << err.AsCString();
- abort();
- }
- size_t write_size = goodbye.length();
- err = connected_socket->Write(goodbye.c_str(), write_size);
- if (err.Fail()) {
- llvm::errs() << err.AsCString();
- abort();
- }
- if (write_size != goodbye.length()) {
- llvm::errs() << err.AsCString();
- abort();
- }
- exit(0);
- }
- int exit_status;
- wait(&exit_status);
- ASSERT_EQ(exit_status, 0);
-}
-
-TEST(RNBSocket, LoopBackConnectIPv4) { TestSocketConnect("127.0.0.1"); }
-
-TEST(RNBSocket, LoopBackConnectIPv6) { TestSocketConnect("::1"); }
+++ /dev/null
-//===-- debugserver_LogCallback.cpp ---------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// this function is defined in debugserver.cpp, but is needed to link the
-// debugserver Common library. It is for logging only, so it is left
-// unimplemented here.
-
-#include <stdint.h>
-#include <stdarg.h>
-
-void FileLogCallback(void *baton, uint32_t flags, const char *format,
- va_list args) {}
+++ /dev/null
-#ifndef LLDB_UNITTESTS_GTEST_COMMON_H
-
-#define LLDB_UNITTESTS_GTEST_COMMON_H
-
-//===-- gtest_common.h ------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#if defined(LLDB_GTEST_COMMON_H)
-#error "gtest_common.h should not be included manually."
-#else
-#define LLDB_GTEST_COMMON_H
-#endif
-
-// This header file is force included by all of LLDB's unittest compilation
-// units. Be very leary about putting anything in this file.
-
-#endif
+++ /dev/null
-if(LLDB_TOOL_LLDB_SERVER_BUILD)
- add_subdirectory(lldb-server)
-endif()
+++ /dev/null
-set(ALL_LLDB_TEST_EXECUTABLES)
-
-function(add_lldb_test_executable test_name)
- set(EXCLUDE_FROM_ALL ON)
- add_llvm_executable(${test_name} NO_INSTALL_RPATH ${ARGN})
- set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
- set_output_directory(${test_name} BINARY_DIR ${outdir} LIBRARY_DIR ${outdir})
- list(APPEND ALL_LLDB_TEST_EXECUTABLES ${test_name})
- set(ALL_LLDB_TEST_EXECUTABLES ${ALL_LLDB_TEST_EXECUTABLES} PARENT_SCOPE)
- set_target_properties(${test_name} PROPERTIES FOLDER "lldb tests")
-endfunction()
-
-add_lldb_test_executable(thread_inferior inferior/thread_inferior.cpp)
-add_lldb_test_executable(environment_check inferior/environment_check.cpp)
-
-if(LLDB_CAN_USE_DEBUGSERVER AND (LLDB_TOOL_DEBUGSERVER_BUILD OR LLDB_USE_SYSTEM_DEBUGSERVER))
- if(LLDB_USE_SYSTEM_DEBUGSERVER)
- lldb_find_system_debugserver(debugserver_path)
- else()
- set(debugserver_path $<TARGET_FILE:debugserver>)
- endif()
- add_definitions(-DLLDB_SERVER="${debugserver_path}" -DLLDB_SERVER_IS_DEBUGSERVER=1)
-else()
- add_definitions(-DLLDB_SERVER="$<TARGET_FILE:lldb-server>" -DLLDB_SERVER_IS_DEBUGSERVER=0)
-endif()
-
-add_definitions(
- -DLLDB_TEST_INFERIOR_PATH="${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
- -DLLDB_TEST_INFERIOR_SUFFIX="${CMAKE_EXECUTABLE_SUFFIX}"
- )
-add_subdirectory(tests)
+++ /dev/null
-//===-- thread_inferior.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include <string>
-#include <cstdlib>
-
-int main() {
- const char *value = std::getenv("LLDB_TEST_MAGIC_VARIABLE");
- if (!value)
- return 1;
- if (std::string(value) != "LLDB_TEST_MAGIC_VALUE")
- return 2;
- return 0;
-}
+++ /dev/null
-//===-- thread_inferior.cpp -----------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include <atomic>
-#include <chrono>
-#include <string>
-#include <thread>
-#include <vector>
-
-int main(int argc, char* argv[]) {
- int thread_count = 2;
- if (argc > 1) {
- thread_count = std::stoi(argv[1], nullptr, 10);
- }
-
- std::atomic<bool> delay(true);
- std::vector<std::thread> threads;
- for (int i = 0; i < thread_count; i++) {
- threads.push_back(std::thread([&delay] {
- while (delay.load())
- std::this_thread::sleep_for(std::chrono::seconds(1));
- }));
- }
-
- // Cause a break.
- volatile char *p = nullptr;
- *p = 'a';
-
- delay.store(false);
- for (std::thread& t : threads) {
- t.join();
- }
-
- return 0;
-}
+++ /dev/null
-add_lldb_unittest(LLDBServerTests
- LLGSTest.cpp
- MessageObjects.cpp
- TestBase.cpp
- TestClient.cpp
- ThreadIdsInJstopinfoTest.cpp
-
- LINK_LIBS
- lldbHost
- lldbCore
- lldbInterpreter
- lldbTarget
- lldbPluginPlatformLinux
- lldbPluginProcessGDBRemote
-
- LLVMTestingSupport
- LINK_COMPONENTS
- Support
- )
-
-add_dependencies(LLDBServerTests lldb-server ${ALL_LLDB_TEST_EXECUTABLES})
+++ /dev/null
-//===-- LLGSTest.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestBase.h"
-#include "lldb/Host/Host.h"
-#include "llvm/Testing/Support/Error.h"
-
-using namespace llgs_tests;
-using namespace lldb_private;
-using namespace llvm;
-
-#ifdef SendMessage
-#undef SendMessage
-#endif
-
-// Disable this test on Windows as it appears to have a race condition
-// that causes lldb-server not to exit after the inferior hangs up.
-#if !defined(_WIN32)
-TEST_F(TestBase, LaunchModePreservesEnvironment) {
- putenv(const_cast<char *>("LLDB_TEST_MAGIC_VARIABLE=LLDB_TEST_MAGIC_VALUE"));
-
- auto ClientOr = TestClient::launch(getLogFileName(),
- {getInferiorPath("environment_check")});
- ASSERT_THAT_EXPECTED(ClientOr, Succeeded());
- auto &Client = **ClientOr;
-
- ASSERT_THAT_ERROR(Client.ContinueAll(), Succeeded());
- ASSERT_THAT_EXPECTED(
- Client.GetLatestStopReplyAs<StopReplyExit>(),
- HasValue(testing::Property(&StopReply::getKind,
- WaitStatus{WaitStatus::Exit, 0})));
-}
-#endif
-
-TEST_F(TestBase, DS_TEST(DebugserverEnv)) {
- // Test that --env takes precedence over inherited environment variables.
- putenv(const_cast<char *>("LLDB_TEST_MAGIC_VARIABLE=foobar"));
-
- auto ClientOr = TestClient::launchCustom(getLogFileName(),
- { "--env", "LLDB_TEST_MAGIC_VARIABLE=LLDB_TEST_MAGIC_VALUE" },
- {getInferiorPath("environment_check")});
- ASSERT_THAT_EXPECTED(ClientOr, Succeeded());
- auto &Client = **ClientOr;
-
- ASSERT_THAT_ERROR(Client.ContinueAll(), Succeeded());
- ASSERT_THAT_EXPECTED(
- Client.GetLatestStopReplyAs<StopReplyExit>(),
- HasValue(testing::Property(&StopReply::getKind,
- WaitStatus{WaitStatus::Exit, 0})));
-}
-
-TEST_F(TestBase, LLGS_TEST(vAttachRichError)) {
- auto ClientOr = TestClient::launch(getLogFileName(),
- {getInferiorPath("environment_check")});
- ASSERT_THAT_EXPECTED(ClientOr, Succeeded());
- auto &Client = **ClientOr;
-
- // Until we enable error strings we should just get the error code.
- ASSERT_THAT_ERROR(Client.SendMessage("vAttach;1"),
- Failed<ErrorInfoBase>(testing::Property(
- &ErrorInfoBase::message, "Error 255")));
-
- ASSERT_THAT_ERROR(Client.SendMessage("QEnableErrorStrings"), Succeeded());
-
- // Now, we expect the full error message.
- ASSERT_THAT_ERROR(
- Client.SendMessage("vAttach;1"),
- Failed<ErrorInfoBase>(testing::Property(
- &ErrorInfoBase::message,
- testing::StartsWith(
- "cannot attach to process 1 when another process with pid"))));
-}
+++ /dev/null
-//===-- MessageObjects.cpp ------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "MessageObjects.h"
-#include "lldb/Utility/Args.h"
-#include "lldb/Utility/StringExtractor.h"
-#include "llvm/ADT/StringExtras.h"
-#include "gtest/gtest.h"
-
-using namespace lldb_private;
-using namespace lldb;
-using namespace llvm;
-namespace llgs_tests {
-
-Expected<ProcessInfo> ProcessInfo::create(StringRef response) {
- ProcessInfo process_info;
- auto elements_or_error = SplitUniquePairList("ProcessInfo", response);
- if (!elements_or_error)
- return elements_or_error.takeError();
-
- auto &elements = *elements_or_error;
- if (elements["pid"].getAsInteger(16, process_info.m_pid))
- return make_parsing_error("ProcessInfo: pid");
- if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid))
- return make_parsing_error("ProcessInfo: parent-pid");
- if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid))
- return make_parsing_error("ProcessInfo: real-uid");
- if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid))
- return make_parsing_error("ProcessInfo: real-uid");
- if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid))
- return make_parsing_error("ProcessInfo: effective-uid");
- if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid))
- return make_parsing_error("ProcessInfo: effective-gid");
- if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize))
- return make_parsing_error("ProcessInfo: ptrsize");
-
- process_info.m_triple = fromHex(elements["triple"]);
- StringRef endian_str = elements["endian"];
- if (endian_str == "little")
- process_info.m_endian = support::little;
- else if (endian_str == "big")
- process_info.m_endian = support::big;
- else
- return make_parsing_error("ProcessInfo: endian");
-
- return process_info;
-}
-
-lldb::pid_t ProcessInfo::GetPid() const { return m_pid; }
-
-support::endianness ProcessInfo::GetEndian() const { return m_endian; }
-
-//====== ThreadInfo ============================================================
-ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers,
- unsigned int)
- : m_name(name.str()), m_reason(reason.str()),
- m_registers(std::move(registers)) {}
-
-const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const {
- auto Iter = m_registers.find(Id);
- return Iter == m_registers.end() ? nullptr : &Iter->getSecond();
-}
-
-//====== JThreadsInfo ==========================================================
-
-Expected<RegisterMap>
-JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict,
- ArrayRef<RegisterInfo> RegInfos) {
- RegisterMap Result;
-
- auto KeysObj = Dict.GetKeys();
- auto Keys = KeysObj->GetAsArray();
- for (size_t i = 0; i < Keys->GetSize(); i++) {
- StringRef KeyStr, ValueStr;
- Keys->GetItemAtIndexAsString(i, KeyStr);
- Dict.GetValueForKeyAsString(KeyStr, ValueStr);
- unsigned int Register;
- if (!llvm::to_integer(KeyStr, Register, 10))
- return make_parsing_error("JThreadsInfo: register key[{0}]", i);
-
- auto RegValOr =
- parseRegisterValue(RegInfos[Register], ValueStr, support::big);
- if (!RegValOr)
- return RegValOr.takeError();
- Result[Register] = std::move(*RegValOr);
- }
- return std::move(Result);
-}
-
-Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response,
- ArrayRef<RegisterInfo> RegInfos) {
- JThreadsInfo jthreads_info;
-
- StructuredData::ObjectSP json =
- StructuredData::ParseJSON(std::string(Response));
- StructuredData::Array *array = json->GetAsArray();
- if (!array)
- return make_parsing_error("JThreadsInfo: JSON array");
-
- for (size_t i = 0; i < array->GetSize(); i++) {
- StructuredData::Dictionary *thread_info;
- array->GetItemAtIndexAsDictionary(i, thread_info);
- if (!thread_info)
- return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);
-
- StringRef name, reason;
- thread_info->GetValueForKeyAsString("name", name);
- thread_info->GetValueForKeyAsString("reason", reason);
- uint64_t signal;
- thread_info->GetValueForKeyAsInteger("signal", signal);
- uint64_t tid;
- thread_info->GetValueForKeyAsInteger("tid", tid);
-
- StructuredData::Dictionary *register_dict;
- thread_info->GetValueForKeyAsDictionary("registers", register_dict);
- if (!register_dict)
- return make_parsing_error("JThreadsInfo: registers JSON obj");
-
- auto RegsOr = parseRegisters(*register_dict, RegInfos);
- if (!RegsOr)
- return RegsOr.takeError();
- jthreads_info.m_thread_infos[tid] =
- ThreadInfo(name, reason, std::move(*RegsOr), signal);
- }
-
- return jthreads_info;
-}
-
-const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {
- return m_thread_infos;
-}
-
-Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) {
- auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response);
- if (!ElementsOr)
- return ElementsOr.takeError();
- auto &Elements = *ElementsOr;
-
- RegisterInfo Info = {
- nullptr, // Name
- nullptr, // Alt name
- 0, // byte size
- 0, // offset
- eEncodingUint, // encoding
- eFormatHex, // format
- {
- LLDB_INVALID_REGNUM, // eh_frame reg num
- LLDB_INVALID_REGNUM, // DWARF reg num
- LLDB_INVALID_REGNUM, // generic reg num
- LLDB_INVALID_REGNUM, // process plugin reg num
- LLDB_INVALID_REGNUM // native register number
- },
- nullptr,
- nullptr,
- nullptr, // Dwarf expression opcode bytes pointer
- 0 // Dwarf expression opcode bytes length
- };
- Info.name = ConstString(Elements["name"]).GetCString();
- if (!Info.name)
- return make_parsing_error("qRegisterInfo: name");
-
- Info.alt_name = ConstString(Elements["alt-name"]).GetCString();
-
- if (!to_integer(Elements["bitsize"], Info.byte_size, 10))
- return make_parsing_error("qRegisterInfo: bit-size");
- Info.byte_size /= CHAR_BIT;
-
- if (!to_integer(Elements["offset"], Info.byte_offset, 10))
- Info.byte_offset = LLDB_INVALID_INDEX32;
-
- Info.encoding = Args::StringToEncoding(Elements["encoding"]);
- if (Info.encoding == eEncodingInvalid)
- return make_parsing_error("qRegisterInfo: encoding");
-
- Info.format = StringSwitch<Format>(Elements["format"])
- .Case("binary", eFormatBinary)
- .Case("decimal", eFormatDecimal)
- .Case("hex", eFormatHex)
- .Case("float", eFormatFloat)
- .Case("vector-sint8", eFormatVectorOfSInt8)
- .Case("vector-uint8", eFormatVectorOfUInt8)
- .Case("vector-sint16", eFormatVectorOfSInt16)
- .Case("vector-uint16", eFormatVectorOfUInt16)
- .Case("vector-sint32", eFormatVectorOfSInt32)
- .Case("vector-uint32", eFormatVectorOfUInt32)
- .Case("vector-float32", eFormatVectorOfFloat32)
- .Case("vector-uint64", eFormatVectorOfUInt64)
- .Case("vector-uint128", eFormatVectorOfUInt128)
- .Default(eFormatInvalid);
- if (Info.format == eFormatInvalid)
- return make_parsing_error("qRegisterInfo: format");
-
- Info.kinds[eRegisterKindGeneric] =
- Args::StringToGenericRegister(Elements["generic"]);
-
- return std::move(Info);
-}
-
-Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info,
- StringRef HexValue,
- llvm::support::endianness Endian,
- bool ZeroPad) {
- SmallString<128> Storage;
- if (ZeroPad && HexValue.size() < Info.byte_size * 2) {
- Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0');
- Storage += HexValue;
- HexValue = Storage;
- }
-
- SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2);
- StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc');
- RegisterValue Value;
- Status ST;
- Value.SetFromMemoryData(
- &Info, Bytes.data(), Bytes.size(),
- Endian == support::little ? eByteOrderLittle : eByteOrderBig, ST);
- if (ST.Fail())
- return ST.ToError();
- return Value;
-}
-
-//====== StopReply =============================================================
-Expected<std::unique_ptr<StopReply>>
-StopReply::create(StringRef Response, llvm::support::endianness Endian,
- ArrayRef<RegisterInfo> RegInfos) {
- if (Response.size() < 3)
- return make_parsing_error("StopReply: Invalid packet");
- if (Response.consume_front("T"))
- return StopReplyStop::create(Response, Endian, RegInfos);
- if (Response.consume_front("W"))
- return StopReplyExit::create(Response);
- return make_parsing_error("StopReply: Invalid packet");
-}
-
-Expected<RegisterMap> StopReplyStop::parseRegisters(
- const StringMap<SmallVector<StringRef, 2>> &Elements,
- support::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) {
-
- RegisterMap Result;
- for (const auto &E : Elements) {
- StringRef Key = E.getKey();
- const auto &Val = E.getValue();
- if (Key.size() != 2)
- continue;
-
- unsigned int Reg;
- if (!to_integer(Key, Reg, 16))
- continue;
-
- if (Val.size() != 1)
- return make_parsing_error(
- "StopReplyStop: multiple entries for register field [{0:x}]", Reg);
-
- auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian);
- if (!RegValOr)
- return RegValOr.takeError();
- Result[Reg] = std::move(*RegValOr);
- }
- return std::move(Result);
-}
-
-Expected<std::unique_ptr<StopReplyStop>>
-StopReplyStop::create(StringRef Response, support::endianness Endian,
- ArrayRef<RegisterInfo> RegInfos) {
- unsigned int Signal;
- StringRef SignalStr = Response.take_front(2);
- Response = Response.drop_front(2);
- if (!to_integer(SignalStr, Signal, 16))
- return make_parsing_error("StopReply: stop signal");
-
- auto Elements = SplitPairList(Response);
- for (StringRef Field :
- {"name", "reason", "thread", "threads", "thread-pcs"}) {
- // This will insert an empty field if there is none. In the future, we
- // should probably differentiate between these fields not being present and
- // them being empty, but right now no tests depends on this.
- if (Elements.insert({Field, {""}}).first->second.size() != 1)
- return make_parsing_error(
- "StopReply: got multiple responses for the {0} field", Field);
- }
- StringRef Name = Elements["name"][0];
- StringRef Reason = Elements["reason"][0];
-
- lldb::tid_t Thread;
- if (!to_integer(Elements["thread"][0], Thread, 16))
- return make_parsing_error("StopReply: thread");
-
- SmallVector<StringRef, 20> Threads;
- SmallVector<StringRef, 20> Pcs;
- Elements["threads"][0].split(Threads, ',');
- Elements["thread-pcs"][0].split(Pcs, ',');
- if (Threads.size() != Pcs.size())
- return make_parsing_error("StopReply: thread/PC count mismatch");
-
- RegisterMap ThreadPcs;
- const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) {
- return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC;
- });
- assert(PcInfo);
-
- for (auto ThreadPc : zip(Threads, Pcs)) {
- lldb::tid_t Id;
- if (!to_integer(std::get<0>(ThreadPc), Id, 16))
- return make_parsing_error("StopReply: Thread id '{0}'",
- std::get<0>(ThreadPc));
-
- auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian,
- /*ZeroPad*/ true);
- if (!PcOr)
- return PcOr.takeError();
- ThreadPcs[Id] = std::move(*PcOr);
- }
-
- auto RegistersOr = parseRegisters(Elements, Endian, RegInfos);
- if (!RegistersOr)
- return RegistersOr.takeError();
-
- return std::make_unique<StopReplyStop>(Signal, Thread, Name,
- std::move(ThreadPcs),
- std::move(*RegistersOr), Reason);
-}
-
-Expected<std::unique_ptr<StopReplyExit>>
-StopReplyExit::create(StringRef Response) {
- uint8_t Status;
- if (!to_integer(Response, Status, 16))
- return make_parsing_error("StopReply: exit status");
- return std::make_unique<StopReplyExit>(Status);
-}
-
-//====== Globals ===============================================================
-Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
- StringRef str) {
- SmallVector<StringRef, 20> elements;
- str.split(elements, ';');
-
- StringMap<StringRef> pairs;
- for (StringRef s : elements) {
- std::pair<StringRef, StringRef> pair = s.split(':');
- if (pairs.count(pair.first))
- return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);
-
- pairs.insert(pair);
- }
-
- return pairs;
-}
-
-StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
- SmallVector<StringRef, 20> elements;
- str.split(elements, ';');
-
- StringMap<SmallVector<StringRef, 2>> pairs;
- for (StringRef s : elements) {
- std::pair<StringRef, StringRef> pair = s.split(':');
- pairs[pair.first].push_back(pair.second);
- }
-
- return pairs;
-}
-} // namespace llgs_tests
-
-std::ostream &lldb_private::operator<<(std::ostream &OS,
- const RegisterValue &RegVal) {
- ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()),
- RegVal.GetByteSize());
- return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(),
- make_range(Bytes.begin(), Bytes.end()))
- .str();
-}
+++ /dev/null
-//===-- MessageObjects.h ----------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_MESSAGEOBJECTS_H
-#define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_MESSAGEOBJECTS_H
-
-#include "lldb/Host/Host.h"
-#include "lldb/Utility/RegisterValue.h"
-#include "lldb/Utility/StructuredData.h"
-#include "lldb/lldb-types.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <string>
-
-namespace llgs_tests {
-class ThreadInfo;
-typedef llvm::DenseMap<uint64_t, ThreadInfo> ThreadInfoMap;
-typedef llvm::DenseMap<unsigned int, lldb_private::RegisterValue> RegisterMap;
-
-template <typename T> struct Parser { using result_type = T; };
-
-class ProcessInfo : public Parser<ProcessInfo> {
-public:
- static llvm::Expected<ProcessInfo> create(llvm::StringRef response);
- lldb::pid_t GetPid() const;
- llvm::support::endianness GetEndian() const;
-
-private:
- ProcessInfo() = default;
- lldb::pid_t m_pid;
- lldb::pid_t m_parent_pid;
- uint32_t m_real_uid;
- uint32_t m_real_gid;
- uint32_t m_effective_uid;
- uint32_t m_effective_gid;
- std::string m_triple;
- llvm::SmallString<16> m_ostype;
- llvm::support::endianness m_endian;
- unsigned int m_ptrsize;
-};
-
-class ThreadInfo {
-public:
- ThreadInfo() = default;
- ThreadInfo(llvm::StringRef name, llvm::StringRef reason,
- RegisterMap registers, unsigned int signal);
-
- const lldb_private::RegisterValue *ReadRegister(unsigned int Id) const;
-
-private:
- std::string m_name;
- std::string m_reason;
- RegisterMap m_registers;
-};
-
-class JThreadsInfo : public Parser<JThreadsInfo> {
-public:
- static llvm::Expected<JThreadsInfo>
- create(llvm::StringRef Response,
- llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
-
- const ThreadInfoMap &GetThreadInfos() const;
-
-private:
- static llvm::Expected<RegisterMap>
- parseRegisters(const lldb_private::StructuredData::Dictionary &Dict,
- llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
-
- JThreadsInfo() = default;
- ThreadInfoMap m_thread_infos;
-};
-
-struct RegisterInfoParser : public Parser<lldb_private::RegisterInfo> {
- static llvm::Expected<lldb_private::RegisterInfo>
- create(llvm::StringRef Response);
-};
-
-llvm::Expected<lldb_private::RegisterValue>
-parseRegisterValue(const lldb_private::RegisterInfo &Info,
- llvm::StringRef HexValue, llvm::support::endianness Endian,
- bool ZeroPad = false);
-
-class StopReply : public Parser<std::unique_ptr<StopReply>> {
-public:
- StopReply() = default;
- virtual ~StopReply() = default;
-
- static llvm::Expected<std::unique_ptr<StopReply>>
- create(llvm::StringRef Response, llvm::support::endianness Endian,
- llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
-
- // for llvm::cast<>
- virtual lldb_private::WaitStatus getKind() const = 0;
-
- StopReply(const StopReply &) = delete;
- void operator=(const StopReply &) = delete;
-};
-
-class StopReplyStop : public StopReply {
-public:
- StopReplyStop(uint8_t Signal, lldb::tid_t ThreadId, llvm::StringRef Name,
- RegisterMap ThreadPcs, RegisterMap Registers,
- llvm::StringRef Reason)
- : Signal(Signal), ThreadId(ThreadId), Name(Name),
- ThreadPcs(std::move(ThreadPcs)), Registers(std::move(Registers)),
- Reason(Reason) {}
-
- static llvm::Expected<std::unique_ptr<StopReplyStop>>
- create(llvm::StringRef Response, llvm::support::endianness Endian,
- llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
-
- const RegisterMap &getThreadPcs() const { return ThreadPcs; }
- lldb::tid_t getThreadId() const { return ThreadId; }
-
- // for llvm::cast<>
- lldb_private::WaitStatus getKind() const override {
- return lldb_private::WaitStatus{lldb_private::WaitStatus::Stop, Signal};
- }
- static bool classof(const StopReply *R) {
- return R->getKind().type == lldb_private::WaitStatus::Stop;
- }
-
-private:
- static llvm::Expected<RegisterMap> parseRegisters(
- const llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>> &Elements,
- llvm::support::endianness Endian,
- llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
-
- uint8_t Signal;
- lldb::tid_t ThreadId;
- std::string Name;
- RegisterMap ThreadPcs;
- RegisterMap Registers;
- std::string Reason;
-};
-
-class StopReplyExit : public StopReply {
-public:
- explicit StopReplyExit(uint8_t Status) : Status(Status) {}
-
- static llvm::Expected<std::unique_ptr<StopReplyExit>>
- create(llvm::StringRef response);
-
- // for llvm::cast<>
- lldb_private::WaitStatus getKind() const override {
- return lldb_private::WaitStatus{lldb_private::WaitStatus::Exit, Status};
- }
- static bool classof(const StopReply *R) {
- return R->getKind().type == lldb_private::WaitStatus::Exit;
- }
-
-private:
- uint8_t Status;
-};
-
-// Common functions for parsing packet data.
-llvm::Expected<llvm::StringMap<llvm::StringRef>>
-SplitUniquePairList(llvm::StringRef caller, llvm::StringRef s);
-
-llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>>
-SplitPairList(llvm::StringRef s);
-
-template <typename... Args>
-llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) {
- std::string error =
- "Unable to parse " +
- llvm::formatv(format.data(), std::forward<Args>(args)...).str();
- return llvm::make_error<llvm::StringError>(error,
- llvm::inconvertibleErrorCode());
-}
-
-} // namespace llgs_tests
-
-namespace lldb_private {
-std::ostream &operator<<(std::ostream &OS, const RegisterValue &RegVal);
-}
-
-#endif // LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_MESSAGEOBJECTS_H
+++ /dev/null
-//===-- TestBase.cpp ------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestBase.h"
-#include <cstdlib>
-
-using namespace llgs_tests;
-using namespace llvm;
-
-std::string TestBase::getLogFileName() {
- const auto *test_info =
- ::testing::UnitTest::GetInstance()->current_test_info();
- assert(test_info);
-
- const char *Dir = getenv("LOG_FILE_DIRECTORY");
- if (!Dir)
- return "";
-
- if (!llvm::sys::fs::is_directory(Dir)) {
- GTEST_LOG_(WARNING) << "Cannot access log directory: " << Dir;
- return "";
- }
-
- SmallString<64> DirStr(Dir);
- sys::path::append(DirStr, std::string("server-") +
- test_info->test_case_name() + "-" +
- test_info->name() + ".log");
- return std::string(DirStr.str());
-}
-
+++ /dev/null
-//===-- TestBase.h ----------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTBASE_H
-#define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTBASE_H
-
-#include "TestClient.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/Socket.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-
-namespace llgs_tests {
-
-class TestBase: public ::testing::Test {
-public:
- static void SetUpTestCase() {
- lldb_private::FileSystem::Initialize();
- lldb_private::HostInfo::Initialize();
- ASSERT_THAT_ERROR(lldb_private::Socket::Initialize(), llvm::Succeeded());
- }
-
- static void TearDownTestCase() {
- lldb_private::Socket::Terminate();
- lldb_private::HostInfo::Terminate();
- lldb_private::FileSystem::Terminate();
- }
-
- static std::string getInferiorPath(llvm::StringRef Name) {
- llvm::SmallString<64> Path(LLDB_TEST_INFERIOR_PATH);
- llvm::sys::path::append(Path, Name + LLDB_TEST_INFERIOR_SUFFIX);
- return std::string(Path.str());
- }
-
- static std::string getLogFileName();
-};
-
-class StandardStartupTest: public TestBase {
-public:
- void SetUp() override {
- auto ClientOr = TestClient::launch(getLogFileName());
- ASSERT_THAT_EXPECTED(ClientOr, llvm::Succeeded());
- Client = std::move(*ClientOr);
- }
-
-protected:
- std::unique_ptr<TestClient> Client;
-};
-
-} // namespace llgs_tests
-
-#endif // LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTBASE_H
+++ /dev/null
-//===-- TestClient.cpp ----------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestClient.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/common/TCPSocket.h"
-#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
-#include "lldb/Utility/Args.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gtest/gtest.h"
-#include <cstdlib>
-#include <future>
-#include <sstream>
-#include <string>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace llvm;
-using namespace llgs_tests;
-
-#ifdef SendMessage
-#undef SendMessage
-#endif
-
-TestClient::TestClient(std::unique_ptr<Connection> Conn) {
- SetConnection(std::move(Conn));
- SetPacketTimeout(std::chrono::seconds(10));
-}
-
-TestClient::~TestClient() {
- if (!IsConnected())
- return;
-
- EXPECT_THAT_ERROR(SendMessage("k"), Succeeded());
-}
-
-Error TestClient::initializeConnection() {
- if (SendAck() == 0)
- return make_error<StringError>("Sending initial ACK failed.",
- inconvertibleErrorCode());
-
- if (Error E = SendMessage("QStartNoAckMode"))
- return E;
-
- m_send_acks = false;
- return Error::success();
-}
-
-Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) {
- return launch(Log, {});
-}
-
-Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) {
- return launchCustom(Log, {}, InferiorArgs);
-}
-
-Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, ArrayRef<StringRef> ServerArgs, ArrayRef<StringRef> InferiorArgs) {
- const ArchSpec &arch_spec = HostInfo::GetArchitecture();
- Args args;
- args.AppendArgument(LLDB_SERVER);
- if (IsLldbServer())
- args.AppendArgument("gdbserver");
- args.AppendArgument("--reverse-connect");
-
- if (!Log.empty()) {
- args.AppendArgument(("--log-file=" + Log).str());
- if (IsLldbServer())
- args.AppendArgument("--log-channels=gdb-remote packets");
- else
- args.AppendArgument("--log-flags=0x800000");
- }
-
- Status status;
- TCPSocket listen_socket(true, false);
- status = listen_socket.Listen("127.0.0.1:0", 5);
- if (status.Fail())
- return status.ToError();
-
- args.AppendArgument(
- ("127.0.0.1:" + Twine(listen_socket.GetLocalPortNumber())).str());
-
- for (StringRef arg : ServerArgs)
- args.AppendArgument(arg);
-
- if (!InferiorArgs.empty()) {
- args.AppendArgument("--");
- for (StringRef arg : InferiorArgs)
- args.AppendArgument(arg);
- }
-
- ProcessLaunchInfo Info;
- Info.SetArchitecture(arch_spec);
- Info.SetArguments(args, true);
- Info.GetEnvironment() = Host::GetEnvironment();
- // TODO: Use this callback to detect botched launches. If lldb-server does not
- // start, we can print a nice error message here instead of hanging in
- // Accept().
- Info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback,
- false);
-
- status = Host::LaunchProcess(Info);
- if (status.Fail())
- return status.ToError();
-
- Socket *accept_socket;
- listen_socket.Accept(accept_socket);
- auto Conn = std::make_unique<ConnectionFileDescriptor>(accept_socket);
- auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
-
- if (Error E = Client->initializeConnection())
- return std::move(E);
-
- if (!InferiorArgs.empty()) {
- if (Error E = Client->queryProcess())
- return std::move(E);
- }
-
- return std::move(Client);
-}
-
-Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
- if (SendEnvironment(Host::GetEnvironment()) != 0) {
- return make_error<StringError>("Failed to set launch environment",
- inconvertibleErrorCode());
- }
- std::stringstream command;
- command << "A";
- for (size_t i = 0; i < inferior_args.size(); i++) {
- if (i > 0)
- command << ',';
- std::string hex_encoded = toHex(inferior_args[i]);
- command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
- }
-
- if (Error E = SendMessage(command.str()))
- return E;
- if (Error E = SendMessage("qLaunchSuccess"))
- return E;
- if (Error E = queryProcess())
- return E;
- return Error::success();
-}
-
-Error TestClient::ListThreadsInStopReply() {
- return SendMessage("QListThreadsInStopReply");
-}
-
-Error TestClient::SetBreakpoint(unsigned long address) {
- return SendMessage(formatv("Z0,{0:x-},1", address).str());
-}
-
-Error TestClient::ContinueAll() { return Continue("vCont;c"); }
-
-Error TestClient::ContinueThread(unsigned long thread_id) {
- return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
-}
-
-const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
- return *m_process_info;
-}
-
-Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
- return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
-}
-
-const StopReply &TestClient::GetLatestStopReply() {
- assert(m_stop_reply);
- return *m_stop_reply;
-}
-
-Error TestClient::SendMessage(StringRef message) {
- std::string dummy_string;
- return SendMessage(message, dummy_string);
-}
-
-Error TestClient::SendMessage(StringRef message, std::string &response_string) {
- if (Error E = SendMessage(message, response_string, PacketResult::Success))
- return E;
- StringExtractorGDBRemote Extractor(response_string);
- if (Extractor.IsErrorResponse())
- return Extractor.GetStatus().ToError();
- return Error::success();
-}
-
-Error TestClient::SendMessage(StringRef message, std::string &response_string,
- PacketResult expected_result) {
- StringExtractorGDBRemote response;
- GTEST_LOG_(INFO) << "Send Packet: " << message.str();
- PacketResult result = SendPacketAndWaitForResponse(message, response);
- response.GetEscapedBinaryData(response_string);
- GTEST_LOG_(INFO) << "Read Packet: " << response_string;
- if (result != expected_result)
- return make_error<StringError>(
- formatv("Error sending message `{0}`: {1}", message, result).str(),
- inconvertibleErrorCode());
-
- return Error::success();
-}
-
-unsigned int TestClient::GetPcRegisterId() {
- assert(m_pc_register != LLDB_INVALID_REGNUM);
- return m_pc_register;
-}
-
-Error TestClient::qProcessInfo() {
- m_process_info = None;
- auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo");
- if (!InfoOr)
- return InfoOr.takeError();
- m_process_info = std::move(*InfoOr);
- return Error::success();
-}
-
-Error TestClient::qRegisterInfos() {
- uint32_t reg_offset = 0;
- for (unsigned int Reg = 0;; ++Reg) {
- std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str();
- Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message);
- if (!InfoOr) {
- consumeError(InfoOr.takeError());
- break;
- }
- m_register_infos.emplace_back(std::move(*InfoOr));
-
- if (m_register_infos[Reg].byte_offset == LLDB_INVALID_INDEX32)
- m_register_infos[Reg].byte_offset = reg_offset;
-
- reg_offset =
- m_register_infos[Reg].byte_offset + m_register_infos[Reg].byte_size;
- if (m_register_infos[Reg].kinds[eRegisterKindGeneric] ==
- LLDB_REGNUM_GENERIC_PC)
- m_pc_register = Reg;
- }
- if (m_pc_register == LLDB_INVALID_REGNUM)
- return make_parsing_error("qRegisterInfo: generic");
- return Error::success();
-}
-
-Error TestClient::queryProcess() {
- if (Error E = qProcessInfo())
- return E;
- if (Error E = qRegisterInfos())
- return E;
- return Error::success();
-}
-
-Error TestClient::Continue(StringRef message) {
- assert(m_process_info.hasValue());
-
- auto StopReplyOr = SendMessage<StopReply>(
- message, m_process_info->GetEndian(), m_register_infos);
- if (!StopReplyOr)
- return StopReplyOr.takeError();
-
- m_stop_reply = std::move(*StopReplyOr);
- if (!isa<StopReplyStop>(m_stop_reply)) {
- StringExtractorGDBRemote R;
- PacketResult result = ReadPacket(R, GetPacketTimeout(), false);
- if (result != PacketResult::ErrorDisconnected) {
- return make_error<StringError>(
- formatv("Expected connection close after sending {0}. Got {1}/{2} "
- "instead.",
- message, result, R.GetStringRef())
- .str(),
- inconvertibleErrorCode());
- }
- }
- return Error::success();
-}
+++ /dev/null
-//===-- TestClient.h --------------------------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H
-#define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H
-
-#include "MessageObjects.h"
-#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
-#include "lldb/Host/ProcessLaunchInfo.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/Connection.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/FormatVariadic.h"
-#include <memory>
-#include <string>
-
-#if LLDB_SERVER_IS_DEBUGSERVER
-#define LLGS_TEST(x) DISABLED_ ## x
-#define DS_TEST(x) x
-#else
-#define LLGS_TEST(x) x
-#define DS_TEST(x) DISABLED_ ## x
-#endif
-
-namespace llgs_tests {
-class TestClient
- : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient {
-public:
- static bool IsDebugServer() { return LLDB_SERVER_IS_DEBUGSERVER; }
- static bool IsLldbServer() { return !IsDebugServer(); }
-
- /// Launches the server, connects it to the client and returns the client. If
- /// Log is non-empty, the server will write it's log to this file.
- static llvm::Expected<std::unique_ptr<TestClient>> launch(llvm::StringRef Log);
-
- /// Launches the server, while specifying the inferior on its command line.
- /// When the client connects, it already has a process ready.
- static llvm::Expected<std::unique_ptr<TestClient>>
- launch(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> InferiorArgs);
-
- /// Allows user to pass additional arguments to the server. Be careful when
- /// using this for generic tests, as the two stubs have different
- /// command-line interfaces.
- static llvm::Expected<std::unique_ptr<TestClient>>
- launchCustom(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> ServerArgs, llvm::ArrayRef<llvm::StringRef> InferiorArgs);
-
-
- ~TestClient() override;
- llvm::Error SetInferior(llvm::ArrayRef<std::string> inferior_args);
- llvm::Error ListThreadsInStopReply();
- llvm::Error SetBreakpoint(unsigned long address);
- llvm::Error ContinueAll();
- llvm::Error ContinueThread(unsigned long thread_id);
- const ProcessInfo &GetProcessInfo();
- llvm::Expected<JThreadsInfo> GetJThreadsInfo();
- const StopReply &GetLatestStopReply();
- template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() {
- assert(m_stop_reply);
- if (const auto *Reply = llvm::dyn_cast<T>(m_stop_reply.get()))
- return *Reply;
- return llvm::make_error<llvm::StringError>(
- llvm::formatv("Unexpected Stop Reply {0}", m_stop_reply->getKind()),
- llvm::inconvertibleErrorCode());
- }
- llvm::Error SendMessage(llvm::StringRef message);
- llvm::Error SendMessage(llvm::StringRef message,
- std::string &response_string);
- llvm::Error SendMessage(llvm::StringRef message, std::string &response_string,
- PacketResult expected_result);
-
- template <typename P, typename... CreateArgs>
- llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message,
- CreateArgs &&... Args);
- unsigned int GetPcRegisterId();
-
-private:
- TestClient(std::unique_ptr<lldb_private::Connection> Conn);
-
- llvm::Error initializeConnection();
- llvm::Error qProcessInfo();
- llvm::Error qRegisterInfos();
- llvm::Error queryProcess();
- llvm::Error Continue(llvm::StringRef message);
- std::string FormatFailedResult(
- const std::string &message,
- lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult
- result);
-
- llvm::Optional<ProcessInfo> m_process_info;
- std::unique_ptr<StopReply> m_stop_reply;
- std::vector<lldb_private::RegisterInfo> m_register_infos;
- unsigned int m_pc_register = LLDB_INVALID_REGNUM;
-};
-
-template <typename P, typename... CreateArgs>
-llvm::Expected<typename P::result_type>
-TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) {
- std::string ResponseText;
- if (llvm::Error E = SendMessage(Message, ResponseText))
- return std::move(E);
- return P::create(ResponseText, std::forward<CreateArgs>(Args)...);
-}
-
-} // namespace llgs_tests
-
-#endif // LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H
+++ /dev/null
-//===-- ThreadsInJstopinfoTest.cpp ----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "TestBase.h"
-#include "TestClient.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include <string>
-
-using namespace llgs_tests;
-using namespace lldb_private;
-using namespace llvm;
-using namespace lldb;
-using namespace testing;
-
-#ifdef __NetBSD__
-#define SKIP_ON_NETBSD(x) DISABLED_ ## x
-#else
-#define SKIP_ON_NETBSD(x) x
-#endif
-
-TEST_F(StandardStartupTest, SKIP_ON_NETBSD(TestStopReplyContainsThreadPcs)) {
- // This inferior spawns 4 threads, then forces a break.
- ASSERT_THAT_ERROR(
- Client->SetInferior({getInferiorPath("thread_inferior"), "4"}),
- Succeeded());
-
- ASSERT_THAT_ERROR(Client->ListThreadsInStopReply(), Succeeded());
- ASSERT_THAT_ERROR(Client->ContinueAll(), Succeeded());
- unsigned int pc_reg = Client->GetPcRegisterId();
- ASSERT_NE(pc_reg, UINT_MAX);
-
- auto jthreads_info = Client->GetJThreadsInfo();
- ASSERT_THAT_EXPECTED(jthreads_info, Succeeded());
-
- auto stop_reply = Client->GetLatestStopReplyAs<StopReplyStop>();
- ASSERT_THAT_EXPECTED(stop_reply, Succeeded());
- auto stop_reply_pcs = stop_reply->getThreadPcs();
- auto thread_infos = jthreads_info->GetThreadInfos();
- ASSERT_EQ(stop_reply_pcs.size(), thread_infos.size())
- << "Thread count mismatch.";
-
- for (auto stop_reply_pc : stop_reply_pcs) {
- unsigned long tid = stop_reply_pc.first;
- ASSERT_TRUE(thread_infos.find(tid) != thread_infos.end())
- << "Thread ID: " << tid << " not in JThreadsInfo.";
- EXPECT_THAT(thread_infos[tid].ReadRegister(pc_reg),
- Pointee(Eq(stop_reply_pc.second)));
- }
-}