-
Notifications
You must be signed in to change notification settings - Fork 15k
When running OS Plugins from dSYM's, make sure start state is correct #146441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
lldb/test/API/functionalities/plugins/python_os_plugin/os_plugin_in_dsym/Makefile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| C_SOURCES := main.c | ||
| ENABLE_THREADS := YES | ||
|
|
||
| include Makefile.rules |
153 changes: 153 additions & 0 deletions
153
lldb/test/API/functionalities/plugins/python_os_plugin/os_plugin_in_dsym/TestOSIndSYM.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| """ | ||
| Test that an OS plugin in a dSYM sees the right process state | ||
| when run from a dSYM on attach | ||
| """ | ||
|
|
||
| from lldbsuite.test.decorators import * | ||
| from lldbsuite.test.lldbtest import * | ||
| import lldbsuite.test.lldbutil as lldbutil | ||
| from lldbgdbserverutils import get_debugserver_exe | ||
|
|
||
| import os | ||
| import lldb | ||
| import time | ||
| import socket | ||
| import shutil | ||
|
|
||
|
|
||
| class TestOSPluginIndSYM(TestBase): | ||
| NO_DEBUG_INFO_TESTCASE = True | ||
|
|
||
| # The port used by debugserver. | ||
| PORT = 54638 | ||
|
|
||
| # The number of attempts. | ||
| ATTEMPTS = 10 | ||
|
|
||
| # Time given to the binary to launch and to debugserver to attach to it for | ||
| # every attempt. We'll wait a maximum of 10 times 2 seconds while the | ||
| # inferior will wait 10 times 10 seconds. | ||
| TIMEOUT = 2 | ||
|
|
||
| def no_debugserver(self): | ||
| if get_debugserver_exe() is None: | ||
| return "no debugserver" | ||
| return None | ||
|
|
||
| def port_not_available(self): | ||
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| if s.connect_ex(("127.0.0.1", self.PORT)) == 0: | ||
| return "{} not available".format(self.PORT) | ||
| return None | ||
|
|
||
| @skipUnlessDarwin | ||
| def test_python_os_plugin(self): | ||
| self.do_test_python_os_plugin(False) | ||
|
|
||
| @skipTestIfFn(no_debugserver) | ||
| @skipTestIfFn(port_not_available) | ||
| def test_python_os_plugin_remote(self): | ||
| self.do_test_python_os_plugin(True) | ||
|
|
||
| def do_test_python_os_plugin(self, remote): | ||
| """Test that the environment for os plugins in dSYM's is correct""" | ||
| executable = self.build_dsym("my_binary") | ||
|
|
||
| # Make sure we're set up to load the symbol file's python | ||
| self.runCmd("settings set target.load-script-from-symbol-file true") | ||
|
|
||
| target = self.dbg.CreateTarget(None) | ||
|
|
||
| error = lldb.SBError() | ||
|
|
||
| # Now run the process, and then attach. When the attach | ||
| # succeeds, make sure that we were in the right state when | ||
| # the OS plugins were run. | ||
| if not remote: | ||
| popen = self.spawnSubprocess(executable, []) | ||
|
|
||
| process = target.AttachToProcessWithID(lldb.SBListener(), popen.pid, error) | ||
| self.assertSuccess(error, "Attach succeeded") | ||
| else: | ||
| self.setup_remote_platform(executable) | ||
| process = target.process | ||
| self.assertTrue(process.IsValid(), "Got a valid process from debugserver") | ||
|
|
||
| # We should have figured out the target from the result of the attach: | ||
| self.assertTrue(target.IsValid, "Got a valid target") | ||
|
|
||
| # Make sure that we got the right plugin: | ||
| self.expect( | ||
| "settings show target.process.python-os-plugin-path", | ||
| substrs=["operating_system.py"], | ||
| ) | ||
|
|
||
| for thread in process.threads: | ||
| stack_depth = thread.num_frames | ||
| reg_threads = thread.frames[0].reg | ||
|
|
||
| # OKAY, that realized the threads, now see if the creation | ||
| # state was correct. The way we use the OS plugin, it doesn't need | ||
| # to create a thread, and doesn't have to call get_register_info, | ||
| # so we don't expect those to get called. | ||
| self.expect( | ||
| "test_report_command", | ||
| substrs=[ | ||
| "in_init=1", | ||
| "in_get_thread_info=1", | ||
| "in_create_thread=2", | ||
| "in_get_register_info=2", | ||
| "in_get_register_data=1", | ||
| ], | ||
| ) | ||
|
|
||
| def build_dsym(self, name): | ||
| self.build(debug_info="dsym", dictionary={"EXE": name}) | ||
| executable = self.getBuildArtifact(name) | ||
| dsym_path = self.getBuildArtifact(name + ".dSYM") | ||
| python_dir_path = dsym_path | ||
| python_dir_path = os.path.join(dsym_path, "Contents", "Resources", "Python") | ||
| if not os.path.exists(python_dir_path): | ||
| os.mkdir(python_dir_path) | ||
| python_file_name = name + ".py" | ||
|
|
||
| os_plugin_dir = os.path.join(python_dir_path, "OS_Plugin") | ||
| if not os.path.exists(os_plugin_dir): | ||
| os.mkdir(os_plugin_dir) | ||
|
|
||
| plugin_dest_path = os.path.join(os_plugin_dir, "operating_system.py") | ||
| plugin_origin_path = os.path.join(self.getSourceDir(), "operating_system.py") | ||
| shutil.copy(plugin_origin_path, plugin_dest_path) | ||
|
|
||
| module_dest_path = os.path.join(python_dir_path, python_file_name) | ||
| with open(module_dest_path, "w") as f: | ||
| f.write("def __lldb_init_module(debugger, unused):\n") | ||
| f.write( | ||
| f" debugger.HandleCommand(\"settings set target.process.python-os-plugin-path '{plugin_dest_path}'\")\n" | ||
| ) | ||
| f.close() | ||
|
|
||
| return executable | ||
|
|
||
| def setup_remote_platform(self, exe): | ||
| # Get debugserver to start up our process for us, and then we | ||
| # can use `process connect` to attach to it. | ||
| debugserver = get_debugserver_exe() | ||
| debugserver_args = ["localhost:{}".format(self.PORT), exe] | ||
| self.spawnSubprocess(debugserver, debugserver_args) | ||
|
|
||
| # Select the platform. | ||
| self.runCmd("platform select remote-gdb-server") | ||
|
|
||
| # Connect to debugserver | ||
| interpreter = self.dbg.GetCommandInterpreter() | ||
| connected = False | ||
| for i in range(self.ATTEMPTS): | ||
| result = lldb.SBCommandReturnObject() | ||
| interpreter.HandleCommand(f"gdb-remote localhost:{self.PORT}", result) | ||
| connected = result.Succeeded() | ||
| if connected: | ||
| break | ||
| time.sleep(self.TIMEOUT) | ||
|
|
||
| self.assertTrue(connected, "could not connect to debugserver") |
8 changes: 8 additions & 0 deletions
8
lldb/test/API/functionalities/plugins/python_os_plugin/os_plugin_in_dsym/main.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| #include <unistd.h> | ||
|
|
||
| int main() { | ||
| while (1) { | ||
| sleep(1); | ||
| } | ||
| return 0; | ||
| } |
83 changes: 83 additions & 0 deletions
83
lldb/test/API/functionalities/plugins/python_os_plugin/os_plugin_in_dsym/operating_system.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| #!/usr/bin/env python | ||
|
|
||
| import lldb | ||
| import struct | ||
|
|
||
| # Value is: | ||
| # 0 called - state is not stopped | ||
| # 1 called - state is stopped | ||
| # 2 not called | ||
|
|
||
| stop_state = { | ||
| "in_init": 2, | ||
| "in_get_thread_info": 2, | ||
| "in_create_thread": 2, | ||
| "in_get_register_info": 2, | ||
| "in_get_register_data": 2, | ||
| } | ||
|
|
||
|
|
||
| def ReportCommand(debugger, command, exe_ctx, result, unused): | ||
| global stop_state | ||
| for state in stop_state: | ||
| result.AppendMessage(f"{state}={stop_state[state]}\n") | ||
| result.SetStatus(lldb.eReturnStatusSuccessFinishResult) | ||
|
|
||
|
|
||
| class OperatingSystemPlugIn: | ||
| """This class checks that all the""" | ||
|
|
||
| def __init__(self, process): | ||
| """Initialization needs a valid.SBProcess object. | ||
| global stop_state | ||
|
|
||
| This plug-in will get created after a live process is valid and has stopped for the | ||
| first time.""" | ||
| self.process = process | ||
| stop_state["in_init"] = self.state_is_stopped() | ||
| interp = process.target.debugger.GetCommandInterpreter() | ||
| result = lldb.SBCommandReturnObject() | ||
| cmd_str = ( | ||
| f"command script add test_report_command -o -f {__name__}.ReportCommand" | ||
| ) | ||
| interp.HandleCommand(cmd_str, result) | ||
|
|
||
| def state_is_stopped(self): | ||
| if self.process.state == lldb.eStateStopped: | ||
| return 1 | ||
| else: | ||
| return 0 | ||
|
|
||
| def does_plugin_report_all_threads(self): | ||
| return True | ||
|
|
||
| def create_thread(self, tid, context): | ||
| global stop_state | ||
| stop_state["in_create_thread"] = self.state_is_stopped() | ||
|
|
||
| return None | ||
|
|
||
| def get_thread_info(self): | ||
| global stop_state | ||
| stop_state["in_get_thread_info"] = self.state_is_stopped() | ||
| idx = self.process.threads[0].idx | ||
| return [ | ||
| { | ||
| "tid": 0x111111111, | ||
| "name": "one", | ||
| "queue": "queue1", | ||
| "state": "stopped", | ||
| "stop_reason": "breakpoint", | ||
| "core": idx, | ||
| } | ||
| ] | ||
|
|
||
| def get_register_info(self): | ||
| global stop_state | ||
| stop_state["in_get_register_info"] = self.state_is_stopped() | ||
| return None | ||
|
|
||
| def get_register_data(self, tid): | ||
| global stop_state | ||
| stop_state["in_get_register_data"] = self.state_is_stopped() | ||
| return None |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My first instinct here was "should this be an else" before I realized that
LoadOperatingSystemPluginprobably initializesm_os_up. Might be wroth a comment.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment to make this clear.