def __init__(self, target: lldb.SBTarget, args: lldb.SBStructuredData):
        super().__init__(target, args)

        self.backing_target_idx = args.GetValueForKey("backing_target_idx")

        self.corefile_target = None
        self.corefile_process = None
        if (self.backing_target_idx and self.backing_target_idx.IsValid()):
            if self.backing_target_idx.GetType(
            ) == lldb.eStructuredDataTypeInteger:
                idx = self.backing_target_idx.GetIntegerValue(42)
            if self.backing_target_idx.GetType(
            ) == lldb.eStructuredDataTypeString:
                idx = int(self.backing_target_idx.GetStringValue(100))
            self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx)
            self.corefile_process = self.corefile_target.GetProcess()
            for corefile_thread in self.corefile_process:
                structured_data = lldb.SBStructuredData()
                structured_data.SetFromJSON(
                    json.dumps({
                        "backing_target_idx": idx,
                        "thread_idx": corefile_thread.GetIndexID()
                    }))

                self.threads[
                    corefile_thread.GetThreadID()] = StackCoreScriptedThread(
                        self, structured_data)
Exemplo n.º 2
0
    def array_struct_test(self, dict_struct):
        # Check API returning a valid SBStructuredData of 'array' type
        array_struct = lldb.SBStructuredData()
        array_struct = dict_struct.GetValueForKey("key_array")
        if not array_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not array_struct.GetType() == lldb.eStructuredDataTypeArray:
            self.fail("Wrong type returned: " + str(array_struct.GetType()))

        # Check Size API for 'array' type
        if not array_struct.GetSize() == 2:
            self.fail("Wrong no of elements returned: " +
                      str(array_struct.GetSize()))

        # Check API returning a valid SBStructuredData for different 'array'
        # indices
        string_struct = array_struct.GetItemAtIndex(0)
        if not string_struct.IsValid():
            self.fail("A valid object should have been returned")
        if not string_struct.GetType() == lldb.eStructuredDataTypeString:
            self.fail("Wrong type returned: " + str(string_struct.GetType()))
        output = string_struct.GetStringValue(5)
        if not output == "23":
            self.fail("wrong output: " + str(output))

        string_struct = array_struct.GetItemAtIndex(1)
        if not string_struct.IsValid():
            self.fail("A valid object should have been returned")
        if not string_struct.GetType() == lldb.eStructuredDataTypeString:
            self.fail("Wrong type returned: " + str(string_struct.GetType()))
        output = string_struct.GetStringValue(5)
        if not output == "arr":
            self.fail("wrong output: " + str(output))
Exemplo n.º 3
0
    def do_bad_args_to_python_command(self):
        error = lldb.SBError()

        self.target = self.createTestTarget()

        self.expect("command script import --allow-reload ./bktptcmd.py")

        bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(bkpt, VALID_BREAKPOINT)

        # Pass a breakpoint command function that doesn't take extra_args,
        # but pass it extra args:

        extra_args = lldb.SBStructuredData()
        stream = lldb.SBStream()
        stream.Print('{"side_effect" : "I am fancy"}')
        extra_args.SetFromJSON(stream)

        error = bkpt.SetScriptCallbackFunction("bktptcmd.function", extra_args)
        self.assertTrue(
            error.Fail(),
            "Can't pass extra args if the function doesn't take them")

        error = bkpt.SetScriptCallbackFunction("bktptcmd.useless_function",
                                               extra_args)
        self.assertTrue(
            error.Fail(),
            "Can't pass extra args if the function has wrong number of args.")

        error = bkpt.SetScriptCallbackFunction("bktptcmd.nosuch_function",
                                               extra_args)
        self.assertTrue(
            error.Fail(),
            "Can't pass extra args if the function doesn't exist.")
Exemplo n.º 4
0
 def make_extra_args(self):
     json_string = '{"symbol":"break_on_me", "test1": "value1"}'
     json_stream = lldb.SBStream()
     json_stream.Print(json_string)
     extra_args = lldb.SBStructuredData()
     error = extra_args.SetFromJSON(json_stream)
     self.assertTrue(error.Success(), "Error making SBStructuredData: %s"%(error.GetCString()))
     return extra_args
Exemplo n.º 5
0
    def test_launch_scripted_process_stack_frames(self):
        """Test that we can launch an lldb scripted process from the command
        line, check its process ID and read string from memory."""
        self.build()
        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
        self.assertTrue(target, VALID_TARGET)

        for module in target.modules:
            if 'a.out' in module.GetFileSpec().GetFilename():
                main_module = module
                break

        self.assertTrue(main_module, "Invalid main module.")
        error = target.SetModuleLoadAddress(main_module, 0)
        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")

        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
        def cleanup():
          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
        self.addTearDownHook(cleanup)

        scripted_process_example_relpath = 'stack_core_scripted_process.py'
        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
                                                            scripted_process_example_relpath))

        corefile_process = None
        with tempfile.NamedTemporaryFile() as file:
            self.create_stack_skinny_corefile(file.name)
            corefile_target = self.dbg.CreateTarget(None)
            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
        self.assertTrue(corefile_process, PROCESS_IS_VALID)

        structured_data = lldb.SBStructuredData()
        structured_data.SetFromJSON(json.dumps({
            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
        }))
        launch_info = lldb.SBLaunchInfo(None)
        launch_info.SetProcessPluginName("ScriptedProcess")
        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
        launch_info.SetScriptedProcessDictionary(structured_data)

        error = lldb.SBError()
        process = target.Launch(launch_info, error)
        self.assertTrue(error.Success(), error.GetCString())
        self.assertTrue(process, PROCESS_IS_VALID)
        self.assertEqual(process.GetProcessID(), 42)

        self.assertEqual(process.GetNumThreads(), 1)
        thread = process.GetSelectedThread()
        self.assertTrue(thread, "Invalid thread.")
        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")

        self.assertEqual(thread.GetNumFrames(), 3)
        frame = thread.GetSelectedFrame()
        self.assertTrue(frame, "Invalid frame.")
        self.assertEqual(frame.GetFunctionName(), "bar")
        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
Exemplo n.º 6
0
    def invalid_struct_test(self, example):
        invalid_struct = lldb.SBStructuredData()
        invalid_struct = example.GetValueForKey("invalid_key")
        if invalid_struct.IsValid():
            self.fail("An invalid object should have been returned")

        # Check Type API
        if not invalid_struct.GetType() == lldb.eStructuredDataTypeInvalid:
            self.fail("Wrong type returned: " + str(invalid_struct.GetType()))
    def structured_data_api_test(self):
        error = lldb.SBError()
        s = lldb.SBStream()
        s.Print(
            "{\"key_dict\":{\"key_string\":\"STRING\",\"key_int\":3,\"key_float\":2.99,\"key_bool\":true,\"key_array\":[\"23\",\"arr\"]}}"
        )
        example = lldb.SBStructuredData()

        # Check SetFromJSON API for dictionaries, integers, floating point
        # values, strings and arrays
        error = example.SetFromJSON(s)
        if not error.Success():
            self.fail("FAILED:   " + error.GetCString())

        # Tests for invalid data type
        self.invalid_struct_test(example)

        # Test that GetDescription works:
        s.Clear()
        error = example.GetDescription(s)
        self.assertTrue(error.Success(), "GetDescription works")
        if not "key_float" in s.GetData():
            self.fail("FAILED: could not find key_float in description output")

        dict_struct = lldb.SBStructuredData()
        dict_struct = example.GetValueForKey("key_dict")

        # Tests for dictionary data type
        self.dictionary_struct_test(example)

        # Tests for string data type
        self.string_struct_test(dict_struct)

        # Tests for integer data type
        self.int_struct_test(dict_struct)

        # Tests for floating point data type
        self.double_struct_test(dict_struct)

        # Tests for boolean data type
        self.bool_struct_test(dict_struct)

        # Tests for array data type
        self.array_struct_test(dict_struct)
Exemplo n.º 8
0
    def bool_struct_test(self, dict_struct):
        bool_struct = lldb.SBStructuredData()
        bool_struct = dict_struct.GetValueForKey("key_bool")
        if not bool_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not bool_struct.GetType() == lldb.eStructuredDataTypeBoolean:
            self.fail("Wrong type returned: " + str(bool_struct.GetType()))

        # Check API returning 'bool' value
        output = bool_struct.GetBooleanValue()
        if not output:
            self.fail("wrong output: " + str(output))
Exemplo n.º 9
0
    def double_struct_test(self, dict_struct):
        floating_point_struct = lldb.SBStructuredData()
        floating_point_struct = dict_struct.GetValueForKey("key_float")
        if not floating_point_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not floating_point_struct.GetType() == lldb.eStructuredDataTypeFloat:
            self.fail("Wrong type returned: " +
                      str(floating_point_struct.GetType()))

        # Check API returning 'double' value
        output = floating_point_struct.GetFloatValue()
        if not output == 2.99:
            self.fail("wrong output: " + str(output))
Exemplo n.º 10
0
    def dictionary_struct_test(self, example):
        # Check API returning a valid SBStructuredData of 'dictionary' type
        dict_struct = lldb.SBStructuredData()
        dict_struct = example.GetValueForKey("key_dict")
        if not dict_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not dict_struct.GetType() == lldb.eStructuredDataTypeDictionary:
            self.fail("Wrong type returned: " + str(dict_struct.GetType()))

        # Check Size API for 'dictionary' type
        if not dict_struct.GetSize() == 5:
            self.fail("Wrong no of elements returned: " +
                      str(dict_struct.GetSize()))
Exemplo n.º 11
0
    def __init__(self, target: lldb.SBTarget, args: lldb.SBStructuredData):
        super().__init__(target, args)

        self.corefile_target = None
        self.corefile_process = None

        self.backing_target_idx = args.GetValueForKey("backing_target_idx")
        if (self.backing_target_idx and self.backing_target_idx.IsValid()):
            if self.backing_target_idx.GetType(
            ) == lldb.eStructuredDataTypeInteger:
                idx = self.backing_target_idx.GetIntegerValue(42)
            if self.backing_target_idx.GetType(
            ) == lldb.eStructuredDataTypeString:
                idx = int(self.backing_target_idx.GetStringValue(100))
            self.corefile_target = target.GetDebugger().GetTargetAtIndex(idx)
            self.corefile_process = self.corefile_target.GetProcess()
            for corefile_thread in self.corefile_process:
                structured_data = lldb.SBStructuredData()
                structured_data.SetFromJSON(
                    json.dumps({
                        "backing_target_idx": idx,
                        "thread_idx": corefile_thread.GetIndexID()
                    }))

                self.threads[
                    corefile_thread.GetThreadID()] = StackCoreScriptedThread(
                        self, structured_data)

        if len(self.threads) == 2:
            self.threads[len(self.threads) - 1].is_stopped = True

        corefile_module = self.get_module_with_name(self.corefile_target,
                                                    "libbaz.dylib")
        if not corefile_module or not corefile_module.IsValid():
            return
        module_path = os.path.join(
            corefile_module.GetFileSpec().GetDirectory(),
            corefile_module.GetFileSpec().GetFilename())
        if not os.path.exists(module_path):
            return
        module_load_addr = corefile_module.GetObjectFileHeaderAddress(
        ).GetLoadAddress(self.corefile_target)

        self.loaded_images.append({
            "path": module_path,
            "load_addr": module_load_addr
        })
Exemplo n.º 12
0
def load_crashlog_in_scripted_process(debugger, crash_log_file):
    result = lldb.SBCommandReturnObject()

    crashlog_path = os.path.expanduser(crash_log_file)
    if not os.path.exists(crashlog_path):
        result.PutCString("error: crashlog file %s does not exist" %
                          crashlog_path)

    try:
        crashlog = CrashLogParser().parse(debugger, crashlog_path, False)
    except Exception as e:
        result.PutCString("error: python exception: %s" % e)
        return

    if debugger.GetNumTargets() > 0:
        target = debugger.GetTargetAtIndex(0)
    else:
        target = crashlog.create_target()
    if not target:
        result.PutCString("error: couldn't create target")
        return

    ci = debugger.GetCommandInterpreter()
    if not ci:
        result.PutCString("error: couldn't get command interpreter")
        return

    res = lldb.SBCommandReturnObject()
    ci.HandleCommand(
        'script from lldb.macosx import crashlog_scripted_process', res)
    if not res.Succeeded():
        result.PutCString(
            "error: couldn't import crashlog scripted process module")
        return

    structured_data = lldb.SBStructuredData()
    structured_data.SetFromJSON(json.dumps({"crashlog_path": crashlog_path}))
    launch_info = lldb.SBLaunchInfo(None)
    launch_info.SetProcessPluginName("ScriptedProcess")
    launch_info.SetScriptedProcessClassName(
        "crashlog_scripted_process.CrashLogScriptedProcess")
    launch_info.SetScriptedProcessDictionary(structured_data)
    error = lldb.SBError()
    process = target.Launch(launch_info, error)
Exemplo n.º 13
0
    def string_struct_test(self, dict_struct):
        string_struct = lldb.SBStructuredData()
        string_struct = dict_struct.GetValueForKey("key_string")
        if not string_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not string_struct.GetType() == lldb.eStructuredDataTypeString:
            self.fail("Wrong type returned: " + str(string_struct.GetType()))

        # Check API returning 'string' value
        output = string_struct.GetStringValue(25)
        if not "STRING" in output:
            self.fail("wrong output: " + output)

        # Calling wrong API on a SBStructuredData
        # (e.g. getting an integer from a string type structure)
        output = string_struct.GetIntegerValue()
        if output:
            self.fail("Valid integer value " + str(output) +
                      " returned for a string object")
Exemplo n.º 14
0
    def do_test_checking_variable(self, use_cli):
        self.build()
        (target, process, thread,
         bkpt) = lldbutil.run_to_source_breakpoint(self,
                                                   "Set a breakpoint here",
                                                   self.main_source_file)

        frame = thread.GetFrameAtIndex(0)
        self.assertEqual("foo", frame.GetFunctionName())
        foo_val = frame.FindVariable("foo")
        self.assertTrue(foo_val.GetError().Success(), "Got the foo variable")
        self.assertEqual(foo_val.GetValueAsUnsigned(), 10, "foo starts at 10")

        if use_cli:
            result = lldb.SBCommandReturnObject()
            self.dbg.GetCommandInterpreter().HandleCommand(
                "thread step-scripted -C Steps.StepUntil -k variable_name -v foo",
                result)
            self.assertTrue(result.Succeeded())
        else:
            args_data = lldb.SBStructuredData()
            data = lldb.SBStream()
            data.Print('{"variable_name" : "foo"}')
            error = args_data.SetFromJSON(data)
            self.assertTrue(error.Success(), "Made the args_data correctly")

            err = thread.StepUsingScriptedThreadPlan("Steps.StepUntil",
                                                     args_data, True)
            self.assertTrue(err.Success(), err.GetCString())

        # We should not have exited:
        self.assertEqual(process.GetState(), lldb.eStateStopped,
                         "We are stopped")

        # We should still be in foo:
        self.assertEqual("foo", frame.GetFunctionName())

        # And foo should have changed:
        self.assertTrue(foo_val.GetValueDidChange(), "Foo changed")
Exemplo n.º 15
0
    def int_struct_test(self, dict_struct):
        # Check a valid SBStructuredData containing an 'integer' by
        int_struct = lldb.SBStructuredData()
        int_struct = dict_struct.GetValueForKey("key_int")
        if not int_struct.IsValid():
            self.fail("A valid object should have been returned")

        # Check Type API
        if not int_struct.GetType() == lldb.eStructuredDataTypeInteger:
            self.fail("Wrong type returned: " + str(int_struct.GetType()))

        # Check API returning 'integer' value
        output = int_struct.GetIntegerValue()
        if not output == 3:
            self.fail("wrong output: " + str(output))

        # Calling wrong API on a SBStructuredData
        # (e.g. getting a string value from an integer type structure)
        output = int_struct.GetStringValue(25)
        if output:
            self.fail("Valid string " + output +
                      " returned for an integer object")
Exemplo n.º 16
0
    def test_launch_scripted_process_stack_frames(self):
        """Test that we can launch an lldb scripted process from the command
        line, check its process ID and read string from memory."""
        self.build()
        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
        self.assertTrue(target, VALID_TARGET)

        for module in target.modules:
            if 'a.out' in module.GetFileSpec().GetFilename():
                main_module = module
                break

        self.assertTrue(main_module, "Invalid main module.")
        error = target.SetModuleLoadAddress(main_module, 0)
        self.assertSuccess(error, "Reloading main module at offset 0 failed.")

        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'

        def cleanup():
            del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]

        self.addTearDownHook(cleanup)

        scripted_process_example_relpath = 'stack_core_scripted_process.py'
        self.runCmd("command script import " + os.path.join(
            self.getSourceDir(), scripted_process_example_relpath))

        corefile_process = None
        with tempfile.NamedTemporaryFile() as file:
            self.create_stack_skinny_corefile(file.name)
            corefile_target = self.dbg.CreateTarget(None)
            corefile_process = corefile_target.LoadCore(
                self.getBuildArtifact(file.name))
        self.assertTrue(corefile_process, PROCESS_IS_VALID)

        structured_data = lldb.SBStructuredData()
        structured_data.SetFromJSON(
            json.dumps({
                "backing_target_idx":
                self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
            }))
        launch_info = lldb.SBLaunchInfo(None)
        launch_info.SetProcessPluginName("ScriptedProcess")
        launch_info.SetScriptedProcessClassName(
            "stack_core_scripted_process.StackCoreScriptedProcess")
        launch_info.SetScriptedProcessDictionary(structured_data)

        error = lldb.SBError()
        process = target.Launch(launch_info, error)
        self.assertSuccess(error)
        self.assertTrue(process, PROCESS_IS_VALID)
        self.assertEqual(process.GetProcessID(), 42)

        self.assertEqual(process.GetNumThreads(), 3)
        thread = process.GetSelectedThread()
        self.assertTrue(thread, "Invalid thread.")
        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")

        self.assertTrue(target.triple, "Invalid target triple")
        arch = target.triple.split('-')[0]
        supported_arch = ['x86_64', 'arm64', 'arm64e']
        self.assertIn(arch, supported_arch)
        # When creating a corefile of a arm process, lldb saves the exception
        # that triggers the breakpoint in the LC_NOTES of the corefile, so they
        # can be reloaded with the corefile on the next debug session.
        if arch in 'arm64e':
            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonException)
        # However, it's architecture specific, and corefiles made from intel
        # process don't save any metadata to retrieve to stop reason.
        # To mitigate this, the StackCoreScriptedProcess will report a
        # eStopReasonSignal with a SIGTRAP, mimicking what debugserver does.
        else:
            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonSignal)

        self.assertEqual(thread.GetNumFrames(), 6)
        frame = thread.GetSelectedFrame()
        self.assertTrue(frame, "Invalid frame.")
        self.assertIn("bar", frame.GetFunctionName())
        self.assertEqual(
            int(
                frame.FindValue("i",
                                lldb.eValueTypeVariableArgument).GetValue()),
            42)
        self.assertEqual(
            int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()),
            42 * 42)
Exemplo n.º 17
0
    def do_set_python_command_from_python(self):
        exe = self.getBuildArtifact("a.out")
        error = lldb.SBError()

        self.target = self.dbg.CreateTarget(exe)
        self.assertTrue(self.target, VALID_TARGET)

        body_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(body_bkpt, VALID_BREAKPOINT)

        func_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(func_bkpt, VALID_BREAKPOINT)

        fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(fancy_bkpt, VALID_BREAKPOINT)

        fancier_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(fancier_bkpt, VALID_BREAKPOINT)

        not_so_fancy_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set break point at this line.", self.main_source_spec)
        self.assertTrue(not_so_fancy_bkpt, VALID_BREAKPOINT)

        # Also test that setting a source regex breakpoint with an empty file
        # spec list sets it on all files:
        no_files_bkpt = self.target.BreakpointCreateBySourceRegex(
            "Set a breakpoint here", lldb.SBFileSpecList(),
            lldb.SBFileSpecList())
        self.assertTrue(no_files_bkpt, VALID_BREAKPOINT)
        num_locations = no_files_bkpt.GetNumLocations()
        self.assertTrue(num_locations >= 2,
                        "Got at least two breakpoint locations")
        got_one_in_A = False
        got_one_in_B = False
        for idx in range(0, num_locations):
            comp_unit = no_files_bkpt.GetLocationAtIndex(idx).GetAddress(
            ).GetSymbolContext(
                lldb.eSymbolContextCompUnit).GetCompileUnit().GetFileSpec()
            print("Got comp unit: ", comp_unit.GetFilename())
            if comp_unit.GetFilename() == "a.c":
                got_one_in_A = True
            elif comp_unit.GetFilename() == "b.c":
                got_one_in_B = True

        self.assertTrue(got_one_in_A, "Failed to match the pattern in A")
        self.assertTrue(got_one_in_B, "Failed to match the pattern in B")
        self.target.BreakpointDelete(no_files_bkpt.GetID())

        error = lldb.SBError()
        error = body_bkpt.SetScriptCallbackBody(
            "import side_effect; side_effect.callback = 'callback was here'")
        self.assertTrue(
            error.Success(), "Failed to set the script callback body: %s." %
            (error.GetCString()))

        self.expect("command script import --allow-reload ./bktptcmd.py")

        func_bkpt.SetScriptCallbackFunction("bktptcmd.function")

        extra_args = lldb.SBStructuredData()
        stream = lldb.SBStream()
        stream.Print('{"side_effect" : "I am fancy"}')
        extra_args.SetFromJSON(stream)
        error = fancy_bkpt.SetScriptCallbackFunction(
            "bktptcmd.another_function", extra_args)
        self.assertTrue(error.Success(),
                        "Failed to add callback %s" % (error.GetCString()))

        stream.Clear()
        stream.Print('{"side_effect" : "I am so much fancier"}')
        extra_args.SetFromJSON(stream)

        # Fancier's callback is set up from the command line
        id = fancier_bkpt.GetID()
        self.expect(
            "breakpoint command add -F bktptcmd.a_third_function -k side_effect -v 'I am fancier' %d"
            % (id))

        # Not so fancy gets an empty extra_args:
        empty_args = lldb.SBStructuredData()
        error = not_so_fancy_bkpt.SetScriptCallbackFunction(
            "bktptcmd.empty_extra_args", empty_args)
        self.assertTrue(error.Success(),
                        "Failed to add callback %s" % (error.GetCString()))

        # Clear out canary variables
        side_effect.bktptcmd = None
        side_effect.callback = None
        side_effect.fancy = None
        side_effect.fancier = None
        side_effect.not_so_fancy = None

        # Now launch the process, and do not stop at entry point.
        self.process = self.target.LaunchSimple(
            None, None, self.get_process_working_directory())

        self.assertTrue(self.process, PROCESS_IS_VALID)

        # Now finish, and make sure the return value is correct.
        threads = lldbutil.get_threads_stopped_at_breakpoint(
            self.process, body_bkpt)
        self.assertEquals(len(threads), 1, "Stopped at inner breakpoint.")
        self.thread = threads[0]

        self.assertEquals("callback was here", side_effect.callback)
        self.assertEquals("function was here", side_effect.bktptcmd)
        self.assertEquals("I am fancy", side_effect.fancy)
        self.assertEquals("I am fancier", side_effect.fancier)
        self.assertEquals("Not so fancy", side_effect.not_so_fancy)
    def do_check_extra_args(self):

        import side_effect
        interp = self.dbg.GetCommandInterpreter()
        error = lldb.SBError()

        script_name = os.path.join(self.getSourceDir(), "resolver.py")

        command = "command script import " + script_name
        result = lldb.SBCommandReturnObject()
        interp.HandleCommand(command, result)
        self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError()))

        # First make sure a scripted breakpoint with no args works:
        bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver", lldb.SBStructuredData(),
                                                           lldb.SBFileSpecList(), lldb.SBFileSpecList())
        self.assertTrue(bkpt.IsValid(), "Bkpt is valid")
        write_bps = lldb.SBBreakpointList(self.orig_target)

        error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps)
        self.assertSuccess(error, "Failed writing breakpoints")

        side_effect.g_extra_args = None
        copy_bps = lldb.SBBreakpointList(self.copy_target)
        error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps)
        self.assertSuccess(error, "Failed reading breakpoints")

        self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.")
        no_keys = lldb.SBStringList()
        side_effect.g_extra_args.GetKeys(no_keys)
        self.assertEqual(no_keys.GetSize(), 0, "Should have no keys")

        self.orig_target.DeleteAllBreakpoints()
        self.copy_target.DeleteAllBreakpoints()

        # Now try one with extra args:

        extra_args = lldb.SBStructuredData()
        stream = lldb.SBStream()
        stream.Print('{"first_arg" : "first_value", "second_arg" : "second_value"}')
        extra_args.SetFromJSON(stream)
        self.assertTrue(extra_args.IsValid(), "SBStructuredData is valid.")

        bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver",
                                                           extra_args, lldb.SBFileSpecList(), lldb.SBFileSpecList())
        self.assertTrue(bkpt.IsValid(), "Bkpt is valid")
        write_bps = lldb.SBBreakpointList(self.orig_target)

        error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps)
        self.assertSuccess(error, "Failed writing breakpoints")

        orig_extra_args = side_effect.g_extra_args
        self.assertTrue(orig_extra_args.IsValid(), "Extra args originally valid")

        orig_keys = lldb.SBStringList()
        orig_extra_args.GetKeys(orig_keys)
        self.assertEqual(2, orig_keys.GetSize(), "Should have two keys")

        side_effect.g_extra_args = None

        copy_bps = lldb.SBBreakpointList(self.copy_target)
        error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps)
        self.assertSuccess(error, "Failed reading breakpoints")

        self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.")

        copy_extra_args = side_effect.g_extra_args
        copy_keys = lldb.SBStringList()
        copy_extra_args.GetKeys(copy_keys)
        self.assertEqual(2, copy_keys.GetSize(), "Copy should have two keys")

        for idx in range(0, orig_keys.GetSize()):
            key = orig_keys.GetStringAtIndex(idx)
            copy_value = copy_extra_args.GetValueForKey(key).GetStringValue(100)

            if key == "first_arg":
                self.assertEqual(copy_value, "first_value")
            elif key == "second_arg":
                self.assertEqual(copy_value, "second_value")
            else:
                self.Fail("Unknown key: %s"%(key))