Coverage Report

Created: 2022-01-15 10:30

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- PlatformWindows.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 "PlatformWindows.h"
10
11
#include <cstdio>
12
#if defined(_WIN32)
13
#include "lldb/Host/windows/windows.h"
14
#include <winsock2.h>
15
#endif
16
17
#include "lldb/Breakpoint/BreakpointLocation.h"
18
#include "lldb/Breakpoint/BreakpointSite.h"
19
#include "lldb/Core/Debugger.h"
20
#include "lldb/Core/Module.h"
21
#include "lldb/Core/PluginManager.h"
22
#include "lldb/Expression/DiagnosticManager.h"
23
#include "lldb/Expression/FunctionCaller.h"
24
#include "lldb/Expression/UserExpression.h"
25
#include "lldb/Expression/UtilityFunction.h"
26
#include "lldb/Host/HostInfo.h"
27
#include "lldb/Target/DynamicLoader.h"
28
#include "lldb/Target/Process.h"
29
#include "lldb/Utility/Status.h"
30
31
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
32
33
#include "llvm/ADT/ScopeExit.h"
34
#include "llvm/Support/ConvertUTF.h"
35
36
using namespace lldb;
37
using namespace lldb_private;
38
39
LLDB_PLUGIN_DEFINE(PlatformWindows)
40
41
static uint32_t g_initialize_count = 0;
42
43
PlatformSP PlatformWindows::CreateInstance(bool force,
44
75
                                           const lldb_private::ArchSpec *arch) {
45
  // The only time we create an instance is when we are creating a remote
46
  // windows platform
47
75
  const bool is_host = false;
48
49
75
  bool create = force;
50
75
  if (!create && 
arch74
&&
arch->IsValid()74
) {
51
74
    const llvm::Triple &triple = arch->GetTriple();
52
74
    switch (triple.getVendor()) {
53
24
    case llvm::Triple::PC:
54
24
      create = true;
55
24
      break;
56
57
44
    case llvm::Triple::UnknownVendor:
58
44
      create = !arch->TripleVendorWasSpecified();
59
44
      break;
60
61
6
    default:
62
6
      break;
63
74
    }
64
65
74
    if (create) {
66
40
      switch (triple.getOS()) {
67
24
      case llvm::Triple::Win32:
68
24
        break;
69
70
4
      case llvm::Triple::UnknownOS:
71
4
        create = arch->TripleOSWasSpecified();
72
4
        break;
73
74
12
      default:
75
12
        create = false;
76
12
        break;
77
40
      }
78
40
    }
79
74
  }
80
75
  if (create)
81
25
    return PlatformSP(new PlatformWindows(is_host));
82
50
  return PlatformSP();
83
75
}
84
85
3.43k
llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
86
3.43k
  return is_host ? 
"Local Windows user platform plug-in."0
87
3.43k
                 : "Remote Windows user platform plug-in.";
88
3.43k
}
89
90
3.43k
void PlatformWindows::Initialize() {
91
3.43k
  Platform::Initialize();
92
93
3.43k
  if (g_initialize_count++ == 0) {
94
#if defined(_WIN32)
95
    // Force a host flag to true for the default platform object.
96
    PlatformSP default_platform_sp(new PlatformWindows(true));
97
    default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
98
    Platform::SetHostPlatform(default_platform_sp);
99
#endif
100
3.43k
    PluginManager::RegisterPlugin(
101
3.43k
        PlatformWindows::GetPluginNameStatic(false),
102
3.43k
        PlatformWindows::GetPluginDescriptionStatic(false),
103
3.43k
        PlatformWindows::CreateInstance);
104
3.43k
  }
105
3.43k
}
106
107
3.43k
void PlatformWindows::Terminate() {
108
3.43k
  if (g_initialize_count > 0) {
109
3.43k
    if (--g_initialize_count == 0) {
110
3.43k
      PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
111
3.43k
    }
112
3.43k
  }
113
114
3.43k
  Platform::Terminate();
115
3.43k
}
116
117
/// Default Constructor
118
25
PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {
119
125
  const auto &AddArch = [&](const ArchSpec &spec) {
120
200
    if (
llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) 125
{
121
200
          return spec.IsExactMatch(rhs);
122
200
        }))
123
25
      return;
124
100
    if (spec.IsValid())
125
100
      m_supported_architectures.push_back(spec);
126
100
  };
127
25
  AddArch(ArchSpec("i686-pc-windows"));
128
25
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
129
25
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
130
25
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
131
25
  AddArch(ArchSpec("i386-pc-windows"));
132
25
}
133
134
0
Status PlatformWindows::ConnectRemote(Args &args) {
135
0
  Status error;
136
0
  if (IsHost()) {
137
0
    error.SetErrorStringWithFormatv(
138
0
        "can't connect to the host platform '{0}', always connected",
139
0
        GetPluginName());
140
0
  } else {
141
0
    if (!m_remote_platform_sp)
142
0
      m_remote_platform_sp =
143
0
          Platform::Create(ConstString("remote-gdb-server"), error);
144
145
0
    if (m_remote_platform_sp) {
146
0
      if (error.Success()) {
147
0
        if (m_remote_platform_sp) {
148
0
          error = m_remote_platform_sp->ConnectRemote(args);
149
0
        } else {
150
0
          error.SetErrorString(
151
0
              "\"platform connect\" takes a single argument: <connect-url>");
152
0
        }
153
0
      }
154
0
    } else
155
0
      error.SetErrorString("failed to create a 'remote-gdb-server' platform");
156
157
0
    if (error.Fail())
158
0
      m_remote_platform_sp.reset();
159
0
  }
160
161
0
  return error;
162
0
}
163
164
uint32_t PlatformWindows::DoLoadImage(Process *process,
165
                                      const FileSpec &remote_file,
166
                                      const std::vector<std::string> *paths,
167
0
                                      Status &error, FileSpec *loaded_image) {
168
0
  DiagnosticManager diagnostics;
169
170
0
  if (loaded_image)
171
0
    loaded_image->Clear();
172
173
0
  ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
174
0
  if (!thread) {
175
0
    error.SetErrorString("LoadLibrary error: no thread available to invoke LoadLibrary");
176
0
    return LLDB_INVALID_IMAGE_TOKEN;
177
0
  }
178
179
0
  ExecutionContext context;
180
0
  thread->CalculateExecutionContext(context);
181
182
0
  Status status;
183
0
  UtilityFunction *loader =
184
0
      process->GetLoadImageUtilityFunction(this, [&]() -> std::unique_ptr<UtilityFunction> {
185
0
        return MakeLoadImageUtilityFunction(context, status);
186
0
      });
187
0
  if (loader == nullptr)
188
0
    return LLDB_INVALID_IMAGE_TOKEN;
189
190
0
  FunctionCaller *invocation = loader->GetFunctionCaller();
191
0
  if (!invocation) {
192
0
    error.SetErrorString("LoadLibrary error: could not get function caller");
193
0
    return LLDB_INVALID_IMAGE_TOKEN;
194
0
  }
195
196
  /* Convert name */
197
0
  llvm::SmallVector<llvm::UTF16, 261> name;
198
0
  if (!llvm::convertUTF8ToUTF16String(remote_file.GetPath(), name)) {
199
0
    error.SetErrorString("LoadLibrary error: could not convert path to UCS2");
200
0
    return LLDB_INVALID_IMAGE_TOKEN;
201
0
  }
202
0
  name.emplace_back(L'\0');
203
204
  /* Inject name paramter into inferior */
205
0
  lldb::addr_t injected_name =
206
0
      process->AllocateMemory(name.size() * sizeof(llvm::UTF16),
207
0
                              ePermissionsReadable | ePermissionsWritable,
208
0
                              status);
209
0
  if (injected_name == LLDB_INVALID_ADDRESS) {
210
0
    error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for name: %s",
211
0
                                   status.AsCString());
212
0
    return LLDB_INVALID_IMAGE_TOKEN;
213
0
  }
214
215
0
  auto name_cleanup = llvm::make_scope_exit([process, injected_name]() {
216
0
    process->DeallocateMemory(injected_name);
217
0
  });
218
219
0
  process->WriteMemory(injected_name, name.data(),
220
0
                       name.size() * sizeof(llvm::UTF16), status);
221
0
  if (status.Fail()) {
222
0
    error.SetErrorStringWithFormat("LoadLibrary error: unable to write name: %s",
223
0
                                   status.AsCString());
224
0
    return LLDB_INVALID_IMAGE_TOKEN;
225
0
  }
226
227
  /* Inject paths parameter into inferior */
228
0
  lldb::addr_t injected_paths{0x0};
229
0
  llvm::Optional<llvm::detail::scope_exit<std::function<void()>>> paths_cleanup;
230
0
  if (paths) {
231
0
    llvm::SmallVector<llvm::UTF16, 261> search_paths;
232
233
0
    for (const auto &path : *paths) {
234
0
      if (path.empty())
235
0
        continue;
236
237
0
      llvm::SmallVector<llvm::UTF16, 261> buffer;
238
0
      if (!llvm::convertUTF8ToUTF16String(path, buffer))
239
0
        continue;
240
241
0
      search_paths.append(std::begin(buffer), std::end(buffer));
242
0
      search_paths.emplace_back(L'\0');
243
0
    }
244
0
    search_paths.emplace_back(L'\0');
245
246
0
    injected_paths =
247
0
        process->AllocateMemory(search_paths.size() * sizeof(llvm::UTF16),
248
0
                                ePermissionsReadable | ePermissionsWritable,
249
0
                                status);
250
0
    if (injected_paths == LLDB_INVALID_ADDRESS) {
251
0
      error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for paths: %s",
252
0
                                     status.AsCString());
253
0
      return LLDB_INVALID_IMAGE_TOKEN;
254
0
    }
255
256
0
    paths_cleanup.emplace([process, injected_paths]() {
257
0
      process->DeallocateMemory(injected_paths);
258
0
    });
259
260
0
    process->WriteMemory(injected_paths, search_paths.data(),
261
0
                         search_paths.size() * sizeof(llvm::UTF16), status);
262
0
    if (status.Fail()) {
263
0
      error.SetErrorStringWithFormat("LoadLibrary error: unable to write paths: %s",
264
0
                                     status.AsCString());
265
0
      return LLDB_INVALID_IMAGE_TOKEN;
266
0
    }
267
0
  }
268
269
  /* Inject wszModulePath into inferior */
270
  // FIXME(compnerd) should do something better for the length?
271
  // GetModuleFileNameA is likely limited to PATH_MAX rather than the NT path
272
  // limit.
273
0
  unsigned injected_length = 261;
274
275
0
  lldb::addr_t injected_module_path =
276
0
      process->AllocateMemory(injected_length + 1,
277
0
                              ePermissionsReadable | ePermissionsWritable,
278
0
                              status);
279
0
  if (injected_module_path == LLDB_INVALID_ADDRESS) {
280
0
    error.SetErrorStringWithFormat("LoadLibrary error: unable to allocate memory for module location: %s",
281
0
                                   status.AsCString());
282
0
    return LLDB_INVALID_IMAGE_TOKEN;
283
0
  }
284
285
0
  auto injected_module_path_cleanup =
286
0
      llvm::make_scope_exit([process, injected_module_path]() {
287
0
    process->DeallocateMemory(injected_module_path);
288
0
  });
289
290
  /* Inject __lldb_LoadLibraryResult into inferior */
291
0
  const uint32_t word_size = process->GetAddressByteSize();
292
0
  lldb::addr_t injected_result =
293
0
      process->AllocateMemory(3 * word_size,
294
0
                              ePermissionsReadable | ePermissionsWritable,
295
0
                              status);
296
0
  if (status.Fail()) {
297
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not allocate memory for result: %s",
298
0
                                   status.AsCString());
299
0
    return LLDB_INVALID_IMAGE_TOKEN;
300
0
  }
301
302
0
  auto result_cleanup = llvm::make_scope_exit([process, injected_result]() {
303
0
    process->DeallocateMemory(injected_result);
304
0
  });
305
306
0
  process->WritePointerToMemory(injected_result + word_size,
307
0
                                injected_module_path, status);
308
0
  if (status.Fail()) {
309
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
310
0
                                   status.AsCString());
311
0
    return LLDB_INVALID_IMAGE_TOKEN;
312
0
  }
313
314
  // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
315
0
  process->WriteScalarToMemory(injected_result + 2 * word_size,
316
0
                               Scalar{injected_length}, sizeof(unsigned),
317
0
                               status);
318
0
  if (status.Fail()) {
319
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not initialize result: %s",
320
0
                                   status.AsCString());
321
0
    return LLDB_INVALID_IMAGE_TOKEN;
322
0
  }
323
324
  /* Setup Formal Parameters */
325
0
  ValueList parameters = invocation->GetArgumentValues();
326
0
  parameters.GetValueAtIndex(0)->GetScalar() = injected_name;
327
0
  parameters.GetValueAtIndex(1)->GetScalar() = injected_paths;
328
0
  parameters.GetValueAtIndex(2)->GetScalar() = injected_result;
329
330
0
  lldb::addr_t injected_parameters = LLDB_INVALID_ADDRESS;
331
0
  diagnostics.Clear();
332
0
  if (!invocation->WriteFunctionArguments(context, injected_parameters,
333
0
                                          parameters, diagnostics)) {
334
0
    error.SetErrorStringWithFormat("LoadLibrary error: unable to write function parameters: %s",
335
0
                                   diagnostics.GetString().c_str());
336
0
    return LLDB_INVALID_IMAGE_TOKEN;
337
0
  }
338
339
0
  auto parameter_cleanup = llvm::make_scope_exit([invocation, &context, injected_parameters]() {
340
0
    invocation->DeallocateFunctionResults(context, injected_parameters);
341
0
  });
342
343
0
  TypeSystemClang *ast =
344
0
      ScratchTypeSystemClang::GetForTarget(process->GetTarget());
345
0
  if (!ast) {
346
0
    error.SetErrorString("LoadLibrary error: unable to get (clang) type system");
347
0
    return LLDB_INVALID_IMAGE_TOKEN;
348
0
  }
349
350
  /* Setup Return Type */
351
0
  CompilerType VoidPtrTy = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
352
353
0
  Value value;
354
0
  value.SetCompilerType(VoidPtrTy);
355
356
  /* Invoke expression */
357
0
  EvaluateExpressionOptions options;
358
0
  options.SetExecutionPolicy(eExecutionPolicyAlways);
359
0
  options.SetLanguage(eLanguageTypeC_plus_plus);
360
0
  options.SetIgnoreBreakpoints(true);
361
0
  options.SetUnwindOnError(true);
362
  // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
363
  // They may potentially throw SEH exceptions which we do not know how to
364
  // handle currently.
365
0
  options.SetTrapExceptions(false);
366
0
  options.SetTimeout(process->GetUtilityExpressionTimeout());
367
0
  options.SetIsForUtilityExpr(true);
368
369
0
  ExpressionResults result =
370
0
      invocation->ExecuteFunction(context, &injected_parameters, options,
371
0
                                  diagnostics, value);
372
0
  if (result != eExpressionCompleted) {
373
0
    error.SetErrorStringWithFormat("LoadLibrary error: failed to execute LoadLibrary helper: %s",
374
0
                                   diagnostics.GetString().c_str());
375
0
    return LLDB_INVALID_IMAGE_TOKEN;
376
0
  }
377
378
  /* Read result */
379
0
  lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);
380
0
  if (status.Fail()) {
381
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not read the result: %s",
382
0
                                   status.AsCString());
383
0
    return LLDB_INVALID_IMAGE_TOKEN;
384
0
  }
385
386
0
  if (!token) {
387
    // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
388
0
    uint64_t error_code =
389
0
        process->ReadUnsignedIntegerFromMemory(injected_result + 2 * word_size + sizeof(unsigned),
390
0
                                               word_size, 0, status);
391
0
    if (status.Fail()) {
392
0
      error.SetErrorStringWithFormat("LoadLibrary error: could not read error status: %s",
393
0
                                     status.AsCString());
394
0
      return LLDB_INVALID_IMAGE_TOKEN;
395
0
    }
396
397
0
    error.SetErrorStringWithFormat("LoadLibrary Error: %" PRIu64, error_code);
398
0
    return LLDB_INVALID_IMAGE_TOKEN;
399
0
  }
400
401
0
  std::string module_path;
402
0
  process->ReadCStringFromMemory(injected_module_path, module_path, status);
403
0
  if (status.Fail()) {
404
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not read module path: %s",
405
0
                                   status.AsCString());
406
0
    return LLDB_INVALID_IMAGE_TOKEN;
407
0
  }
408
409
0
  if (loaded_image)
410
0
    loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
411
0
  return process->AddImageToken(token);
412
0
}
413
414
0
Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
415
0
  const addr_t address = process->GetImagePtrFromToken(image_token);
416
0
  if (address == LLDB_INVALID_ADDRESS)
417
0
    return Status("invalid image token");
418
419
0
  StreamString expression;
420
0
  expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
421
422
0
  ValueObjectSP value;
423
0
  Status result =
424
0
      EvaluateLoaderExpression(process, expression.GetData(), value);
425
0
  if (result.Fail())
426
0
    return result;
427
428
0
  if (value->GetError().Fail())
429
0
    return value->GetError();
430
431
0
  Scalar scalar;
432
0
  if (value->ResolveValue(scalar)) {
433
0
    if (scalar.UInt(1))
434
0
      return Status("expression failed: \"%s\"", expression.GetData());
435
0
    process->ResetImageToken(image_token);
436
0
  }
437
438
0
  return Status();
439
0
}
440
441
0
Status PlatformWindows::DisconnectRemote() {
442
0
  Status error;
443
444
0
  if (IsHost()) {
445
0
    error.SetErrorStringWithFormatv(
446
0
        "can't disconnect from the host platform '{0}', always connected",
447
0
        GetPluginName());
448
0
  } else {
449
0
    if (m_remote_platform_sp)
450
0
      error = m_remote_platform_sp->DisconnectRemote();
451
0
    else
452
0
      error.SetErrorString("the platform is not currently connected");
453
0
  }
454
0
  return error;
455
0
}
456
457
ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
458
                                        Debugger &debugger, Target &target,
459
0
                                        Status &error) {
460
  // Windows has special considerations that must be followed when launching or
461
  // attaching to a process.  The key requirement is that when launching or
462
  // attaching to a process, you must do it from the same the thread that will
463
  // go into a permanent loop which will then receive debug events from the
464
  // process.  In particular, this means we can't use any of LLDB's generic
465
  // mechanisms to do it for us, because it doesn't have the special knowledge
466
  // required for setting up the background thread or passing the right flags.
467
  //
468
  // Another problem is that that LLDB's standard model for debugging a process
469
  // is to first launch it, have it stop at the entry point, and then attach to
470
  // it.  In Windows this doesn't quite work, you have to specify as an
471
  // argument to CreateProcess() that you're going to debug the process.  So we
472
  // override DebugProcess here to handle this.  Launch operations go directly
473
  // to the process plugin, and attach operations almost go directly to the
474
  // process plugin (but we hijack the events first).  In essence, we
475
  // encapsulate all the logic of Launching and Attaching in the process
476
  // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
477
  // the process plugin.
478
479
0
  if (IsRemote()) {
480
0
    if (m_remote_platform_sp)
481
0
      return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
482
0
                                                error);
483
0
    else
484
0
      error.SetErrorString("the platform is not currently connected");
485
0
  }
486
487
0
  if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
488
    // This is a process attach.  Don't need to launch anything.
489
0
    ProcessAttachInfo attach_info(launch_info);
490
0
    return Attach(attach_info, debugger, &target, error);
491
0
  } else {
492
0
    ProcessSP process_sp = target.CreateProcess(
493
0
        launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr,
494
0
        false);
495
496
    // We need to launch and attach to the process.
497
0
    launch_info.GetFlags().Set(eLaunchFlagDebug);
498
0
    if (process_sp)
499
0
      error = process_sp->Launch(launch_info);
500
501
0
    return process_sp;
502
0
  }
503
0
}
504
505
lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
506
                                        Debugger &debugger, Target *target,
507
0
                                        Status &error) {
508
0
  error.Clear();
509
0
  lldb::ProcessSP process_sp;
510
0
  if (!IsHost()) {
511
0
    if (m_remote_platform_sp)
512
0
      process_sp =
513
0
          m_remote_platform_sp->Attach(attach_info, debugger, target, error);
514
0
    else
515
0
      error.SetErrorString("the platform is not currently connected");
516
0
    return process_sp;
517
0
  }
518
519
0
  if (target == nullptr) {
520
0
    TargetSP new_target_sp;
521
0
    FileSpec emptyFileSpec;
522
0
    ArchSpec emptyArchSpec;
523
524
0
    error = debugger.GetTargetList().CreateTarget(
525
0
        debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
526
0
    target = new_target_sp.get();
527
0
  }
528
529
0
  if (!target || error.Fail())
530
0
    return process_sp;
531
532
0
  const char *plugin_name = attach_info.GetProcessPluginName();
533
0
  process_sp = target->CreateProcess(
534
0
      attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false);
535
536
0
  process_sp->HijackProcessEvents(attach_info.GetHijackListener());
537
0
  if (process_sp)
538
0
    error = process_sp->Attach(attach_info);
539
540
0
  return process_sp;
541
0
}
542
543
0
void PlatformWindows::GetStatus(Stream &strm) {
544
0
  Platform::GetStatus(strm);
545
546
#ifdef _WIN32
547
  llvm::VersionTuple version = HostInfo::GetOSVersion();
548
  strm << "      Host: Windows " << version.getAsString() << '\n';
549
#endif
550
0
}
551
552
0
bool PlatformWindows::CanDebugProcess() { return true; }
553
554
0
ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
555
0
  if (basename.IsEmpty())
556
0
    return basename;
557
558
0
  StreamString stream;
559
0
  stream.Printf("%s.dll", basename.GetCString());
560
0
  return ConstString(stream.GetString());
561
0
}
562
563
size_t
564
PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
565
0
                                                 BreakpointSite *bp_site) {
566
0
  ArchSpec arch = target.GetArchitecture();
567
0
  assert(arch.IsValid());
568
0
  const uint8_t *trap_opcode = nullptr;
569
0
  size_t trap_opcode_size = 0;
570
571
0
  switch (arch.GetMachine()) {
572
0
  case llvm::Triple::aarch64: {
573
0
    static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
574
0
    trap_opcode = g_aarch64_opcode;
575
0
    trap_opcode_size = sizeof(g_aarch64_opcode);
576
577
0
    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
578
0
      return trap_opcode_size;
579
0
    return 0;
580
0
  } break;
581
582
0
  case llvm::Triple::arm:
583
0
  case llvm::Triple::thumb: {
584
0
    static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
585
0
    trap_opcode = g_thumb_opcode;
586
0
    trap_opcode_size = sizeof(g_thumb_opcode);
587
588
0
    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
589
0
      return trap_opcode_size;
590
0
    return 0;
591
0
  } break;
592
593
0
  default:
594
0
    return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
595
0
  }
596
0
}
597
598
std::unique_ptr<UtilityFunction>
599
PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
600
0
                                              Status &status) {
601
  // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
602
0
  static constexpr const char kLoaderDecls[] = R"(
603
0
extern "C" {
604
0
// errhandlingapi.h
605
0
606
0
// `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
607
0
//
608
0
// Directories in the standard search path are not searched. This value cannot
609
0
// be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
610
0
//
611
0
// This value represents the recommended maximum number of directories an
612
0
// application should include in its DLL search path.
613
0
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
614
0
615
0
// WINBASEAPI DWORD WINAPI GetLastError(VOID);
616
0
/* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
617
0
618
0
// libloaderapi.h
619
0
620
0
// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
621
0
/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
622
0
623
0
// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
624
0
/* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
625
0
626
0
// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
627
0
/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
628
0
629
0
// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
630
0
/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
631
0
632
0
// corecrt_wstring.h
633
0
634
0
// _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
635
0
/* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
636
0
637
0
// lldb specific code
638
0
639
0
struct __lldb_LoadLibraryResult {
640
0
  void *ImageBase;
641
0
  char *ModulePath;
642
0
  unsigned Length;
643
0
  unsigned ErrorCode;
644
0
};
645
0
646
0
_Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
647
0
               "__lldb_LoadLibraryResult size mismatch");
648
0
649
0
void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
650
0
                                __lldb_LoadLibraryResult *result) {
651
0
  for (const wchar_t *path = paths; path; ) {
652
0
    (void)AddDllDirectory(path);
653
0
    path += wcslen(path) + 1;
654
0
  }
655
0
656
0
  result->ImageBase = LoadLibraryExW(name, nullptr,
657
0
                                     LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
658
0
  if (result->ImageBase == nullptr)
659
0
    result->ErrorCode = GetLastError();
660
0
  else
661
0
    result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,
662
0
                                        result->Length);
663
0
664
0
  return result->ImageBase;
665
0
}
666
0
}
667
0
  )";
668
669
0
  static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
670
671
0
  ProcessSP process = context.GetProcessSP();
672
0
  Target &target = process->GetTarget();
673
674
0
  auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
675
0
                                               eLanguageTypeC_plus_plus,
676
0
                                               context);
677
0
  if (!function) {
678
0
    std::string error = llvm::toString(function.takeError());
679
0
    status.SetErrorStringWithFormat("LoadLibrary error: could not create utility function: %s",
680
0
                                    error.c_str());
681
0
    return nullptr;
682
0
  }
683
684
0
  TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget(target);
685
0
  if (!ast)
686
0
    return nullptr;
687
688
0
  CompilerType VoidPtrTy = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
689
0
  CompilerType WCharPtrTy = ast->GetBasicType(eBasicTypeWChar).GetPointerType();
690
691
0
  ValueList parameters;
692
693
0
  Value value;
694
0
  value.SetValueType(Value::ValueType::Scalar);
695
696
0
  value.SetCompilerType(WCharPtrTy);
697
0
  parameters.PushValue(value);  // name
698
0
  parameters.PushValue(value);  // paths
699
700
0
  value.SetCompilerType(VoidPtrTy);
701
0
  parameters.PushValue(value);  // result
702
703
0
  Status error;
704
0
  std::unique_ptr<UtilityFunction> utility{std::move(*function)};
705
0
  utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
706
0
                              error);
707
0
  if (error.Fail()) {
708
0
    status.SetErrorStringWithFormat("LoadLibrary error: could not create function caller: %s",
709
0
                                    error.AsCString());
710
0
    return nullptr;
711
0
  }
712
713
0
  if (!utility->GetFunctionCaller()) {
714
0
    status.SetErrorString("LoadLibrary error: could not get function caller");
715
0
    return nullptr;
716
0
  }
717
718
0
  return utility;
719
0
}
720
721
Status PlatformWindows::EvaluateLoaderExpression(Process *process,
722
                                                 const char *expression,
723
0
                                                 ValueObjectSP &value) {
724
  // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
725
0
  static constexpr const char kLoaderDecls[] = R"(
726
0
extern "C" {
727
0
// libloaderapi.h
728
0
729
0
// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
730
0
/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
731
0
732
0
// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
733
0
/* __declspec(dllimport) */ int __stdcall FreeModule(void *);
734
0
735
0
// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);
736
0
/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
737
0
738
0
// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
739
0
/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
740
0
}
741
0
  )";
742
743
0
  if (DynamicLoader *loader = process->GetDynamicLoader()) {
744
0
    Status result = loader->CanLoadImage();
745
0
    if (result.Fail())
746
0
      return result;
747
0
  }
748
749
0
  ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
750
0
  if (!thread)
751
0
    return Status("selected thread is invalid");
752
753
0
  StackFrameSP frame = thread->GetStackFrameAtIndex(0);
754
0
  if (!frame)
755
0
    return Status("frame 0 is invalid");
756
757
0
  ExecutionContext context;
758
0
  frame->CalculateExecutionContext(context);
759
760
0
  EvaluateExpressionOptions options;
761
0
  options.SetUnwindOnError(true);
762
0
  options.SetIgnoreBreakpoints(true);
763
0
  options.SetExecutionPolicy(eExecutionPolicyAlways);
764
0
  options.SetLanguage(eLanguageTypeC_plus_plus);
765
  // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
766
  // They may potentially throw SEH exceptions which we do not know how to
767
  // handle currently.
768
0
  options.SetTrapExceptions(false);
769
0
  options.SetTimeout(process->GetUtilityExpressionTimeout());
770
771
0
  Status error;
772
0
  ExpressionResults result = UserExpression::Evaluate(
773
0
      context, options, expression, kLoaderDecls, value, error);
774
0
  if (result != eExpressionCompleted)
775
0
    return error;
776
777
0
  if (value->GetError().Fail())
778
0
    return value->GetError();
779
780
0
  return Status();
781
0
}