summaryrefslogtreecommitdiff
path: root/lldb/source/Commands/CommandObjectProcessScripted.cpp
blob: f2d3250027e91eea69bf731b8393822c762bff41 (plain)
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//===-- CommandObjectProcessScripted.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 "CommandObjectProcessScripted.h"

#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"

using namespace lldb;
using namespace lldb_private;

// CommandObjectProcessScriptedLoad
#pragma mark CommandObjectProcessScriptedLoad
#define LLDB_OPTIONS_process_scripted_load
#include "CommandOptions.inc"

class CommandObjectProcessScriptedLoad : public CommandObjectParsed {
private:
  class CommandOptions : public OptionGroup {
  public:
    CommandOptions() : OptionGroup() {}
    ~CommandOptions() override = default;

    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
                          ExecutionContext *execution_context) override {
      Status error;
      const int short_option =
          g_process_scripted_load_options[option_idx].short_option;

      switch (short_option) {
      case 'S':
        m_module = std::string(option_arg);
        break;
      default:
        llvm_unreachable("Unimplemented option");
      }

      return error;
    }

    void OptionParsingStarting(ExecutionContext *execution_context) override {
      m_module = "";
    }

    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
      return llvm::makeArrayRef(g_process_scripted_load_options);
    }

    std::string m_module;
  };

  CommandOptions m_options;
  OptionGroupPythonClassWithDict m_class_options;
  OptionGroupOptions m_all_options;

  Options *GetOptions() override { return &m_all_options; }

protected:
  bool DoExecute(Args &command, CommandReturnObject &result) override {
#if LLDB_ENABLE_PYTHON
    if (m_class_options.GetName().empty()) {
      result.AppendErrorWithFormat(
          "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
      result.SetStatus(eReturnStatusFailed);
      return false;
    }

    if (m_options.m_module.empty()) {
      result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
                                   m_cmd_name.c_str());
      result.SetStatus(eReturnStatusFailed);
      return false;
    }

    ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();

    if (interpreter &&
        !interpreter->CheckObjectExists(m_class_options.GetName().c_str())) {
      result.AppendWarning(
          "The provided class does not exist - please define it "
          "before attempting to use this frame recognizer");
    }

    Target &target = GetSelectedOrDummyTarget();
    if (target.IsValid()) {
      FileSpec script_spec(m_options.m_module);
      ScriptedProcessLaunchInfo launch_info =
          (m_class_options.IsClass())
              ? ScriptedProcessLaunchInfo(script_spec,
                                          m_class_options.GetName())
              : ScriptedProcessLaunchInfo(m_class_options.GetStructuredData());
      target.SetScriptedProcessLaunchInfo(launch_info);
    }
#endif
    result.SetStatus(eReturnStatusSuccessFinishNoResult);
    return result.Succeeded();
  }

public:
  CommandObjectProcessScriptedLoad(CommandInterpreter &interpreter)
      : CommandObjectParsed(
            interpreter, "process scripted load",
            "Load a scripted process.\n"
            "You can either specify a script file and the implementation class "
            "or you can specify a dictionary of key (-k) and value (-v) pairs "
            "that will be used to populate an SBStructuredData Dictionary, "
            "which "
            "will be passed to the constructor of the class implementing the "
            "scripted step.  See the Python Reference for more details.",
            nullptr),
        m_options(), m_class_options("process scripted load") {
    m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
                         LLDB_OPT_SET_ALL);
    m_all_options.Append(&m_options, LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
                         LLDB_OPT_SET_ALL);
    m_all_options.Finalize();
    /*    FIXME: Update Long Help
    //    SetHelpLong(R"(
    //                Frame recognizers allow for retrieving information about
    //                special frames based on ABI, arguments or other special
    //                properties of that frame, even without source code or
    //                debug info. Currently, one use case is to extract function
    //                arguments that would otherwise be unaccesible, or augment
    //                existing arguments.
    //
    //                Adding a custom frame recognizer is possible by
    //                implementing a Python class and using the 'frame
    //                recognizer add' command. The Python class should have a
    //                'get_recognized_arguments' method and it will receive an
    //                argument of type lldb.SBFrame representing the current
    //                frame that we are trying to recognize. The method should
    //                return a (possibly empty) list of lldb.SBValue objects
    //                that represent the recognized arguments.
    //
    //                An example of a recognizer that retrieves the file
    //                descriptor values from libc functions 'read', 'write' and
    //                'close' follows:
    //
    //                class LibcFdRecognizer(object):
    //                def get_recognized_arguments(self, frame):
    //                if frame.name in ["read", "write", "close"]:
    //                fd = frame.EvaluateExpression("$arg1").unsigned
    //                value = lldb.target.CreateValueFromExpression("fd",
    //                "(int)%d" % fd) return [value] return []
    //
    //                The file containing this implementation can be imported
    //                via 'command script import' and then we can register this
    //                recognizer with 'frame recognizer add'. It's important to
    //                restrict the recognizer to the libc library (which is
    //                libsystem_kernel.dylib on macOS) to avoid matching
    //                functions with the same name in other modules:
    //
    //                (lldb) command script import .../fd_recognizer.py
    //                (lldb) frame recognizer add -l
    //                fd_recognizer.LibcFdRecognizer -n read -s
    //                libsystem_kernel.dylib
    //
    //                When the program is stopped at the beginning of the 'read'
    //                function in libc, we can view the recognizer arguments in
    //                'frame variable':
    //
    //                (lldb) b read
    //                (lldb) r
    //                Process 1234 stopped
    //                * thread #1, queue = 'com.apple.main-thread', stop reason
    //                = breakpoint 1.3 frame #0: 0x00007fff06013ca0
    //                libsystem_kernel.dylib`read (lldb) frame variable (int) fd
    //                = 3
    //
    //                )");
    */
  }
  ~CommandObjectProcessScriptedLoad() override = default;
};

CommandObjectProcessScripted::CommandObjectProcessScripted(
    CommandInterpreter &interpreter)
    : CommandObjectMultiword(
          interpreter, "process scripted",
          "Commands for operating on scripted processes.",
          "process plugin <subcommand> [<subcommand-options>]") {
  LoadSubCommand("load", CommandObjectSP(new CommandObjectProcessScriptedLoad(
                             interpreter)));
  // TODO: Implement CommandObjectProcessPluginScriptedGenerate
  //  LoadSubCommand(
  //      "generate",
  //      CommandObjectSP(new CommandObjectProcessScriptedLoad(interpreter)));
}