Coverage Report

Created: 2023-11-11 10:31

/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
#include <optional>
13
#if defined(_WIN32)
14
#include "lldb/Host/windows/windows.h"
15
#include <winsock2.h>
16
#endif
17
18
#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
19
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
20
#include "lldb/Breakpoint/BreakpointLocation.h"
21
#include "lldb/Breakpoint/BreakpointSite.h"
22
#include "lldb/Core/Debugger.h"
23
#include "lldb/Core/Module.h"
24
#include "lldb/Core/PluginManager.h"
25
#include "lldb/Expression/DiagnosticManager.h"
26
#include "lldb/Expression/FunctionCaller.h"
27
#include "lldb/Expression/UserExpression.h"
28
#include "lldb/Expression/UtilityFunction.h"
29
#include "lldb/Host/HostInfo.h"
30
#include "lldb/Target/DynamicLoader.h"
31
#include "lldb/Target/Process.h"
32
#include "lldb/Utility/Status.h"
33
34
#include "llvm/ADT/ScopeExit.h"
35
#include "llvm/Support/ConvertUTF.h"
36
37
using namespace lldb;
38
using namespace lldb_private;
39
40
LLDB_PLUGIN_DEFINE(PlatformWindows)
41
42
static uint32_t g_initialize_count = 0;
43
44
PlatformSP PlatformWindows::CreateInstance(bool force,
45
206
                                           const lldb_private::ArchSpec *arch) {
46
  // The only time we create an instance is when we are creating a remote
47
  // windows platform
48
206
  const bool is_host = false;
49
50
206
  bool create = force;
51
206
  if (!create && 
arch200
&&
arch->IsValid()200
) {
52
200
    const llvm::Triple &triple = arch->GetTriple();
53
200
    switch (triple.getVendor()) {
54
90
    case llvm::Triple::PC:
55
90
      create = true;
56
90
      break;
57
58
103
    case llvm::Triple::UnknownVendor:
59
103
      create = !arch->TripleVendorWasSpecified();
60
103
      break;
61
62
7
    default:
63
7
      break;
64
200
    }
65
66
200
    if (create) {
67
113
      switch (triple.getOS()) {
68
90
      case llvm::Triple::Win32:
69
90
        break;
70
71
11
      case llvm::Triple::UnknownOS:
72
11
        create = arch->TripleOSWasSpecified();
73
11
        break;
74
75
12
      default:
76
12
        create = false;
77
12
        break;
78
113
      }
79
113
    }
80
200
  }
81
206
  if (create)
82
96
    return PlatformSP(new PlatformWindows(is_host));
83
110
  return PlatformSP();
84
206
}
85
86
3.95k
llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
87
3.95k
  return is_host ? 
"Local Windows user platform plug-in."0
88
3.95k
                 : "Remote Windows user platform plug-in.";
89
3.95k
}
90
91
3.95k
void PlatformWindows::Initialize() {
92
3.95k
  Platform::Initialize();
93
94
3.95k
  if (g_initialize_count++ == 0) {
95
#if defined(_WIN32)
96
    // Force a host flag to true for the default platform object.
97
    PlatformSP default_platform_sp(new PlatformWindows(true));
98
    default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
99
    Platform::SetHostPlatform(default_platform_sp);
100
#endif
101
3.95k
    PluginManager::RegisterPlugin(
102
3.95k
        PlatformWindows::GetPluginNameStatic(false),
103
3.95k
        PlatformWindows::GetPluginDescriptionStatic(false),
104
3.95k
        PlatformWindows::CreateInstance);
105
3.95k
  }
106
3.95k
}
107
108
3.94k
void PlatformWindows::Terminate() {
109
3.94k
  if (g_initialize_count > 0) {
110
3.94k
    if (--g_initialize_count == 0) {
111
3.94k
      PluginManager::UnregisterPlugin(PlatformWindows::CreateInstance);
112
3.94k
    }
113
3.94k
  }
114
115
3.94k
  Platform::Terminate();
116
3.94k
}
117
118
/// Default Constructor
119
96
PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {
120
288
  const auto &AddArch = [&](const ArchSpec &spec) {
121
288
    if (llvm::any_of(m_supported_architectures, [spec](const ArchSpec &rhs) {
122
192
          return spec.IsExactMatch(rhs);
123
192
        }))
124
96
      return;
125
192
    if (spec.IsValid())
126
192
      m_supported_architectures.push_back(spec);
127
192
  };
128
96
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
129
96
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind32));
130
96
  AddArch(HostInfo::GetArchitecture(HostInfo::eArchKind64));
131
96
}
132
133
0
Status PlatformWindows::ConnectRemote(Args &args) {
134
0
  Status error;
135
0
  if (IsHost()) {
136
0
    error.SetErrorStringWithFormatv(
137
0
        "can't connect to the host platform '{0}', always connected",
138
0
        GetPluginName());
139
0
  } else {
140
0
    if (!m_remote_platform_sp)
141
0
      m_remote_platform_sp =
142
0
          platform_gdb_server::PlatformRemoteGDBServer::CreateInstance(
143
0
              /*force=*/true, nullptr);
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
  std::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 =
340
0
      llvm::make_scope_exit([invocation, &context, injected_parameters]() {
341
0
        invocation->DeallocateFunctionResults(context, injected_parameters);
342
0
      });
343
344
0
  TypeSystemClangSP scratch_ts_sp =
345
0
      ScratchTypeSystemClang::GetForTarget(process->GetTarget());
346
0
  if (!scratch_ts_sp) {
347
0
    error.SetErrorString("LoadLibrary error: unable to get (clang) type system");
348
0
    return LLDB_INVALID_IMAGE_TOKEN;
349
0
  }
350
351
  /* Setup Return Type */
352
0
  CompilerType VoidPtrTy =
353
0
      scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
354
355
0
  Value value;
356
0
  value.SetCompilerType(VoidPtrTy);
357
358
  /* Invoke expression */
359
0
  EvaluateExpressionOptions options;
360
0
  options.SetExecutionPolicy(eExecutionPolicyAlways);
361
0
  options.SetLanguage(eLanguageTypeC_plus_plus);
362
0
  options.SetIgnoreBreakpoints(true);
363
0
  options.SetUnwindOnError(true);
364
  // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
365
  // They may potentially throw SEH exceptions which we do not know how to
366
  // handle currently.
367
0
  options.SetTrapExceptions(false);
368
0
  options.SetTimeout(process->GetUtilityExpressionTimeout());
369
0
  options.SetIsForUtilityExpr(true);
370
371
0
  ExpressionResults result =
372
0
      invocation->ExecuteFunction(context, &injected_parameters, options,
373
0
                                  diagnostics, value);
374
0
  if (result != eExpressionCompleted) {
375
0
    error.SetErrorStringWithFormat("LoadLibrary error: failed to execute LoadLibrary helper: %s",
376
0
                                   diagnostics.GetString().c_str());
377
0
    return LLDB_INVALID_IMAGE_TOKEN;
378
0
  }
379
380
  /* Read result */
381
0
  lldb::addr_t token = process->ReadPointerFromMemory(injected_result, status);
382
0
  if (status.Fail()) {
383
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not read the result: %s",
384
0
                                   status.AsCString());
385
0
    return LLDB_INVALID_IMAGE_TOKEN;
386
0
  }
387
388
0
  if (!token) {
389
    // XXX(compnerd) should we use the compiler to get the sizeof(unsigned)?
390
0
    uint64_t error_code =
391
0
        process->ReadUnsignedIntegerFromMemory(injected_result + 2 * word_size + sizeof(unsigned),
392
0
                                               word_size, 0, status);
393
0
    if (status.Fail()) {
394
0
      error.SetErrorStringWithFormat("LoadLibrary error: could not read error status: %s",
395
0
                                     status.AsCString());
396
0
      return LLDB_INVALID_IMAGE_TOKEN;
397
0
    }
398
399
0
    error.SetErrorStringWithFormat("LoadLibrary Error: %" PRIu64, error_code);
400
0
    return LLDB_INVALID_IMAGE_TOKEN;
401
0
  }
402
403
0
  std::string module_path;
404
0
  process->ReadCStringFromMemory(injected_module_path, module_path, status);
405
0
  if (status.Fail()) {
406
0
    error.SetErrorStringWithFormat("LoadLibrary error: could not read module path: %s",
407
0
                                   status.AsCString());
408
0
    return LLDB_INVALID_IMAGE_TOKEN;
409
0
  }
410
411
0
  if (loaded_image)
412
0
    loaded_image->SetFile(module_path, llvm::sys::path::Style::native);
413
0
  return process->AddImageToken(token);
414
0
}
415
416
0
Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) {
417
0
  const addr_t address = process->GetImagePtrFromToken(image_token);
418
0
  if (address == LLDB_INVALID_IMAGE_TOKEN)
419
0
    return Status("invalid image token");
420
421
0
  StreamString expression;
422
0
  expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address);
423
424
0
  ValueObjectSP value;
425
0
  Status result =
426
0
      EvaluateLoaderExpression(process, expression.GetData(), value);
427
0
  if (result.Fail())
428
0
    return result;
429
430
0
  if (value->GetError().Fail())
431
0
    return value->GetError();
432
433
0
  Scalar scalar;
434
0
  if (value->ResolveValue(scalar)) {
435
0
    if (scalar.UInt(1))
436
0
      return Status("expression failed: \"%s\"", expression.GetData());
437
0
    process->ResetImageToken(image_token);
438
0
  }
439
440
0
  return Status();
441
0
}
442
443
0
Status PlatformWindows::DisconnectRemote() {
444
0
  Status error;
445
446
0
  if (IsHost()) {
447
0
    error.SetErrorStringWithFormatv(
448
0
        "can't disconnect from the host platform '{0}', always connected",
449
0
        GetPluginName());
450
0
  } else {
451
0
    if (m_remote_platform_sp)
452
0
      error = m_remote_platform_sp->DisconnectRemote();
453
0
    else
454
0
      error.SetErrorString("the platform is not currently connected");
455
0
  }
456
0
  return error;
457
0
}
458
459
ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
460
                                        Debugger &debugger, Target &target,
461
0
                                        Status &error) {
462
  // Windows has special considerations that must be followed when launching or
463
  // attaching to a process.  The key requirement is that when launching or
464
  // attaching to a process, you must do it from the same the thread that will
465
  // go into a permanent loop which will then receive debug events from the
466
  // process.  In particular, this means we can't use any of LLDB's generic
467
  // mechanisms to do it for us, because it doesn't have the special knowledge
468
  // required for setting up the background thread or passing the right flags.
469
  //
470
  // Another problem is that LLDB's standard model for debugging a process
471
  // is to first launch it, have it stop at the entry point, and then attach to
472
  // it.  In Windows this doesn't quite work, you have to specify as an
473
  // argument to CreateProcess() that you're going to debug the process.  So we
474
  // override DebugProcess here to handle this.  Launch operations go directly
475
  // to the process plugin, and attach operations almost go directly to the
476
  // process plugin (but we hijack the events first).  In essence, we
477
  // encapsulate all the logic of Launching and Attaching in the process
478
  // plugin, and PlatformWindows::DebugProcess is just a pass-through to get to
479
  // the process plugin.
480
481
0
  if (IsRemote()) {
482
0
    if (m_remote_platform_sp)
483
0
      return m_remote_platform_sp->DebugProcess(launch_info, debugger, target,
484
0
                                                error);
485
0
    else
486
0
      error.SetErrorString("the platform is not currently connected");
487
0
  }
488
489
0
  if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
490
    // This is a process attach.  Don't need to launch anything.
491
0
    ProcessAttachInfo attach_info(launch_info);
492
0
    return Attach(attach_info, debugger, &target, error);
493
0
  }
494
495
0
  ProcessSP process_sp =
496
0
      target.CreateProcess(launch_info.GetListener(),
497
0
                           launch_info.GetProcessPluginName(), nullptr, false);
498
499
0
  process_sp->HijackProcessEvents(launch_info.GetHijackListener());
500
501
  // We need to launch and attach to the process.
502
0
  launch_info.GetFlags().Set(eLaunchFlagDebug);
503
0
  if (process_sp)
504
0
    error = process_sp->Launch(launch_info);
505
506
0
  return process_sp;
507
0
}
508
509
lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info,
510
                                        Debugger &debugger, Target *target,
511
0
                                        Status &error) {
512
0
  error.Clear();
513
0
  lldb::ProcessSP process_sp;
514
0
  if (!IsHost()) {
515
0
    if (m_remote_platform_sp)
516
0
      process_sp =
517
0
          m_remote_platform_sp->Attach(attach_info, debugger, target, error);
518
0
    else
519
0
      error.SetErrorString("the platform is not currently connected");
520
0
    return process_sp;
521
0
  }
522
523
0
  if (target == nullptr) {
524
0
    TargetSP new_target_sp;
525
0
    FileSpec emptyFileSpec;
526
0
    ArchSpec emptyArchSpec;
527
528
0
    error = debugger.GetTargetList().CreateTarget(
529
0
        debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
530
0
    target = new_target_sp.get();
531
0
  }
532
533
0
  if (!target || error.Fail())
534
0
    return process_sp;
535
536
0
  process_sp =
537
0
      target->CreateProcess(attach_info.GetListenerForProcess(debugger),
538
0
                            attach_info.GetProcessPluginName(), nullptr, false);
539
540
0
  process_sp->HijackProcessEvents(attach_info.GetHijackListener());
541
0
  if (process_sp)
542
0
    error = process_sp->Attach(attach_info);
543
544
0
  return process_sp;
545
0
}
546
547
0
void PlatformWindows::GetStatus(Stream &strm) {
548
0
  Platform::GetStatus(strm);
549
550
#ifdef _WIN32
551
  llvm::VersionTuple version = HostInfo::GetOSVersion();
552
  strm << "      Host: Windows " << version.getAsString() << '\n';
553
#endif
554
0
}
555
556
0
bool PlatformWindows::CanDebugProcess() { return true; }
557
558
0
ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
559
0
  if (basename.IsEmpty())
560
0
    return basename;
561
562
0
  StreamString stream;
563
0
  stream.Printf("%s.dll", basename.GetCString());
564
0
  return ConstString(stream.GetString());
565
0
}
566
567
size_t
568
PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
569
0
                                                 BreakpointSite *bp_site) {
570
0
  ArchSpec arch = target.GetArchitecture();
571
0
  assert(arch.IsValid());
572
0
  const uint8_t *trap_opcode = nullptr;
573
0
  size_t trap_opcode_size = 0;
574
575
0
  switch (arch.GetMachine()) {
576
0
  case llvm::Triple::aarch64: {
577
0
    static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
578
0
    trap_opcode = g_aarch64_opcode;
579
0
    trap_opcode_size = sizeof(g_aarch64_opcode);
580
581
0
    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
582
0
      return trap_opcode_size;
583
0
    return 0;
584
0
  } break;
585
586
0
  case llvm::Triple::arm:
587
0
  case llvm::Triple::thumb: {
588
0
    static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
589
0
    trap_opcode = g_thumb_opcode;
590
0
    trap_opcode_size = sizeof(g_thumb_opcode);
591
592
0
    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
593
0
      return trap_opcode_size;
594
0
    return 0;
595
0
  } break;
596
597
0
  default:
598
0
    return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
599
0
  }
600
0
}
601
602
std::unique_ptr<UtilityFunction>
603
PlatformWindows::MakeLoadImageUtilityFunction(ExecutionContext &context,
604
0
                                              Status &status) {
605
  // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
606
0
  static constexpr const char kLoaderDecls[] = R"(
607
0
extern "C" {
608
0
// errhandlingapi.h
609
0
610
0
// `LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS`
611
0
//
612
0
// Directories in the standard search path are not searched. This value cannot
613
0
// be combined with `LOAD_WITH_ALTERED_SEARCH_PATH`.
614
0
//
615
0
// This value represents the recommended maximum number of directories an
616
0
// application should include in its DLL search path.
617
0
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
618
0
619
0
// WINBASEAPI DWORD WINAPI GetLastError(VOID);
620
0
/* __declspec(dllimport) */ uint32_t __stdcall GetLastError();
621
0
622
0
// libloaderapi.h
623
0
624
0
// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
625
0
/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
626
0
627
0
// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
628
0
/* __declspec(dllimport) */ int __stdcall FreeModule(void *hLibModule);
629
0
630
0
// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
631
0
/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
632
0
633
0
// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
634
0
/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
635
0
636
0
// corecrt_wstring.h
637
0
638
0
// _ACRTIMP size_t __cdecl wcslen(wchar_t const *_String);
639
0
/* __declspec(dllimport) */ size_t __cdecl wcslen(const wchar_t *);
640
0
641
0
// lldb specific code
642
0
643
0
struct __lldb_LoadLibraryResult {
644
0
  void *ImageBase;
645
0
  char *ModulePath;
646
0
  unsigned Length;
647
0
  unsigned ErrorCode;
648
0
};
649
0
650
0
_Static_assert(sizeof(struct __lldb_LoadLibraryResult) <= 3 * sizeof(void *),
651
0
               "__lldb_LoadLibraryResult size mismatch");
652
0
653
0
void * __lldb_LoadLibraryHelper(const wchar_t *name, const wchar_t *paths,
654
0
                                __lldb_LoadLibraryResult *result) {
655
0
  for (const wchar_t *path = paths; path && *path; ) {
656
0
    (void)AddDllDirectory(path);
657
0
    path += wcslen(path) + 1;
658
0
  }
659
0
660
0
  result->ImageBase = LoadLibraryExW(name, nullptr,
661
0
                                     LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
662
0
  if (result->ImageBase == nullptr)
663
0
    result->ErrorCode = GetLastError();
664
0
  else
665
0
    result->Length = GetModuleFileNameA(result->ImageBase, result->ModulePath,
666
0
                                        result->Length);
667
0
668
0
  return result->ImageBase;
669
0
}
670
0
}
671
0
  )";
672
673
0
  static constexpr const char kName[] = "__lldb_LoadLibraryHelper";
674
675
0
  ProcessSP process = context.GetProcessSP();
676
0
  Target &target = process->GetTarget();
677
678
0
  auto function = target.CreateUtilityFunction(std::string{kLoaderDecls}, kName,
679
0
                                               eLanguageTypeC_plus_plus,
680
0
                                               context);
681
0
  if (!function) {
682
0
    std::string error = llvm::toString(function.takeError());
683
0
    status.SetErrorStringWithFormat("LoadLibrary error: could not create utility function: %s",
684
0
                                    error.c_str());
685
0
    return nullptr;
686
0
  }
687
688
0
  TypeSystemClangSP scratch_ts_sp =
689
0
      ScratchTypeSystemClang::GetForTarget(target);
690
0
  if (!scratch_ts_sp)
691
0
    return nullptr;
692
693
0
  CompilerType VoidPtrTy =
694
0
      scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
695
0
  CompilerType WCharPtrTy =
696
0
      scratch_ts_sp->GetBasicType(eBasicTypeWChar).GetPointerType();
697
698
0
  ValueList parameters;
699
700
0
  Value value;
701
0
  value.SetValueType(Value::ValueType::Scalar);
702
703
0
  value.SetCompilerType(WCharPtrTy);
704
0
  parameters.PushValue(value);  // name
705
0
  parameters.PushValue(value);  // paths
706
707
0
  value.SetCompilerType(VoidPtrTy);
708
0
  parameters.PushValue(value);  // result
709
710
0
  Status error;
711
0
  std::unique_ptr<UtilityFunction> utility{std::move(*function)};
712
0
  utility->MakeFunctionCaller(VoidPtrTy, parameters, context.GetThreadSP(),
713
0
                              error);
714
0
  if (error.Fail()) {
715
0
    status.SetErrorStringWithFormat("LoadLibrary error: could not create function caller: %s",
716
0
                                    error.AsCString());
717
0
    return nullptr;
718
0
  }
719
720
0
  if (!utility->GetFunctionCaller()) {
721
0
    status.SetErrorString("LoadLibrary error: could not get function caller");
722
0
    return nullptr;
723
0
  }
724
725
0
  return utility;
726
0
}
727
728
Status PlatformWindows::EvaluateLoaderExpression(Process *process,
729
                                                 const char *expression,
730
0
                                                 ValueObjectSP &value) {
731
  // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance?
732
0
  static constexpr const char kLoaderDecls[] = R"(
733
0
extern "C" {
734
0
// libloaderapi.h
735
0
736
0
// WINBASEAPI DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(LPCWSTR);
737
0
/* __declspec(dllimport) */ void * __stdcall AddDllDirectory(const wchar_t *);
738
0
739
0
// WINBASEAPI BOOL WINAPI FreeModule(HMODULE);
740
0
/* __declspec(dllimport) */ int __stdcall FreeModule(void *);
741
0
742
0
// WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE, LPSTR, DWORD);
743
0
/* __declspec(dllimport) */ uint32_t GetModuleFileNameA(void *, char *, uint32_t);
744
0
745
0
// WINBASEAPI HMODULE WINAPI LoadLibraryExW(LPCWSTR, HANDLE, DWORD);
746
0
/* __declspec(dllimport) */ void * __stdcall LoadLibraryExW(const wchar_t *, void *, uint32_t);
747
0
}
748
0
  )";
749
750
0
  if (DynamicLoader *loader = process->GetDynamicLoader()) {
751
0
    Status result = loader->CanLoadImage();
752
0
    if (result.Fail())
753
0
      return result;
754
0
  }
755
756
0
  ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread();
757
0
  if (!thread)
758
0
    return Status("selected thread is invalid");
759
760
0
  StackFrameSP frame = thread->GetStackFrameAtIndex(0);
761
0
  if (!frame)
762
0
    return Status("frame 0 is invalid");
763
764
0
  ExecutionContext context;
765
0
  frame->CalculateExecutionContext(context);
766
767
0
  EvaluateExpressionOptions options;
768
0
  options.SetUnwindOnError(true);
769
0
  options.SetIgnoreBreakpoints(true);
770
0
  options.SetExecutionPolicy(eExecutionPolicyAlways);
771
0
  options.SetLanguage(eLanguageTypeC_plus_plus);
772
  // LoadLibraryEx{A,W}/FreeLibrary cannot raise exceptions which we can handle.
773
  // They may potentially throw SEH exceptions which we do not know how to
774
  // handle currently.
775
0
  options.SetTrapExceptions(false);
776
0
  options.SetTimeout(process->GetUtilityExpressionTimeout());
777
778
0
  Status error;
779
0
  ExpressionResults result = UserExpression::Evaluate(
780
0
      context, options, expression, kLoaderDecls, value, error);
781
0
  if (result != eExpressionCompleted)
782
0
    return error;
783
784
0
  if (value->GetError().Fail())
785
0
    return value->GetError();
786
787
0
  return Status();
788
0
}