Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp
39587 views
1
//===-- CommandObjectPlatform.cpp -----------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "CommandObjectPlatform.h"
10
#include "CommandOptionsProcessAttach.h"
11
#include "CommandOptionsProcessLaunch.h"
12
#include "lldb/Core/Debugger.h"
13
#include "lldb/Core/Module.h"
14
#include "lldb/Core/PluginManager.h"
15
#include "lldb/Host/OptionParser.h"
16
#include "lldb/Interpreter/CommandInterpreter.h"
17
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
18
#include "lldb/Interpreter/CommandOptionValidators.h"
19
#include "lldb/Interpreter/CommandReturnObject.h"
20
#include "lldb/Interpreter/OptionGroupFile.h"
21
#include "lldb/Interpreter/OptionGroupPlatform.h"
22
#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
23
#include "lldb/Target/ExecutionContext.h"
24
#include "lldb/Target/Platform.h"
25
#include "lldb/Target/Process.h"
26
#include "lldb/Utility/Args.h"
27
#include "lldb/Utility/ScriptedMetadata.h"
28
#include "lldb/Utility/State.h"
29
30
#include "llvm/ADT/SmallString.h"
31
32
using namespace lldb;
33
using namespace lldb_private;
34
35
static mode_t ParsePermissionString(const char *) = delete;
36
37
static mode_t ParsePermissionString(llvm::StringRef permissions) {
38
if (permissions.size() != 9)
39
return (mode_t)(-1);
40
bool user_r, user_w, user_x, group_r, group_w, group_x, world_r, world_w,
41
world_x;
42
43
user_r = (permissions[0] == 'r');
44
user_w = (permissions[1] == 'w');
45
user_x = (permissions[2] == 'x');
46
47
group_r = (permissions[3] == 'r');
48
group_w = (permissions[4] == 'w');
49
group_x = (permissions[5] == 'x');
50
51
world_r = (permissions[6] == 'r');
52
world_w = (permissions[7] == 'w');
53
world_x = (permissions[8] == 'x');
54
55
mode_t user, group, world;
56
user = (user_r ? 4 : 0) | (user_w ? 2 : 0) | (user_x ? 1 : 0);
57
group = (group_r ? 4 : 0) | (group_w ? 2 : 0) | (group_x ? 1 : 0);
58
world = (world_r ? 4 : 0) | (world_w ? 2 : 0) | (world_x ? 1 : 0);
59
60
return user | group | world;
61
}
62
63
#define LLDB_OPTIONS_permissions
64
#include "CommandOptions.inc"
65
66
class OptionPermissions : public OptionGroup {
67
public:
68
OptionPermissions() = default;
69
70
~OptionPermissions() override = default;
71
72
lldb_private::Status
73
SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
74
ExecutionContext *execution_context) override {
75
Status error;
76
char short_option = (char)GetDefinitions()[option_idx].short_option;
77
switch (short_option) {
78
case 'v': {
79
if (option_arg.getAsInteger(8, m_permissions)) {
80
m_permissions = 0777;
81
error.SetErrorStringWithFormat("invalid value for permissions: %s",
82
option_arg.str().c_str());
83
}
84
85
} break;
86
case 's': {
87
mode_t perms = ParsePermissionString(option_arg);
88
if (perms == (mode_t)-1)
89
error.SetErrorStringWithFormat("invalid value for permissions: %s",
90
option_arg.str().c_str());
91
else
92
m_permissions = perms;
93
} break;
94
case 'r':
95
m_permissions |= lldb::eFilePermissionsUserRead;
96
break;
97
case 'w':
98
m_permissions |= lldb::eFilePermissionsUserWrite;
99
break;
100
case 'x':
101
m_permissions |= lldb::eFilePermissionsUserExecute;
102
break;
103
case 'R':
104
m_permissions |= lldb::eFilePermissionsGroupRead;
105
break;
106
case 'W':
107
m_permissions |= lldb::eFilePermissionsGroupWrite;
108
break;
109
case 'X':
110
m_permissions |= lldb::eFilePermissionsGroupExecute;
111
break;
112
case 'd':
113
m_permissions |= lldb::eFilePermissionsWorldRead;
114
break;
115
case 't':
116
m_permissions |= lldb::eFilePermissionsWorldWrite;
117
break;
118
case 'e':
119
m_permissions |= lldb::eFilePermissionsWorldExecute;
120
break;
121
default:
122
llvm_unreachable("Unimplemented option");
123
}
124
125
return error;
126
}
127
128
void OptionParsingStarting(ExecutionContext *execution_context) override {
129
m_permissions = 0;
130
}
131
132
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
133
return llvm::ArrayRef(g_permissions_options);
134
}
135
136
// Instance variables to hold the values for command options.
137
138
uint32_t m_permissions;
139
140
private:
141
OptionPermissions(const OptionPermissions &) = delete;
142
const OptionPermissions &operator=(const OptionPermissions &) = delete;
143
};
144
145
// "platform select <platform-name>"
146
class CommandObjectPlatformSelect : public CommandObjectParsed {
147
public:
148
CommandObjectPlatformSelect(CommandInterpreter &interpreter)
149
: CommandObjectParsed(interpreter, "platform select",
150
"Create a platform if needed and select it as the "
151
"current platform.",
152
"platform select <platform-name>", 0),
153
m_platform_options(
154
false) // Don't include the "--platform" option by passing false
155
{
156
m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1);
157
m_option_group.Finalize();
158
AddSimpleArgumentList(eArgTypePlatform);
159
}
160
161
~CommandObjectPlatformSelect() override = default;
162
163
void HandleCompletion(CompletionRequest &request) override {
164
lldb_private::CommandCompletions::PlatformPluginNames(
165
GetCommandInterpreter(), request, nullptr);
166
}
167
168
Options *GetOptions() override { return &m_option_group; }
169
170
protected:
171
void DoExecute(Args &args, CommandReturnObject &result) override {
172
if (args.GetArgumentCount() == 1) {
173
const char *platform_name = args.GetArgumentAtIndex(0);
174
if (platform_name && platform_name[0]) {
175
const bool select = true;
176
m_platform_options.SetPlatformName(platform_name);
177
Status error;
178
ArchSpec platform_arch;
179
PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions(
180
m_interpreter, ArchSpec(), select, error, platform_arch));
181
if (platform_sp) {
182
GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp);
183
184
platform_sp->GetStatus(result.GetOutputStream());
185
result.SetStatus(eReturnStatusSuccessFinishResult);
186
} else {
187
result.AppendError(error.AsCString());
188
}
189
} else {
190
result.AppendError("invalid platform name");
191
}
192
} else {
193
result.AppendError(
194
"platform create takes a platform name as an argument\n");
195
}
196
}
197
198
OptionGroupOptions m_option_group;
199
OptionGroupPlatform m_platform_options;
200
};
201
202
// "platform list"
203
class CommandObjectPlatformList : public CommandObjectParsed {
204
public:
205
CommandObjectPlatformList(CommandInterpreter &interpreter)
206
: CommandObjectParsed(interpreter, "platform list",
207
"List all platforms that are available.", nullptr,
208
0) {}
209
210
~CommandObjectPlatformList() override = default;
211
212
protected:
213
void DoExecute(Args &args, CommandReturnObject &result) override {
214
Stream &ostrm = result.GetOutputStream();
215
ostrm.Printf("Available platforms:\n");
216
217
PlatformSP host_platform_sp(Platform::GetHostPlatform());
218
ostrm.Format("{0}: {1}\n", host_platform_sp->GetPluginName(),
219
host_platform_sp->GetDescription());
220
221
uint32_t idx;
222
for (idx = 0; true; ++idx) {
223
llvm::StringRef plugin_name =
224
PluginManager::GetPlatformPluginNameAtIndex(idx);
225
if (plugin_name.empty())
226
break;
227
llvm::StringRef plugin_desc =
228
PluginManager::GetPlatformPluginDescriptionAtIndex(idx);
229
ostrm.Format("{0}: {1}\n", plugin_name, plugin_desc);
230
}
231
232
if (idx == 0) {
233
result.AppendError("no platforms are available\n");
234
} else
235
result.SetStatus(eReturnStatusSuccessFinishResult);
236
}
237
};
238
239
// "platform status"
240
class CommandObjectPlatformStatus : public CommandObjectParsed {
241
public:
242
CommandObjectPlatformStatus(CommandInterpreter &interpreter)
243
: CommandObjectParsed(interpreter, "platform status",
244
"Display status for the current platform.", nullptr,
245
0) {}
246
247
~CommandObjectPlatformStatus() override = default;
248
249
protected:
250
void DoExecute(Args &args, CommandReturnObject &result) override {
251
Stream &ostrm = result.GetOutputStream();
252
253
Target *target = GetDebugger().GetSelectedTarget().get();
254
PlatformSP platform_sp;
255
if (target) {
256
platform_sp = target->GetPlatform();
257
}
258
if (!platform_sp) {
259
platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
260
}
261
if (platform_sp) {
262
platform_sp->GetStatus(ostrm);
263
result.SetStatus(eReturnStatusSuccessFinishResult);
264
} else {
265
result.AppendError("no platform is currently selected\n");
266
}
267
}
268
};
269
270
// "platform connect <connect-url>"
271
class CommandObjectPlatformConnect : public CommandObjectParsed {
272
public:
273
CommandObjectPlatformConnect(CommandInterpreter &interpreter)
274
: CommandObjectParsed(
275
interpreter, "platform connect",
276
"Select the current platform by providing a connection URL.",
277
"platform connect <connect-url>", 0) {
278
AddSimpleArgumentList(eArgTypeConnectURL);
279
}
280
281
~CommandObjectPlatformConnect() override = default;
282
283
protected:
284
void DoExecute(Args &args, CommandReturnObject &result) override {
285
Stream &ostrm = result.GetOutputStream();
286
287
PlatformSP platform_sp(
288
GetDebugger().GetPlatformList().GetSelectedPlatform());
289
if (platform_sp) {
290
Status error(platform_sp->ConnectRemote(args));
291
if (error.Success()) {
292
platform_sp->GetStatus(ostrm);
293
result.SetStatus(eReturnStatusSuccessFinishResult);
294
295
platform_sp->ConnectToWaitingProcesses(GetDebugger(), error);
296
if (error.Fail()) {
297
result.AppendError(error.AsCString());
298
}
299
} else {
300
result.AppendErrorWithFormat("%s\n", error.AsCString());
301
}
302
} else {
303
result.AppendError("no platform is currently selected\n");
304
}
305
}
306
307
Options *GetOptions() override {
308
PlatformSP platform_sp(
309
GetDebugger().GetPlatformList().GetSelectedPlatform());
310
OptionGroupOptions *m_platform_options = nullptr;
311
if (platform_sp) {
312
m_platform_options = platform_sp->GetConnectionOptions(m_interpreter);
313
if (m_platform_options != nullptr && !m_platform_options->m_did_finalize)
314
m_platform_options->Finalize();
315
}
316
return m_platform_options;
317
}
318
};
319
320
// "platform disconnect"
321
class CommandObjectPlatformDisconnect : public CommandObjectParsed {
322
public:
323
CommandObjectPlatformDisconnect(CommandInterpreter &interpreter)
324
: CommandObjectParsed(interpreter, "platform disconnect",
325
"Disconnect from the current platform.",
326
"platform disconnect", 0) {}
327
328
~CommandObjectPlatformDisconnect() override = default;
329
330
protected:
331
void DoExecute(Args &args, CommandReturnObject &result) override {
332
PlatformSP platform_sp(
333
GetDebugger().GetPlatformList().GetSelectedPlatform());
334
if (platform_sp) {
335
if (args.GetArgumentCount() == 0) {
336
Status error;
337
338
if (platform_sp->IsConnected()) {
339
// Cache the instance name if there is one since we are about to
340
// disconnect and the name might go with it.
341
const char *hostname_cstr = platform_sp->GetHostname();
342
std::string hostname;
343
if (hostname_cstr)
344
hostname.assign(hostname_cstr);
345
346
error = platform_sp->DisconnectRemote();
347
if (error.Success()) {
348
Stream &ostrm = result.GetOutputStream();
349
if (hostname.empty())
350
ostrm.Format("Disconnected from \"{0}\"\n",
351
platform_sp->GetPluginName());
352
else
353
ostrm.Printf("Disconnected from \"%s\"\n", hostname.c_str());
354
result.SetStatus(eReturnStatusSuccessFinishResult);
355
} else {
356
result.AppendErrorWithFormat("%s", error.AsCString());
357
}
358
} else {
359
// Not connected...
360
result.AppendErrorWithFormatv("not connected to '{0}'",
361
platform_sp->GetPluginName());
362
}
363
} else {
364
// Bad args
365
result.AppendError(
366
"\"platform disconnect\" doesn't take any arguments");
367
}
368
} else {
369
result.AppendError("no platform is currently selected");
370
}
371
}
372
};
373
374
// "platform settings"
375
class CommandObjectPlatformSettings : public CommandObjectParsed {
376
public:
377
CommandObjectPlatformSettings(CommandInterpreter &interpreter)
378
: CommandObjectParsed(interpreter, "platform settings",
379
"Set settings for the current target's platform.",
380
"platform settings", 0),
381
m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w',
382
lldb::eRemoteDiskDirectoryCompletion, eArgTypePath,
383
"The working directory for the platform.") {
384
m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
385
}
386
387
~CommandObjectPlatformSettings() override = default;
388
389
protected:
390
void DoExecute(Args &args, CommandReturnObject &result) override {
391
PlatformSP platform_sp(
392
GetDebugger().GetPlatformList().GetSelectedPlatform());
393
if (platform_sp) {
394
if (m_option_working_dir.GetOptionValue().OptionWasSet())
395
platform_sp->SetWorkingDirectory(
396
m_option_working_dir.GetOptionValue().GetCurrentValue());
397
} else {
398
result.AppendError("no platform is currently selected");
399
}
400
}
401
402
Options *GetOptions() override {
403
if (!m_options.DidFinalize())
404
m_options.Finalize();
405
return &m_options;
406
}
407
408
OptionGroupOptions m_options;
409
OptionGroupFile m_option_working_dir;
410
};
411
412
// "platform mkdir"
413
class CommandObjectPlatformMkDir : public CommandObjectParsed {
414
public:
415
CommandObjectPlatformMkDir(CommandInterpreter &interpreter)
416
: CommandObjectParsed(interpreter, "platform mkdir",
417
"Make a new directory on the remote end.", nullptr,
418
0) {
419
AddSimpleArgumentList(eArgTypeRemotePath);
420
}
421
422
~CommandObjectPlatformMkDir() override = default;
423
424
void DoExecute(Args &args, CommandReturnObject &result) override {
425
PlatformSP platform_sp(
426
GetDebugger().GetPlatformList().GetSelectedPlatform());
427
if (platform_sp) {
428
std::string cmd_line;
429
args.GetCommandString(cmd_line);
430
uint32_t mode;
431
const OptionPermissions *options_permissions =
432
(const OptionPermissions *)m_options.GetGroupWithOption('r');
433
if (options_permissions)
434
mode = options_permissions->m_permissions;
435
else
436
mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX |
437
lldb::eFilePermissionsWorldRX;
438
Status error = platform_sp->MakeDirectory(FileSpec(cmd_line), mode);
439
if (error.Success()) {
440
result.SetStatus(eReturnStatusSuccessFinishResult);
441
} else {
442
result.AppendError(error.AsCString());
443
}
444
} else {
445
result.AppendError("no platform currently selected\n");
446
}
447
}
448
449
Options *GetOptions() override {
450
if (!m_options.DidFinalize()) {
451
m_options.Append(&m_option_permissions);
452
m_options.Finalize();
453
}
454
return &m_options;
455
}
456
457
OptionPermissions m_option_permissions;
458
OptionGroupOptions m_options;
459
};
460
461
// "platform fopen"
462
class CommandObjectPlatformFOpen : public CommandObjectParsed {
463
public:
464
CommandObjectPlatformFOpen(CommandInterpreter &interpreter)
465
: CommandObjectParsed(interpreter, "platform file open",
466
"Open a file on the remote end.", nullptr, 0) {
467
AddSimpleArgumentList(eArgTypeRemotePath);
468
}
469
470
~CommandObjectPlatformFOpen() override = default;
471
472
void DoExecute(Args &args, CommandReturnObject &result) override {
473
PlatformSP platform_sp(
474
GetDebugger().GetPlatformList().GetSelectedPlatform());
475
if (platform_sp) {
476
Status error;
477
std::string cmd_line;
478
args.GetCommandString(cmd_line);
479
mode_t perms;
480
const OptionPermissions *options_permissions =
481
(const OptionPermissions *)m_options.GetGroupWithOption('r');
482
if (options_permissions)
483
perms = options_permissions->m_permissions;
484
else
485
perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW |
486
lldb::eFilePermissionsWorldRead;
487
lldb::user_id_t fd = platform_sp->OpenFile(
488
FileSpec(cmd_line),
489
File::eOpenOptionReadWrite | File::eOpenOptionCanCreate,
490
perms, error);
491
if (error.Success()) {
492
result.AppendMessageWithFormat("File Descriptor = %" PRIu64 "\n", fd);
493
result.SetStatus(eReturnStatusSuccessFinishResult);
494
} else {
495
result.AppendError(error.AsCString());
496
}
497
} else {
498
result.AppendError("no platform currently selected\n");
499
}
500
}
501
502
Options *GetOptions() override {
503
if (!m_options.DidFinalize()) {
504
m_options.Append(&m_option_permissions);
505
m_options.Finalize();
506
}
507
return &m_options;
508
}
509
510
OptionPermissions m_option_permissions;
511
OptionGroupOptions m_options;
512
};
513
514
// "platform fclose"
515
class CommandObjectPlatformFClose : public CommandObjectParsed {
516
public:
517
CommandObjectPlatformFClose(CommandInterpreter &interpreter)
518
: CommandObjectParsed(interpreter, "platform file close",
519
"Close a file on the remote end.", nullptr, 0) {
520
AddSimpleArgumentList(eArgTypeUnsignedInteger);
521
}
522
523
~CommandObjectPlatformFClose() override = default;
524
525
void DoExecute(Args &args, CommandReturnObject &result) override {
526
PlatformSP platform_sp(
527
GetDebugger().GetPlatformList().GetSelectedPlatform());
528
if (platform_sp) {
529
std::string cmd_line;
530
args.GetCommandString(cmd_line);
531
lldb::user_id_t fd;
532
if (!llvm::to_integer(cmd_line, fd)) {
533
result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
534
cmd_line);
535
return;
536
}
537
Status error;
538
bool success = platform_sp->CloseFile(fd, error);
539
if (success) {
540
result.AppendMessageWithFormat("file %" PRIu64 " closed.\n", fd);
541
result.SetStatus(eReturnStatusSuccessFinishResult);
542
} else {
543
result.AppendError(error.AsCString());
544
}
545
} else {
546
result.AppendError("no platform currently selected\n");
547
}
548
}
549
};
550
551
// "platform fread"
552
553
#define LLDB_OPTIONS_platform_fread
554
#include "CommandOptions.inc"
555
556
class CommandObjectPlatformFRead : public CommandObjectParsed {
557
public:
558
CommandObjectPlatformFRead(CommandInterpreter &interpreter)
559
: CommandObjectParsed(interpreter, "platform file read",
560
"Read data from a file on the remote end.", nullptr,
561
0) {
562
AddSimpleArgumentList(eArgTypeUnsignedInteger);
563
}
564
565
~CommandObjectPlatformFRead() override = default;
566
567
void DoExecute(Args &args, CommandReturnObject &result) override {
568
PlatformSP platform_sp(
569
GetDebugger().GetPlatformList().GetSelectedPlatform());
570
if (platform_sp) {
571
std::string cmd_line;
572
args.GetCommandString(cmd_line);
573
lldb::user_id_t fd;
574
if (!llvm::to_integer(cmd_line, fd)) {
575
result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n",
576
cmd_line);
577
return;
578
}
579
std::string buffer(m_options.m_count, 0);
580
Status error;
581
uint64_t retcode = platform_sp->ReadFile(
582
fd, m_options.m_offset, &buffer[0], m_options.m_count, error);
583
if (retcode != UINT64_MAX) {
584
result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
585
result.AppendMessageWithFormat("Data = \"%s\"\n", buffer.c_str());
586
result.SetStatus(eReturnStatusSuccessFinishResult);
587
} else {
588
result.AppendError(error.AsCString());
589
}
590
} else {
591
result.AppendError("no platform currently selected\n");
592
}
593
}
594
595
Options *GetOptions() override { return &m_options; }
596
597
protected:
598
class CommandOptions : public Options {
599
public:
600
CommandOptions() = default;
601
602
~CommandOptions() override = default;
603
604
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
605
ExecutionContext *execution_context) override {
606
Status error;
607
char short_option = (char)m_getopt_table[option_idx].val;
608
609
switch (short_option) {
610
case 'o':
611
if (option_arg.getAsInteger(0, m_offset))
612
error.SetErrorStringWithFormat("invalid offset: '%s'",
613
option_arg.str().c_str());
614
break;
615
case 'c':
616
if (option_arg.getAsInteger(0, m_count))
617
error.SetErrorStringWithFormat("invalid offset: '%s'",
618
option_arg.str().c_str());
619
break;
620
default:
621
llvm_unreachable("Unimplemented option");
622
}
623
624
return error;
625
}
626
627
void OptionParsingStarting(ExecutionContext *execution_context) override {
628
m_offset = 0;
629
m_count = 1;
630
}
631
632
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
633
return llvm::ArrayRef(g_platform_fread_options);
634
}
635
636
// Instance variables to hold the values for command options.
637
638
uint32_t m_offset;
639
uint32_t m_count;
640
};
641
642
CommandOptions m_options;
643
};
644
645
// "platform fwrite"
646
647
#define LLDB_OPTIONS_platform_fwrite
648
#include "CommandOptions.inc"
649
650
class CommandObjectPlatformFWrite : public CommandObjectParsed {
651
public:
652
CommandObjectPlatformFWrite(CommandInterpreter &interpreter)
653
: CommandObjectParsed(interpreter, "platform file write",
654
"Write data to a file on the remote end.", nullptr,
655
0) {
656
AddSimpleArgumentList(eArgTypeUnsignedInteger);
657
}
658
659
~CommandObjectPlatformFWrite() override = default;
660
661
void DoExecute(Args &args, CommandReturnObject &result) override {
662
PlatformSP platform_sp(
663
GetDebugger().GetPlatformList().GetSelectedPlatform());
664
if (platform_sp) {
665
std::string cmd_line;
666
args.GetCommandString(cmd_line);
667
Status error;
668
lldb::user_id_t fd;
669
if (!llvm::to_integer(cmd_line, fd)) {
670
result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.",
671
cmd_line);
672
return;
673
}
674
uint64_t retcode =
675
platform_sp->WriteFile(fd, m_options.m_offset, &m_options.m_data[0],
676
m_options.m_data.size(), error);
677
if (retcode != UINT64_MAX) {
678
result.AppendMessageWithFormat("Return = %" PRIu64 "\n", retcode);
679
result.SetStatus(eReturnStatusSuccessFinishResult);
680
} else {
681
result.AppendError(error.AsCString());
682
}
683
} else {
684
result.AppendError("no platform currently selected\n");
685
}
686
}
687
688
Options *GetOptions() override { return &m_options; }
689
690
protected:
691
class CommandOptions : public Options {
692
public:
693
CommandOptions() = default;
694
695
~CommandOptions() override = default;
696
697
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
698
ExecutionContext *execution_context) override {
699
Status error;
700
char short_option = (char)m_getopt_table[option_idx].val;
701
702
switch (short_option) {
703
case 'o':
704
if (option_arg.getAsInteger(0, m_offset))
705
error.SetErrorStringWithFormat("invalid offset: '%s'",
706
option_arg.str().c_str());
707
break;
708
case 'd':
709
m_data.assign(std::string(option_arg));
710
break;
711
default:
712
llvm_unreachable("Unimplemented option");
713
}
714
715
return error;
716
}
717
718
void OptionParsingStarting(ExecutionContext *execution_context) override {
719
m_offset = 0;
720
m_data.clear();
721
}
722
723
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
724
return llvm::ArrayRef(g_platform_fwrite_options);
725
}
726
727
// Instance variables to hold the values for command options.
728
729
uint32_t m_offset;
730
std::string m_data;
731
};
732
733
CommandOptions m_options;
734
};
735
736
class CommandObjectPlatformFile : public CommandObjectMultiword {
737
public:
738
// Constructors and Destructors
739
CommandObjectPlatformFile(CommandInterpreter &interpreter)
740
: CommandObjectMultiword(
741
interpreter, "platform file",
742
"Commands to access files on the current platform.",
743
"platform file [open|close|read|write] ...") {
744
LoadSubCommand(
745
"open", CommandObjectSP(new CommandObjectPlatformFOpen(interpreter)));
746
LoadSubCommand(
747
"close", CommandObjectSP(new CommandObjectPlatformFClose(interpreter)));
748
LoadSubCommand(
749
"read", CommandObjectSP(new CommandObjectPlatformFRead(interpreter)));
750
LoadSubCommand(
751
"write", CommandObjectSP(new CommandObjectPlatformFWrite(interpreter)));
752
}
753
754
~CommandObjectPlatformFile() override = default;
755
756
private:
757
// For CommandObjectPlatform only
758
CommandObjectPlatformFile(const CommandObjectPlatformFile &) = delete;
759
const CommandObjectPlatformFile &
760
operator=(const CommandObjectPlatformFile &) = delete;
761
};
762
763
// "platform get-file remote-file-path host-file-path"
764
class CommandObjectPlatformGetFile : public CommandObjectParsed {
765
public:
766
CommandObjectPlatformGetFile(CommandInterpreter &interpreter)
767
: CommandObjectParsed(
768
interpreter, "platform get-file",
769
"Transfer a file from the remote end to the local host.",
770
"platform get-file <remote-file-spec> <local-file-spec>", 0) {
771
SetHelpLong(
772
R"(Examples:
773
774
(lldb) platform get-file /the/remote/file/path /the/local/file/path
775
776
Transfer a file from the remote end with file path /the/remote/file/path to the local host.)");
777
778
CommandArgumentEntry arg1, arg2;
779
CommandArgumentData file_arg_remote, file_arg_host;
780
781
// Define the first (and only) variant of this arg.
782
file_arg_remote.arg_type = eArgTypeRemoteFilename;
783
file_arg_remote.arg_repetition = eArgRepeatPlain;
784
// There is only one variant this argument could be; put it into the
785
// argument entry.
786
arg1.push_back(file_arg_remote);
787
788
// Define the second (and only) variant of this arg.
789
file_arg_host.arg_type = eArgTypeFilename;
790
file_arg_host.arg_repetition = eArgRepeatPlain;
791
// There is only one variant this argument could be; put it into the
792
// argument entry.
793
arg2.push_back(file_arg_host);
794
795
// Push the data for the first and the second arguments into the
796
// m_arguments vector.
797
m_arguments.push_back(arg1);
798
m_arguments.push_back(arg2);
799
}
800
801
~CommandObjectPlatformGetFile() override = default;
802
803
void
804
HandleArgumentCompletion(CompletionRequest &request,
805
OptionElementVector &opt_element_vector) override {
806
if (request.GetCursorIndex() == 0)
807
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
808
GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,
809
nullptr);
810
else if (request.GetCursorIndex() == 1)
811
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
812
GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
813
}
814
815
void DoExecute(Args &args, CommandReturnObject &result) override {
816
// If the number of arguments is incorrect, issue an error message.
817
if (args.GetArgumentCount() != 2) {
818
result.AppendError("required arguments missing; specify both the "
819
"source and destination file paths");
820
return;
821
}
822
823
PlatformSP platform_sp(
824
GetDebugger().GetPlatformList().GetSelectedPlatform());
825
if (platform_sp) {
826
const char *remote_file_path = args.GetArgumentAtIndex(0);
827
const char *local_file_path = args.GetArgumentAtIndex(1);
828
Status error = platform_sp->GetFile(FileSpec(remote_file_path),
829
FileSpec(local_file_path));
830
if (error.Success()) {
831
result.AppendMessageWithFormat(
832
"successfully get-file from %s (remote) to %s (host)\n",
833
remote_file_path, local_file_path);
834
result.SetStatus(eReturnStatusSuccessFinishResult);
835
} else {
836
result.AppendMessageWithFormat("get-file failed: %s\n",
837
error.AsCString());
838
}
839
} else {
840
result.AppendError("no platform currently selected\n");
841
}
842
}
843
};
844
845
// "platform get-size remote-file-path"
846
class CommandObjectPlatformGetSize : public CommandObjectParsed {
847
public:
848
CommandObjectPlatformGetSize(CommandInterpreter &interpreter)
849
: CommandObjectParsed(interpreter, "platform get-size",
850
"Get the file size from the remote end.",
851
"platform get-size <remote-file-spec>", 0) {
852
SetHelpLong(
853
R"(Examples:
854
855
(lldb) platform get-size /the/remote/file/path
856
857
Get the file size from the remote end with path /the/remote/file/path.)");
858
859
AddSimpleArgumentList(eArgTypeRemoteFilename);
860
}
861
862
~CommandObjectPlatformGetSize() override = default;
863
864
void DoExecute(Args &args, CommandReturnObject &result) override {
865
// If the number of arguments is incorrect, issue an error message.
866
if (args.GetArgumentCount() != 1) {
867
result.AppendError("required argument missing; specify the source file "
868
"path as the only argument");
869
return;
870
}
871
872
PlatformSP platform_sp(
873
GetDebugger().GetPlatformList().GetSelectedPlatform());
874
if (platform_sp) {
875
std::string remote_file_path(args.GetArgumentAtIndex(0));
876
user_id_t size = platform_sp->GetFileSize(FileSpec(remote_file_path));
877
if (size != UINT64_MAX) {
878
result.AppendMessageWithFormat("File size of %s (remote): %" PRIu64
879
"\n",
880
remote_file_path.c_str(), size);
881
result.SetStatus(eReturnStatusSuccessFinishResult);
882
} else {
883
result.AppendMessageWithFormat(
884
"Error getting file size of %s (remote)\n",
885
remote_file_path.c_str());
886
}
887
} else {
888
result.AppendError("no platform currently selected\n");
889
}
890
}
891
};
892
893
// "platform get-permissions remote-file-path"
894
class CommandObjectPlatformGetPermissions : public CommandObjectParsed {
895
public:
896
CommandObjectPlatformGetPermissions(CommandInterpreter &interpreter)
897
: CommandObjectParsed(interpreter, "platform get-permissions",
898
"Get the file permission bits from the remote end.",
899
"platform get-permissions <remote-file-spec>", 0) {
900
SetHelpLong(
901
R"(Examples:
902
903
(lldb) platform get-permissions /the/remote/file/path
904
905
Get the file permissions from the remote end with path /the/remote/file/path.)");
906
907
AddSimpleArgumentList(eArgTypeRemoteFilename);
908
}
909
910
~CommandObjectPlatformGetPermissions() override = default;
911
912
void DoExecute(Args &args, CommandReturnObject &result) override {
913
// If the number of arguments is incorrect, issue an error message.
914
if (args.GetArgumentCount() != 1) {
915
result.AppendError("required argument missing; specify the source file "
916
"path as the only argument");
917
return;
918
}
919
920
PlatformSP platform_sp(
921
GetDebugger().GetPlatformList().GetSelectedPlatform());
922
if (platform_sp) {
923
std::string remote_file_path(args.GetArgumentAtIndex(0));
924
uint32_t permissions;
925
Status error = platform_sp->GetFilePermissions(FileSpec(remote_file_path),
926
permissions);
927
if (error.Success()) {
928
result.AppendMessageWithFormat(
929
"File permissions of %s (remote): 0o%04" PRIo32 "\n",
930
remote_file_path.c_str(), permissions);
931
result.SetStatus(eReturnStatusSuccessFinishResult);
932
} else
933
result.AppendError(error.AsCString());
934
} else {
935
result.AppendError("no platform currently selected\n");
936
}
937
}
938
};
939
940
// "platform file-exists remote-file-path"
941
class CommandObjectPlatformFileExists : public CommandObjectParsed {
942
public:
943
CommandObjectPlatformFileExists(CommandInterpreter &interpreter)
944
: CommandObjectParsed(interpreter, "platform file-exists",
945
"Check if the file exists on the remote end.",
946
"platform file-exists <remote-file-spec>", 0) {
947
SetHelpLong(
948
R"(Examples:
949
950
(lldb) platform file-exists /the/remote/file/path
951
952
Check if /the/remote/file/path exists on the remote end.)");
953
954
AddSimpleArgumentList(eArgTypeRemoteFilename);
955
}
956
957
~CommandObjectPlatformFileExists() override = default;
958
959
void DoExecute(Args &args, CommandReturnObject &result) override {
960
// If the number of arguments is incorrect, issue an error message.
961
if (args.GetArgumentCount() != 1) {
962
result.AppendError("required argument missing; specify the source file "
963
"path as the only argument");
964
return;
965
}
966
967
PlatformSP platform_sp(
968
GetDebugger().GetPlatformList().GetSelectedPlatform());
969
if (platform_sp) {
970
std::string remote_file_path(args.GetArgumentAtIndex(0));
971
bool exists = platform_sp->GetFileExists(FileSpec(remote_file_path));
972
result.AppendMessageWithFormat(
973
"File %s (remote) %s\n",
974
remote_file_path.c_str(), exists ? "exists" : "does not exist");
975
result.SetStatus(eReturnStatusSuccessFinishResult);
976
} else {
977
result.AppendError("no platform currently selected\n");
978
}
979
}
980
};
981
982
// "platform put-file"
983
class CommandObjectPlatformPutFile : public CommandObjectParsed {
984
public:
985
CommandObjectPlatformPutFile(CommandInterpreter &interpreter)
986
: CommandObjectParsed(
987
interpreter, "platform put-file",
988
"Transfer a file from this system to the remote end.",
989
"platform put-file <source> [<destination>]", 0) {
990
SetHelpLong(
991
R"(Examples:
992
993
(lldb) platform put-file /source/foo.txt /destination/bar.txt
994
995
(lldb) platform put-file /source/foo.txt
996
997
Relative source file paths are resolved against lldb's local working directory.
998
999
Omitting the destination places the file in the platform working directory.)");
1000
CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain};
1001
CommandArgumentData path_arg{eArgTypeRemotePath, eArgRepeatOptional};
1002
m_arguments.push_back({source_arg});
1003
m_arguments.push_back({path_arg});
1004
}
1005
1006
~CommandObjectPlatformPutFile() override = default;
1007
1008
void
1009
HandleArgumentCompletion(CompletionRequest &request,
1010
OptionElementVector &opt_element_vector) override {
1011
if (request.GetCursorIndex() == 0)
1012
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1013
GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
1014
else if (request.GetCursorIndex() == 1)
1015
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1016
GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,
1017
nullptr);
1018
}
1019
1020
void DoExecute(Args &args, CommandReturnObject &result) override {
1021
const char *src = args.GetArgumentAtIndex(0);
1022
const char *dst = args.GetArgumentAtIndex(1);
1023
1024
FileSpec src_fs(src);
1025
FileSystem::Instance().Resolve(src_fs);
1026
FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString());
1027
1028
PlatformSP platform_sp(
1029
GetDebugger().GetPlatformList().GetSelectedPlatform());
1030
if (platform_sp) {
1031
Status error(platform_sp->PutFile(src_fs, dst_fs));
1032
if (error.Success()) {
1033
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1034
} else {
1035
result.AppendError(error.AsCString());
1036
}
1037
} else {
1038
result.AppendError("no platform currently selected\n");
1039
}
1040
}
1041
};
1042
1043
// "platform process launch"
1044
class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
1045
public:
1046
CommandObjectPlatformProcessLaunch(CommandInterpreter &interpreter)
1047
: CommandObjectParsed(interpreter, "platform process launch",
1048
"Launch a new process on a remote platform.",
1049
"platform process launch program",
1050
eCommandRequiresTarget | eCommandTryTargetAPILock),
1051
m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1052
m_all_options.Append(&m_options);
1053
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
1054
LLDB_OPT_SET_ALL);
1055
m_all_options.Finalize();
1056
AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatStar);
1057
}
1058
1059
void
1060
HandleArgumentCompletion(CompletionRequest &request,
1061
OptionElementVector &opt_element_vector) override {
1062
// I didn't make a type for RemoteRunArgs, but since we're going to run
1063
// this on the remote system we should use the remote completer.
1064
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1065
GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request,
1066
nullptr);
1067
}
1068
1069
~CommandObjectPlatformProcessLaunch() override = default;
1070
1071
Options *GetOptions() override { return &m_all_options; }
1072
1073
protected:
1074
void DoExecute(Args &args, CommandReturnObject &result) override {
1075
Target *target = GetDebugger().GetSelectedTarget().get();
1076
PlatformSP platform_sp;
1077
if (target) {
1078
platform_sp = target->GetPlatform();
1079
}
1080
if (!platform_sp) {
1081
platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1082
}
1083
1084
if (platform_sp) {
1085
Status error;
1086
const size_t argc = args.GetArgumentCount();
1087
Target *target = m_exe_ctx.GetTargetPtr();
1088
Module *exe_module = target->GetExecutableModulePointer();
1089
if (exe_module) {
1090
m_options.launch_info.GetExecutableFile() = exe_module->GetFileSpec();
1091
llvm::SmallString<128> exe_path;
1092
m_options.launch_info.GetExecutableFile().GetPath(exe_path);
1093
if (!exe_path.empty())
1094
m_options.launch_info.GetArguments().AppendArgument(exe_path);
1095
m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
1096
}
1097
1098
if (!m_class_options.GetName().empty()) {
1099
m_options.launch_info.SetProcessPluginName("ScriptedProcess");
1100
ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
1101
m_class_options.GetName(), m_class_options.GetStructuredData());
1102
m_options.launch_info.SetScriptedMetadata(metadata_sp);
1103
target->SetProcessLaunchInfo(m_options.launch_info);
1104
}
1105
1106
if (argc > 0) {
1107
if (m_options.launch_info.GetExecutableFile()) {
1108
// We already have an executable file, so we will use this and all
1109
// arguments to this function are extra arguments
1110
m_options.launch_info.GetArguments().AppendArguments(args);
1111
} else {
1112
// We don't have any file yet, so the first argument is our
1113
// executable, and the rest are program arguments
1114
const bool first_arg_is_executable = true;
1115
m_options.launch_info.SetArguments(args, first_arg_is_executable);
1116
}
1117
}
1118
1119
if (m_options.launch_info.GetExecutableFile()) {
1120
Debugger &debugger = GetDebugger();
1121
1122
if (argc == 0) {
1123
// If no arguments were given to the command, use target.run-args.
1124
Args target_run_args;
1125
target->GetRunArguments(target_run_args);
1126
m_options.launch_info.GetArguments().AppendArguments(target_run_args);
1127
}
1128
1129
ProcessSP process_sp(platform_sp->DebugProcess(
1130
m_options.launch_info, debugger, *target, error));
1131
1132
if (!process_sp && error.Success()) {
1133
result.AppendError("failed to launch or debug process");
1134
return;
1135
} else if (!error.Success()) {
1136
result.AppendError(error.AsCString());
1137
return;
1138
}
1139
1140
const bool synchronous_execution =
1141
debugger.GetCommandInterpreter().GetSynchronous();
1142
auto launch_info = m_options.launch_info;
1143
bool rebroadcast_first_stop =
1144
!synchronous_execution &&
1145
launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
1146
1147
EventSP first_stop_event_sp;
1148
StateType state = process_sp->WaitForProcessToStop(
1149
std::nullopt, &first_stop_event_sp, rebroadcast_first_stop,
1150
launch_info.GetHijackListener());
1151
process_sp->RestoreProcessEvents();
1152
1153
if (rebroadcast_first_stop) {
1154
assert(first_stop_event_sp);
1155
process_sp->BroadcastEvent(first_stop_event_sp);
1156
return;
1157
}
1158
1159
switch (state) {
1160
case eStateStopped: {
1161
if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
1162
break;
1163
if (synchronous_execution) {
1164
// Now we have handled the stop-from-attach, and we are just
1165
// switching to a synchronous resume. So we should switch to the
1166
// SyncResume hijacker.
1167
process_sp->ResumeSynchronous(&result.GetOutputStream());
1168
} else {
1169
error = process_sp->Resume();
1170
if (!error.Success()) {
1171
result.AppendErrorWithFormat(
1172
"process resume at entry point failed: %s",
1173
error.AsCString());
1174
}
1175
}
1176
} break;
1177
default:
1178
result.AppendErrorWithFormat(
1179
"initial process state wasn't stopped: %s",
1180
StateAsCString(state));
1181
break;
1182
}
1183
1184
if (process_sp && process_sp->IsAlive()) {
1185
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1186
return;
1187
}
1188
} else {
1189
result.AppendError("'platform process launch' uses the current target "
1190
"file and arguments, or the executable and its "
1191
"arguments can be specified in this command");
1192
return;
1193
}
1194
} else {
1195
result.AppendError("no platform is selected\n");
1196
}
1197
}
1198
1199
CommandOptionsProcessLaunch m_options;
1200
OptionGroupPythonClassWithDict m_class_options;
1201
OptionGroupOptions m_all_options;
1202
};
1203
1204
// "platform process list"
1205
1206
static PosixPlatformCommandOptionValidator posix_validator;
1207
#define LLDB_OPTIONS_platform_process_list
1208
#include "CommandOptions.inc"
1209
1210
class CommandObjectPlatformProcessList : public CommandObjectParsed {
1211
public:
1212
CommandObjectPlatformProcessList(CommandInterpreter &interpreter)
1213
: CommandObjectParsed(interpreter, "platform process list",
1214
"List processes on a remote platform by name, pid, "
1215
"or many other matching attributes.",
1216
"platform process list", 0) {}
1217
1218
~CommandObjectPlatformProcessList() override = default;
1219
1220
Options *GetOptions() override { return &m_options; }
1221
1222
protected:
1223
void DoExecute(Args &args, CommandReturnObject &result) override {
1224
Target *target = GetDebugger().GetSelectedTarget().get();
1225
PlatformSP platform_sp;
1226
if (target) {
1227
platform_sp = target->GetPlatform();
1228
}
1229
if (!platform_sp) {
1230
platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1231
}
1232
1233
if (platform_sp) {
1234
Status error;
1235
if (platform_sp) {
1236
Stream &ostrm = result.GetOutputStream();
1237
1238
lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
1239
if (pid != LLDB_INVALID_PROCESS_ID) {
1240
ProcessInstanceInfo proc_info;
1241
if (platform_sp->GetProcessInfo(pid, proc_info)) {
1242
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1243
m_options.verbose);
1244
proc_info.DumpAsTableRow(ostrm, platform_sp->GetUserIDResolver(),
1245
m_options.show_args, m_options.verbose);
1246
result.SetStatus(eReturnStatusSuccessFinishResult);
1247
} else {
1248
result.AppendErrorWithFormat(
1249
"no process found with pid = %" PRIu64 "\n", pid);
1250
}
1251
} else {
1252
ProcessInstanceInfoList proc_infos;
1253
const uint32_t matches =
1254
platform_sp->FindProcesses(m_options.match_info, proc_infos);
1255
const char *match_desc = nullptr;
1256
const char *match_name =
1257
m_options.match_info.GetProcessInfo().GetName();
1258
if (match_name && match_name[0]) {
1259
switch (m_options.match_info.GetNameMatchType()) {
1260
case NameMatch::Ignore:
1261
break;
1262
case NameMatch::Equals:
1263
match_desc = "matched";
1264
break;
1265
case NameMatch::Contains:
1266
match_desc = "contained";
1267
break;
1268
case NameMatch::StartsWith:
1269
match_desc = "started with";
1270
break;
1271
case NameMatch::EndsWith:
1272
match_desc = "ended with";
1273
break;
1274
case NameMatch::RegularExpression:
1275
match_desc = "matched the regular expression";
1276
break;
1277
}
1278
}
1279
1280
if (matches == 0) {
1281
if (match_desc)
1282
result.AppendErrorWithFormatv(
1283
"no processes were found that {0} \"{1}\" on the \"{2}\" "
1284
"platform\n",
1285
match_desc, match_name, platform_sp->GetName());
1286
else
1287
result.AppendErrorWithFormatv(
1288
"no processes were found on the \"{0}\" platform\n",
1289
platform_sp->GetName());
1290
} else {
1291
result.AppendMessageWithFormatv(
1292
"{0} matching process{1} found on \"{2}\"", matches,
1293
matches > 1 ? "es were" : " was", platform_sp->GetName());
1294
if (match_desc)
1295
result.AppendMessageWithFormat(" whose name %s \"%s\"",
1296
match_desc, match_name);
1297
result.AppendMessageWithFormat("\n");
1298
ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args,
1299
m_options.verbose);
1300
for (uint32_t i = 0; i < matches; ++i) {
1301
proc_infos[i].DumpAsTableRow(
1302
ostrm, platform_sp->GetUserIDResolver(), m_options.show_args,
1303
m_options.verbose);
1304
}
1305
}
1306
}
1307
}
1308
} else {
1309
result.AppendError("no platform is selected\n");
1310
}
1311
}
1312
1313
class CommandOptions : public Options {
1314
public:
1315
CommandOptions() = default;
1316
1317
~CommandOptions() override = default;
1318
1319
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1320
ExecutionContext *execution_context) override {
1321
Status error;
1322
const int short_option = m_getopt_table[option_idx].val;
1323
bool success = false;
1324
1325
uint32_t id = LLDB_INVALID_PROCESS_ID;
1326
success = !option_arg.getAsInteger(0, id);
1327
switch (short_option) {
1328
case 'p': {
1329
match_info.GetProcessInfo().SetProcessID(id);
1330
if (!success)
1331
error.SetErrorStringWithFormat("invalid process ID string: '%s'",
1332
option_arg.str().c_str());
1333
break;
1334
}
1335
case 'P':
1336
match_info.GetProcessInfo().SetParentProcessID(id);
1337
if (!success)
1338
error.SetErrorStringWithFormat(
1339
"invalid parent process ID string: '%s'",
1340
option_arg.str().c_str());
1341
break;
1342
1343
case 'u':
1344
match_info.GetProcessInfo().SetUserID(success ? id : UINT32_MAX);
1345
if (!success)
1346
error.SetErrorStringWithFormat("invalid user ID string: '%s'",
1347
option_arg.str().c_str());
1348
break;
1349
1350
case 'U':
1351
match_info.GetProcessInfo().SetEffectiveUserID(success ? id
1352
: UINT32_MAX);
1353
if (!success)
1354
error.SetErrorStringWithFormat(
1355
"invalid effective user ID string: '%s'",
1356
option_arg.str().c_str());
1357
break;
1358
1359
case 'g':
1360
match_info.GetProcessInfo().SetGroupID(success ? id : UINT32_MAX);
1361
if (!success)
1362
error.SetErrorStringWithFormat("invalid group ID string: '%s'",
1363
option_arg.str().c_str());
1364
break;
1365
1366
case 'G':
1367
match_info.GetProcessInfo().SetEffectiveGroupID(success ? id
1368
: UINT32_MAX);
1369
if (!success)
1370
error.SetErrorStringWithFormat(
1371
"invalid effective group ID string: '%s'",
1372
option_arg.str().c_str());
1373
break;
1374
1375
case 'a': {
1376
TargetSP target_sp =
1377
execution_context ? execution_context->GetTargetSP() : TargetSP();
1378
DebuggerSP debugger_sp =
1379
target_sp ? target_sp->GetDebugger().shared_from_this()
1380
: DebuggerSP();
1381
PlatformSP platform_sp =
1382
debugger_sp ? debugger_sp->GetPlatformList().GetSelectedPlatform()
1383
: PlatformSP();
1384
match_info.GetProcessInfo().GetArchitecture() =
1385
Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg);
1386
} break;
1387
1388
case 'n':
1389
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1390
option_arg, FileSpec::Style::native);
1391
match_info.SetNameMatchType(NameMatch::Equals);
1392
break;
1393
1394
case 'e':
1395
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1396
option_arg, FileSpec::Style::native);
1397
match_info.SetNameMatchType(NameMatch::EndsWith);
1398
break;
1399
1400
case 's':
1401
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1402
option_arg, FileSpec::Style::native);
1403
match_info.SetNameMatchType(NameMatch::StartsWith);
1404
break;
1405
1406
case 'c':
1407
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1408
option_arg, FileSpec::Style::native);
1409
match_info.SetNameMatchType(NameMatch::Contains);
1410
break;
1411
1412
case 'r':
1413
match_info.GetProcessInfo().GetExecutableFile().SetFile(
1414
option_arg, FileSpec::Style::native);
1415
match_info.SetNameMatchType(NameMatch::RegularExpression);
1416
break;
1417
1418
case 'A':
1419
show_args = true;
1420
break;
1421
1422
case 'v':
1423
verbose = true;
1424
break;
1425
1426
case 'x':
1427
match_info.SetMatchAllUsers(true);
1428
break;
1429
1430
default:
1431
llvm_unreachable("Unimplemented option");
1432
}
1433
1434
return error;
1435
}
1436
1437
void OptionParsingStarting(ExecutionContext *execution_context) override {
1438
match_info.Clear();
1439
show_args = false;
1440
verbose = false;
1441
}
1442
1443
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1444
return llvm::ArrayRef(g_platform_process_list_options);
1445
}
1446
1447
// Instance variables to hold the values for command options.
1448
1449
ProcessInstanceInfoMatch match_info;
1450
bool show_args = false;
1451
bool verbose = false;
1452
};
1453
1454
CommandOptions m_options;
1455
};
1456
1457
// "platform process info"
1458
class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
1459
public:
1460
CommandObjectPlatformProcessInfo(CommandInterpreter &interpreter)
1461
: CommandObjectParsed(
1462
interpreter, "platform process info",
1463
"Get detailed information for one or more process by process ID.",
1464
"platform process info <pid> [<pid> <pid> ...]", 0) {
1465
AddSimpleArgumentList(eArgTypePid, eArgRepeatStar);
1466
}
1467
1468
~CommandObjectPlatformProcessInfo() override = default;
1469
1470
protected:
1471
void DoExecute(Args &args, CommandReturnObject &result) override {
1472
Target *target = GetDebugger().GetSelectedTarget().get();
1473
PlatformSP platform_sp;
1474
if (target) {
1475
platform_sp = target->GetPlatform();
1476
}
1477
if (!platform_sp) {
1478
platform_sp = GetDebugger().GetPlatformList().GetSelectedPlatform();
1479
}
1480
1481
if (platform_sp) {
1482
const size_t argc = args.GetArgumentCount();
1483
if (argc > 0) {
1484
Status error;
1485
1486
if (platform_sp->IsConnected()) {
1487
Stream &ostrm = result.GetOutputStream();
1488
for (auto &entry : args.entries()) {
1489
lldb::pid_t pid;
1490
if (entry.ref().getAsInteger(0, pid)) {
1491
result.AppendErrorWithFormat("invalid process ID argument '%s'",
1492
entry.ref().str().c_str());
1493
break;
1494
} else {
1495
ProcessInstanceInfo proc_info;
1496
if (platform_sp->GetProcessInfo(pid, proc_info)) {
1497
ostrm.Printf("Process information for process %" PRIu64 ":\n",
1498
pid);
1499
proc_info.Dump(ostrm, platform_sp->GetUserIDResolver());
1500
} else {
1501
ostrm.Printf("error: no process information is available for "
1502
"process %" PRIu64 "\n",
1503
pid);
1504
}
1505
ostrm.EOL();
1506
}
1507
}
1508
} else {
1509
// Not connected...
1510
result.AppendErrorWithFormatv("not connected to '{0}'",
1511
platform_sp->GetPluginName());
1512
}
1513
} else {
1514
// No args
1515
result.AppendError("one or more process id(s) must be specified");
1516
}
1517
} else {
1518
result.AppendError("no platform is currently selected");
1519
}
1520
}
1521
};
1522
1523
#define LLDB_OPTIONS_platform_process_attach
1524
#include "CommandOptions.inc"
1525
1526
class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
1527
public:
1528
CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter)
1529
: CommandObjectParsed(interpreter, "platform process attach",
1530
"Attach to a process.",
1531
"platform process attach <cmd-options>"),
1532
m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
1533
m_all_options.Append(&m_options);
1534
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
1535
LLDB_OPT_SET_ALL);
1536
m_all_options.Finalize();
1537
}
1538
1539
~CommandObjectPlatformProcessAttach() override = default;
1540
1541
void DoExecute(Args &command, CommandReturnObject &result) override {
1542
PlatformSP platform_sp(
1543
GetDebugger().GetPlatformList().GetSelectedPlatform());
1544
if (platform_sp) {
1545
1546
if (!m_class_options.GetName().empty()) {
1547
m_options.attach_info.SetProcessPluginName("ScriptedProcess");
1548
ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
1549
m_class_options.GetName(), m_class_options.GetStructuredData());
1550
m_options.attach_info.SetScriptedMetadata(metadata_sp);
1551
}
1552
1553
Status err;
1554
ProcessSP remote_process_sp = platform_sp->Attach(
1555
m_options.attach_info, GetDebugger(), nullptr, err);
1556
if (err.Fail()) {
1557
result.AppendError(err.AsCString());
1558
} else if (!remote_process_sp) {
1559
result.AppendError("could not attach: unknown reason");
1560
} else
1561
result.SetStatus(eReturnStatusSuccessFinishResult);
1562
} else {
1563
result.AppendError("no platform is currently selected");
1564
}
1565
}
1566
1567
Options *GetOptions() override { return &m_all_options; }
1568
1569
protected:
1570
CommandOptionsProcessAttach m_options;
1571
OptionGroupPythonClassWithDict m_class_options;
1572
OptionGroupOptions m_all_options;
1573
};
1574
1575
class CommandObjectPlatformProcess : public CommandObjectMultiword {
1576
public:
1577
// Constructors and Destructors
1578
CommandObjectPlatformProcess(CommandInterpreter &interpreter)
1579
: CommandObjectMultiword(interpreter, "platform process",
1580
"Commands to query, launch and attach to "
1581
"processes on the current platform.",
1582
"platform process [attach|launch|list] ...") {
1583
LoadSubCommand(
1584
"attach",
1585
CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
1586
LoadSubCommand(
1587
"launch",
1588
CommandObjectSP(new CommandObjectPlatformProcessLaunch(interpreter)));
1589
LoadSubCommand("info", CommandObjectSP(new CommandObjectPlatformProcessInfo(
1590
interpreter)));
1591
LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
1592
interpreter)));
1593
}
1594
1595
~CommandObjectPlatformProcess() override = default;
1596
1597
private:
1598
// For CommandObjectPlatform only
1599
CommandObjectPlatformProcess(const CommandObjectPlatformProcess &) = delete;
1600
const CommandObjectPlatformProcess &
1601
operator=(const CommandObjectPlatformProcess &) = delete;
1602
};
1603
1604
// "platform shell"
1605
#define LLDB_OPTIONS_platform_shell
1606
#include "CommandOptions.inc"
1607
1608
class CommandObjectPlatformShell : public CommandObjectRaw {
1609
public:
1610
class CommandOptions : public Options {
1611
public:
1612
CommandOptions() = default;
1613
1614
~CommandOptions() override = default;
1615
1616
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1617
return llvm::ArrayRef(g_platform_shell_options);
1618
}
1619
1620
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1621
ExecutionContext *execution_context) override {
1622
Status error;
1623
1624
const char short_option = (char)GetDefinitions()[option_idx].short_option;
1625
1626
switch (short_option) {
1627
case 'h':
1628
m_use_host_platform = true;
1629
break;
1630
case 't':
1631
uint32_t timeout_sec;
1632
if (option_arg.getAsInteger(10, timeout_sec))
1633
error.SetErrorStringWithFormat(
1634
"could not convert \"%s\" to a numeric value.",
1635
option_arg.str().c_str());
1636
else
1637
m_timeout = std::chrono::seconds(timeout_sec);
1638
break;
1639
case 's': {
1640
if (option_arg.empty()) {
1641
error.SetErrorStringWithFormat(
1642
"missing shell interpreter path for option -i|--interpreter.");
1643
return error;
1644
}
1645
1646
m_shell_interpreter = option_arg.str();
1647
break;
1648
}
1649
default:
1650
llvm_unreachable("Unimplemented option");
1651
}
1652
1653
return error;
1654
}
1655
1656
void OptionParsingStarting(ExecutionContext *execution_context) override {
1657
m_timeout.reset();
1658
m_use_host_platform = false;
1659
m_shell_interpreter.clear();
1660
}
1661
1662
Timeout<std::micro> m_timeout = std::chrono::seconds(10);
1663
bool m_use_host_platform;
1664
std::string m_shell_interpreter;
1665
};
1666
1667
CommandObjectPlatformShell(CommandInterpreter &interpreter)
1668
: CommandObjectRaw(interpreter, "platform shell",
1669
"Run a shell command on the current platform.",
1670
"platform shell <shell-command>", 0) {
1671
AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar);
1672
}
1673
1674
~CommandObjectPlatformShell() override = default;
1675
1676
Options *GetOptions() override { return &m_options; }
1677
1678
void DoExecute(llvm::StringRef raw_command_line,
1679
CommandReturnObject &result) override {
1680
ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
1681
m_options.NotifyOptionParsingStarting(&exe_ctx);
1682
1683
// Print out an usage syntax on an empty command line.
1684
if (raw_command_line.empty()) {
1685
result.GetOutputStream().Printf("%s\n", this->GetSyntax().str().c_str());
1686
return;
1687
}
1688
1689
const bool is_alias = !raw_command_line.contains("platform");
1690
OptionsWithRaw args(raw_command_line);
1691
1692
if (args.HasArgs())
1693
if (!ParseOptions(args.GetArgs(), result))
1694
return;
1695
1696
if (args.GetRawPart().empty()) {
1697
result.GetOutputStream().Printf("%s <shell-command>\n",
1698
is_alias ? "shell" : "platform shell");
1699
return;
1700
}
1701
1702
llvm::StringRef cmd = args.GetRawPart();
1703
1704
PlatformSP platform_sp(
1705
m_options.m_use_host_platform
1706
? Platform::GetHostPlatform()
1707
: GetDebugger().GetPlatformList().GetSelectedPlatform());
1708
Status error;
1709
if (platform_sp) {
1710
FileSpec working_dir{};
1711
std::string output;
1712
int status = -1;
1713
int signo = -1;
1714
error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd,
1715
working_dir, &status, &signo,
1716
&output, m_options.m_timeout));
1717
if (!output.empty())
1718
result.GetOutputStream().PutCString(output);
1719
if (status > 0) {
1720
if (signo > 0) {
1721
const char *signo_cstr = Host::GetSignalAsCString(signo);
1722
if (signo_cstr)
1723
result.GetOutputStream().Printf(
1724
"error: command returned with status %i and signal %s\n",
1725
status, signo_cstr);
1726
else
1727
result.GetOutputStream().Printf(
1728
"error: command returned with status %i and signal %i\n",
1729
status, signo);
1730
} else
1731
result.GetOutputStream().Printf(
1732
"error: command returned with status %i\n", status);
1733
}
1734
} else {
1735
result.GetOutputStream().Printf(
1736
"error: cannot run remote shell commands without a platform\n");
1737
error.SetErrorString(
1738
"error: cannot run remote shell commands without a platform");
1739
}
1740
1741
if (error.Fail()) {
1742
result.AppendError(error.AsCString());
1743
} else {
1744
result.SetStatus(eReturnStatusSuccessFinishResult);
1745
}
1746
}
1747
1748
CommandOptions m_options;
1749
};
1750
1751
// "platform install" - install a target to a remote end
1752
class CommandObjectPlatformInstall : public CommandObjectParsed {
1753
public:
1754
CommandObjectPlatformInstall(CommandInterpreter &interpreter)
1755
: CommandObjectParsed(
1756
interpreter, "platform target-install",
1757
"Install a target (bundle or executable file) to the remote end.",
1758
"platform target-install <local-thing> <remote-sandbox>", 0) {
1759
CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain};
1760
CommandArgumentData remote_arg{eArgTypeRemotePath, eArgRepeatPlain};
1761
m_arguments.push_back({local_arg});
1762
m_arguments.push_back({remote_arg});
1763
}
1764
1765
~CommandObjectPlatformInstall() override = default;
1766
1767
void
1768
HandleArgumentCompletion(CompletionRequest &request,
1769
OptionElementVector &opt_element_vector) override {
1770
if (request.GetCursorIndex())
1771
return;
1772
lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1773
GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
1774
}
1775
1776
void DoExecute(Args &args, CommandReturnObject &result) override {
1777
if (args.GetArgumentCount() != 2) {
1778
result.AppendError("platform target-install takes two arguments");
1779
return;
1780
}
1781
// TODO: move the bulk of this code over to the platform itself
1782
FileSpec src(args.GetArgumentAtIndex(0));
1783
FileSystem::Instance().Resolve(src);
1784
FileSpec dst(args.GetArgumentAtIndex(1));
1785
if (!FileSystem::Instance().Exists(src)) {
1786
result.AppendError("source location does not exist or is not accessible");
1787
return;
1788
}
1789
PlatformSP platform_sp(
1790
GetDebugger().GetPlatformList().GetSelectedPlatform());
1791
if (!platform_sp) {
1792
result.AppendError("no platform currently selected");
1793
return;
1794
}
1795
1796
Status error = platform_sp->Install(src, dst);
1797
if (error.Success()) {
1798
result.SetStatus(eReturnStatusSuccessFinishNoResult);
1799
} else {
1800
result.AppendErrorWithFormat("install failed: %s", error.AsCString());
1801
}
1802
}
1803
};
1804
1805
CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter)
1806
: CommandObjectMultiword(
1807
interpreter, "platform", "Commands to manage and create platforms.",
1808
"platform [connect|disconnect|info|list|status|select] ...") {
1809
LoadSubCommand("select",
1810
CommandObjectSP(new CommandObjectPlatformSelect(interpreter)));
1811
LoadSubCommand("list",
1812
CommandObjectSP(new CommandObjectPlatformList(interpreter)));
1813
LoadSubCommand("status",
1814
CommandObjectSP(new CommandObjectPlatformStatus(interpreter)));
1815
LoadSubCommand("connect", CommandObjectSP(
1816
new CommandObjectPlatformConnect(interpreter)));
1817
LoadSubCommand(
1818
"disconnect",
1819
CommandObjectSP(new CommandObjectPlatformDisconnect(interpreter)));
1820
LoadSubCommand("settings", CommandObjectSP(new CommandObjectPlatformSettings(
1821
interpreter)));
1822
LoadSubCommand("mkdir",
1823
CommandObjectSP(new CommandObjectPlatformMkDir(interpreter)));
1824
LoadSubCommand("file",
1825
CommandObjectSP(new CommandObjectPlatformFile(interpreter)));
1826
LoadSubCommand("file-exists",
1827
CommandObjectSP(new CommandObjectPlatformFileExists(interpreter)));
1828
LoadSubCommand("get-file", CommandObjectSP(new CommandObjectPlatformGetFile(
1829
interpreter)));
1830
LoadSubCommand("get-permissions",
1831
CommandObjectSP(new CommandObjectPlatformGetPermissions(interpreter)));
1832
LoadSubCommand("get-size", CommandObjectSP(new CommandObjectPlatformGetSize(
1833
interpreter)));
1834
LoadSubCommand("put-file", CommandObjectSP(new CommandObjectPlatformPutFile(
1835
interpreter)));
1836
LoadSubCommand("process", CommandObjectSP(
1837
new CommandObjectPlatformProcess(interpreter)));
1838
LoadSubCommand("shell",
1839
CommandObjectSP(new CommandObjectPlatformShell(interpreter)));
1840
LoadSubCommand(
1841
"target-install",
1842
CommandObjectSP(new CommandObjectPlatformInstall(interpreter)));
1843
}
1844
1845
CommandObjectPlatform::~CommandObjectPlatform() = default;
1846
1847