1//===-- PlatformNetBSD.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 "PlatformNetBSD.h"
10#include "lldb/Host/Config.h"
11
12#include <cstdio>
13#if LLDB_ENABLE_POSIX
14#include <sys/utsname.h>
15#endif
16
17#include "lldb/Core/Debugger.h"
18#include "lldb/Core/PluginManager.h"
19#include "lldb/Host/HostInfo.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Utility/FileSpec.h"
23#include "lldb/Utility/LLDBLog.h"
24#include "lldb/Utility/Log.h"
25#include "lldb/Utility/State.h"
26#include "lldb/Utility/Status.h"
27#include "lldb/Utility/StreamString.h"
28
29// Define these constants from NetBSD mman.h for use when targeting remote
30// netbsd systems even when host has different values.
31#define MAP_PRIVATE 0x0002
32#define MAP_ANON 0x1000
33
34using namespace lldb;
35using namespace lldb_private;
36using namespace lldb_private::platform_netbsd;
37
38LLDB_PLUGIN_DEFINE(PlatformNetBSD)
39
40static uint32_t g_initialize_count = 0;
41
42
43PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) {
44  Log *log = GetLog(LLDBLog::Platform);
45  LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
46           arch ? arch->GetArchitectureName() : "<null>",
47           arch ? arch->GetTriple().getTriple() : "<null>");
48
49  bool create = force;
50  if (!create && arch && arch->IsValid()) {
51    const llvm::Triple &triple = arch->GetTriple();
52    switch (triple.getOS()) {
53    case llvm::Triple::NetBSD:
54      create = true;
55      break;
56
57    default:
58      break;
59    }
60  }
61
62  LLDB_LOG(log, "create = {0}", create);
63  if (create) {
64    return PlatformSP(new PlatformNetBSD(false));
65  }
66  return PlatformSP();
67}
68
69llvm::StringRef PlatformNetBSD::GetPluginDescriptionStatic(bool is_host) {
70  if (is_host)
71    return "Local NetBSD user platform plug-in.";
72  return "Remote NetBSD user platform plug-in.";
73}
74
75void PlatformNetBSD::Initialize() {
76  PlatformPOSIX::Initialize();
77
78  if (g_initialize_count++ == 0) {
79#if defined(__NetBSD__)
80    PlatformSP default_platform_sp(new PlatformNetBSD(true));
81    default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
82    Platform::SetHostPlatform(default_platform_sp);
83#endif
84    PluginManager::RegisterPlugin(
85        PlatformNetBSD::GetPluginNameStatic(false),
86        PlatformNetBSD::GetPluginDescriptionStatic(false),
87        PlatformNetBSD::CreateInstance, nullptr);
88  }
89}
90
91void PlatformNetBSD::Terminate() {
92  if (g_initialize_count > 0) {
93    if (--g_initialize_count == 0) {
94      PluginManager::UnregisterPlugin(PlatformNetBSD::CreateInstance);
95    }
96  }
97
98  PlatformPOSIX::Terminate();
99}
100
101/// Default Constructor
102PlatformNetBSD::PlatformNetBSD(bool is_host)
103    : PlatformPOSIX(is_host) // This is the local host platform
104{
105  if (is_host) {
106    ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
107    m_supported_architectures.push_back(hostArch);
108    if (hostArch.GetTriple().isArch64Bit()) {
109      m_supported_architectures.push_back(
110          HostInfo::GetArchitecture(HostInfo::eArchKind32));
111    }
112  } else {
113    m_supported_architectures = CreateArchList(
114        {llvm::Triple::x86_64, llvm::Triple::x86}, llvm::Triple::NetBSD);
115  }
116}
117
118std::vector<ArchSpec>
119PlatformNetBSD::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
120  if (m_remote_platform_sp)
121    return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
122  return m_supported_architectures;
123}
124
125void PlatformNetBSD::GetStatus(Stream &strm) {
126  Platform::GetStatus(strm);
127
128#if LLDB_ENABLE_POSIX
129  // Display local kernel information only when we are running in host mode.
130  // Otherwise, we would end up printing non-NetBSD information (when running
131  // on Mac OS for example).
132  if (IsHost()) {
133    struct utsname un;
134
135    if (uname(&un))
136      return;
137
138    strm.Printf("    Kernel: %s\n", un.sysname);
139    strm.Printf("   Release: %s\n", un.release);
140    strm.Printf("   Version: %s\n", un.version);
141  }
142#endif
143}
144
145uint32_t
146PlatformNetBSD::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
147  uint32_t resume_count = 0;
148
149  // Always resume past the initial stop when we use eLaunchFlagDebug
150  if (launch_info.GetFlags().Test(eLaunchFlagDebug)) {
151    // Resume past the stop for the final exec into the true inferior.
152    ++resume_count;
153  }
154
155  // If we're not launching a shell, we're done.
156  const FileSpec &shell = launch_info.GetShell();
157  if (!shell)
158    return resume_count;
159
160  std::string shell_string = shell.GetPath();
161  // We're in a shell, so for sure we have to resume past the shell exec.
162  ++resume_count;
163
164  // Figure out what shell we're planning on using.
165  const char *shell_name = strrchr(shell_string.c_str(), '/');
166  if (shell_name == nullptr)
167    shell_name = shell_string.c_str();
168  else
169    shell_name++;
170
171  if (strcmp(shell_name, "csh") == 0 || strcmp(shell_name, "tcsh") == 0 ||
172      strcmp(shell_name, "zsh") == 0 || strcmp(shell_name, "sh") == 0) {
173    // These shells seem to re-exec themselves.  Add another resume.
174    ++resume_count;
175  }
176
177  return resume_count;
178}
179
180bool PlatformNetBSD::CanDebugProcess() {
181  if (IsHost()) {
182    return true;
183  } else {
184    // If we're connected, we can debug.
185    return IsConnected();
186  }
187}
188
189void PlatformNetBSD::CalculateTrapHandlerSymbolNames() {
190  m_trap_handlers.push_back(ConstString("_sigtramp"));
191}
192
193MmapArgList PlatformNetBSD::GetMmapArgumentList(const ArchSpec &arch,
194                                                addr_t addr, addr_t length,
195                                                unsigned prot, unsigned flags,
196                                                addr_t fd, addr_t offset) {
197  uint64_t flags_platform = 0;
198
199  if (flags & eMmapFlagsPrivate)
200    flags_platform |= MAP_PRIVATE;
201  if (flags & eMmapFlagsAnon)
202    flags_platform |= MAP_ANON;
203
204  MmapArgList args({addr, length, prot, flags_platform, fd, offset});
205  return args;
206}
207
208CompilerType PlatformNetBSD::GetSiginfoType(const llvm::Triple &triple) {
209  {
210    std::lock_guard<std::mutex> guard(m_mutex);
211    if (!m_type_system)
212      m_type_system = std::make_shared<TypeSystemClang>("siginfo", triple);
213  }
214  TypeSystemClang *ast = m_type_system.get();
215
216  // generic types
217  CompilerType int_type = ast->GetBasicType(eBasicTypeInt);
218  CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt);
219  CompilerType long_type = ast->GetBasicType(eBasicTypeLong);
220  CompilerType long_long_type = ast->GetBasicType(eBasicTypeLongLong);
221  CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
222
223  // platform-specific types
224  CompilerType &pid_type = int_type;
225  CompilerType &uid_type = uint_type;
226  CompilerType &clock_type = uint_type;
227  CompilerType &lwpid_type = int_type;
228
229  CompilerType sigval_type = ast->CreateRecordType(
230      nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t",
231      llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
232  ast->StartTagDeclarationDefinition(sigval_type);
233  ast->AddFieldToRecordType(sigval_type, "sival_int", int_type,
234                            lldb::eAccessPublic, 0);
235  ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type,
236                            lldb::eAccessPublic, 0);
237  ast->CompleteTagDeclarationDefinition(sigval_type);
238
239  CompilerType ptrace_option_type = ast->CreateRecordType(
240      nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
241      llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
242  ast->StartTagDeclarationDefinition(ptrace_option_type);
243  ast->AddFieldToRecordType(ptrace_option_type, "_pe_other_pid", pid_type,
244                            lldb::eAccessPublic, 0);
245  ast->AddFieldToRecordType(ptrace_option_type, "_pe_lwp", lwpid_type,
246                            lldb::eAccessPublic, 0);
247  ast->CompleteTagDeclarationDefinition(ptrace_option_type);
248
249  // siginfo_t
250  CompilerType siginfo_type = ast->CreateRecordType(
251      nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t",
252      llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
253  ast->StartTagDeclarationDefinition(siginfo_type);
254
255  // struct _ksiginfo
256  CompilerType ksiginfo_type = ast->CreateRecordType(
257      nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
258      llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
259  ast->StartTagDeclarationDefinition(ksiginfo_type);
260  ast->AddFieldToRecordType(ksiginfo_type, "_signo", int_type,
261                            lldb::eAccessPublic, 0);
262  ast->AddFieldToRecordType(ksiginfo_type, "_code", int_type,
263                            lldb::eAccessPublic, 0);
264  ast->AddFieldToRecordType(ksiginfo_type, "_errno", int_type,
265                            lldb::eAccessPublic, 0);
266
267  // the structure is padded on 64-bit arches to fix alignment
268  if (triple.isArch64Bit())
269    ast->AddFieldToRecordType(ksiginfo_type, "__pad0", int_type,
270                              lldb::eAccessPublic, 0);
271
272  // union used to hold the signal data
273  CompilerType union_type = ast->CreateRecordType(
274      nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
275      llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
276  ast->StartTagDeclarationDefinition(union_type);
277
278  ast->AddFieldToRecordType(
279      union_type, "_rt",
280      ast->CreateStructForIdentifier(llvm::StringRef(),
281                                     {
282                                         {"_pid", pid_type},
283                                         {"_uid", uid_type},
284                                         {"_value", sigval_type},
285                                     }),
286      lldb::eAccessPublic, 0);
287
288  ast->AddFieldToRecordType(
289      union_type, "_child",
290      ast->CreateStructForIdentifier(llvm::StringRef(),
291                                     {
292                                         {"_pid", pid_type},
293                                         {"_uid", uid_type},
294                                         {"_status", int_type},
295                                         {"_utime", clock_type},
296                                         {"_stime", clock_type},
297                                     }),
298      lldb::eAccessPublic, 0);
299
300  ast->AddFieldToRecordType(
301      union_type, "_fault",
302      ast->CreateStructForIdentifier(llvm::StringRef(),
303                                     {
304                                         {"_addr", voidp_type},
305                                         {"_trap", int_type},
306                                         {"_trap2", int_type},
307                                         {"_trap3", int_type},
308                                     }),
309      lldb::eAccessPublic, 0);
310
311  ast->AddFieldToRecordType(
312      union_type, "_poll",
313      ast->CreateStructForIdentifier(llvm::StringRef(),
314                                     {
315                                         {"_band", long_type},
316                                         {"_fd", int_type},
317                                     }),
318      lldb::eAccessPublic, 0);
319
320  ast->AddFieldToRecordType(union_type, "_syscall",
321                            ast->CreateStructForIdentifier(
322                                llvm::StringRef(),
323                                {
324                                    {"_sysnum", int_type},
325                                    {"_retval", int_type.GetArrayType(2)},
326                                    {"_error", int_type},
327                                    {"_args", long_long_type.GetArrayType(8)},
328                                }),
329                            lldb::eAccessPublic, 0);
330
331  ast->AddFieldToRecordType(
332      union_type, "_ptrace_state",
333      ast->CreateStructForIdentifier(llvm::StringRef(),
334                                     {
335                                         {"_pe_report_event", int_type},
336                                         {"_option", ptrace_option_type},
337                                     }),
338      lldb::eAccessPublic, 0);
339
340  ast->CompleteTagDeclarationDefinition(union_type);
341  ast->AddFieldToRecordType(ksiginfo_type, "_reason", union_type,
342                            lldb::eAccessPublic, 0);
343
344  ast->CompleteTagDeclarationDefinition(ksiginfo_type);
345  ast->AddFieldToRecordType(siginfo_type, "_info", ksiginfo_type,
346                            lldb::eAccessPublic, 0);
347
348  ast->CompleteTagDeclarationDefinition(siginfo_type);
349  return siginfo_type;
350}
351