1dda28197Spatrick //===-- PlatformFreeBSD.cpp -----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "PlatformFreeBSD.h"
10061da546Spatrick #include "lldb/Host/Config.h"
11061da546Spatrick 
12be691f3bSpatrick #include <cstdio>
13061da546Spatrick #if LLDB_ENABLE_POSIX
14061da546Spatrick #include <sys/utsname.h>
15061da546Spatrick #endif
16061da546Spatrick 
17061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
18061da546Spatrick #include "lldb/Breakpoint/BreakpointSite.h"
19061da546Spatrick #include "lldb/Core/Debugger.h"
20061da546Spatrick #include "lldb/Core/PluginManager.h"
21061da546Spatrick #include "lldb/Host/HostInfo.h"
22061da546Spatrick #include "lldb/Target/Process.h"
23061da546Spatrick #include "lldb/Target/Target.h"
24061da546Spatrick #include "lldb/Utility/FileSpec.h"
25*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
26061da546Spatrick #include "lldb/Utility/Log.h"
27061da546Spatrick #include "lldb/Utility/State.h"
28061da546Spatrick #include "lldb/Utility/Status.h"
29061da546Spatrick #include "lldb/Utility/StreamString.h"
30061da546Spatrick 
31be691f3bSpatrick #include "llvm/ADT/Triple.h"
32be691f3bSpatrick #include "llvm/Support/Host.h"
33be691f3bSpatrick 
34061da546Spatrick // Define these constants from FreeBSD mman.h for use when targeting remote
35061da546Spatrick // FreeBSD systems even when host has different values.
36061da546Spatrick #define MAP_PRIVATE 0x0002
37061da546Spatrick #define MAP_ANON 0x1000
38061da546Spatrick 
39061da546Spatrick using namespace lldb;
40061da546Spatrick using namespace lldb_private;
41061da546Spatrick using namespace lldb_private::platform_freebsd;
42061da546Spatrick 
43dda28197Spatrick LLDB_PLUGIN_DEFINE(PlatformFreeBSD)
44dda28197Spatrick 
45061da546Spatrick static uint32_t g_initialize_count = 0;
46061da546Spatrick 
47061da546Spatrick 
CreateInstance(bool force,const ArchSpec * arch)48061da546Spatrick PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
49*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Platform);
50061da546Spatrick   LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
51061da546Spatrick            arch ? arch->GetArchitectureName() : "<null>",
52061da546Spatrick            arch ? arch->GetTriple().getTriple() : "<null>");
53061da546Spatrick 
54061da546Spatrick   bool create = force;
55061da546Spatrick   if (!create && arch && arch->IsValid()) {
56061da546Spatrick     const llvm::Triple &triple = arch->GetTriple();
57061da546Spatrick     switch (triple.getOS()) {
58061da546Spatrick     case llvm::Triple::FreeBSD:
59061da546Spatrick       create = true;
60061da546Spatrick       break;
61061da546Spatrick 
62061da546Spatrick #if defined(__FreeBSD__)
63061da546Spatrick     // Only accept "unknown" for the OS if the host is BSD and it "unknown"
64061da546Spatrick     // wasn't specified (it was just returned because it was NOT specified)
65061da546Spatrick     case llvm::Triple::OSType::UnknownOS:
66061da546Spatrick       create = !arch->TripleOSWasSpecified();
67061da546Spatrick       break;
68061da546Spatrick #endif
69061da546Spatrick     default:
70061da546Spatrick       break;
71061da546Spatrick     }
72061da546Spatrick   }
73061da546Spatrick   LLDB_LOG(log, "create = {0}", create);
74061da546Spatrick   if (create) {
75061da546Spatrick     return PlatformSP(new PlatformFreeBSD(false));
76061da546Spatrick   }
77061da546Spatrick   return PlatformSP();
78061da546Spatrick }
79061da546Spatrick 
GetPluginDescriptionStatic(bool is_host)80*f6aab3d8Srobert llvm::StringRef PlatformFreeBSD::GetPluginDescriptionStatic(bool is_host) {
81061da546Spatrick   if (is_host)
82061da546Spatrick     return "Local FreeBSD user platform plug-in.";
83061da546Spatrick   return "Remote FreeBSD user platform plug-in.";
84061da546Spatrick }
85061da546Spatrick 
Initialize()86061da546Spatrick void PlatformFreeBSD::Initialize() {
87061da546Spatrick   Platform::Initialize();
88061da546Spatrick 
89061da546Spatrick   if (g_initialize_count++ == 0) {
90061da546Spatrick #if defined(__FreeBSD__)
91061da546Spatrick     PlatformSP default_platform_sp(new PlatformFreeBSD(true));
92061da546Spatrick     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
93061da546Spatrick     Platform::SetHostPlatform(default_platform_sp);
94061da546Spatrick #endif
95061da546Spatrick     PluginManager::RegisterPlugin(
96061da546Spatrick         PlatformFreeBSD::GetPluginNameStatic(false),
97061da546Spatrick         PlatformFreeBSD::GetPluginDescriptionStatic(false),
98061da546Spatrick         PlatformFreeBSD::CreateInstance, nullptr);
99061da546Spatrick   }
100061da546Spatrick }
101061da546Spatrick 
Terminate()102061da546Spatrick void PlatformFreeBSD::Terminate() {
103061da546Spatrick   if (g_initialize_count > 0) {
104061da546Spatrick     if (--g_initialize_count == 0) {
105061da546Spatrick       PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
106061da546Spatrick     }
107061da546Spatrick   }
108061da546Spatrick 
109061da546Spatrick   PlatformPOSIX::Terminate();
110061da546Spatrick }
111061da546Spatrick 
112061da546Spatrick /// Default Constructor
PlatformFreeBSD(bool is_host)113061da546Spatrick PlatformFreeBSD::PlatformFreeBSD(bool is_host)
114061da546Spatrick     : PlatformPOSIX(is_host) // This is the local host platform
115*f6aab3d8Srobert {
116*f6aab3d8Srobert   if (is_host) {
117061da546Spatrick     ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
118*f6aab3d8Srobert     m_supported_architectures.push_back(hostArch);
119*f6aab3d8Srobert     if (hostArch.GetTriple().isArch64Bit()) {
120*f6aab3d8Srobert       m_supported_architectures.push_back(
121*f6aab3d8Srobert           HostInfo::GetArchitecture(HostInfo::eArchKind32));
122061da546Spatrick     }
123061da546Spatrick   } else {
124*f6aab3d8Srobert     m_supported_architectures = CreateArchList(
125*f6aab3d8Srobert         {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::aarch64,
126*f6aab3d8Srobert          llvm::Triple::arm, llvm::Triple::mips64, llvm::Triple::ppc64,
127*f6aab3d8Srobert          llvm::Triple::ppc},
128*f6aab3d8Srobert         llvm::Triple::FreeBSD);
129*f6aab3d8Srobert   }
130*f6aab3d8Srobert }
131*f6aab3d8Srobert 
132*f6aab3d8Srobert std::vector<ArchSpec>
GetSupportedArchitectures(const ArchSpec & process_host_arch)133*f6aab3d8Srobert PlatformFreeBSD::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
134061da546Spatrick   if (m_remote_platform_sp)
135*f6aab3d8Srobert     return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
136*f6aab3d8Srobert   return m_supported_architectures;
137061da546Spatrick }
138061da546Spatrick 
GetStatus(Stream & strm)139061da546Spatrick void PlatformFreeBSD::GetStatus(Stream &strm) {
140061da546Spatrick   Platform::GetStatus(strm);
141061da546Spatrick 
142061da546Spatrick #if LLDB_ENABLE_POSIX
143061da546Spatrick   // Display local kernel information only when we are running in host mode.
144061da546Spatrick   // Otherwise, we would end up printing non-FreeBSD information (when running
145061da546Spatrick   // on Mac OS for example).
146061da546Spatrick   if (IsHost()) {
147061da546Spatrick     struct utsname un;
148061da546Spatrick 
149061da546Spatrick     if (uname(&un))
150061da546Spatrick       return;
151061da546Spatrick 
152061da546Spatrick     strm.Printf("    Kernel: %s\n", un.sysname);
153061da546Spatrick     strm.Printf("   Release: %s\n", un.release);
154061da546Spatrick     strm.Printf("   Version: %s\n", un.version);
155061da546Spatrick   }
156061da546Spatrick #endif
157061da546Spatrick }
158061da546Spatrick 
CanDebugProcess()159061da546Spatrick bool PlatformFreeBSD::CanDebugProcess() {
160be691f3bSpatrick   if (IsHost()) {
161be691f3bSpatrick     return true;
162be691f3bSpatrick   } else {
163be691f3bSpatrick     // If we're connected, we can debug.
164be691f3bSpatrick     return IsConnected();
165be691f3bSpatrick   }
166061da546Spatrick }
167061da546Spatrick 
CalculateTrapHandlerSymbolNames()168061da546Spatrick void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
169061da546Spatrick   m_trap_handlers.push_back(ConstString("_sigtramp"));
170061da546Spatrick }
171061da546Spatrick 
GetMmapArgumentList(const ArchSpec & arch,addr_t addr,addr_t length,unsigned prot,unsigned flags,addr_t fd,addr_t offset)172061da546Spatrick MmapArgList PlatformFreeBSD::GetMmapArgumentList(const ArchSpec &arch,
173061da546Spatrick                                                  addr_t addr, addr_t length,
174061da546Spatrick                                                  unsigned prot, unsigned flags,
175061da546Spatrick                                                  addr_t fd, addr_t offset) {
176061da546Spatrick   uint64_t flags_platform = 0;
177061da546Spatrick 
178061da546Spatrick   if (flags & eMmapFlagsPrivate)
179061da546Spatrick     flags_platform |= MAP_PRIVATE;
180061da546Spatrick   if (flags & eMmapFlagsAnon)
181061da546Spatrick     flags_platform |= MAP_ANON;
182061da546Spatrick 
183061da546Spatrick   MmapArgList args({addr, length, prot, flags_platform, fd, offset});
184061da546Spatrick   if (arch.GetTriple().getArch() == llvm::Triple::x86)
185061da546Spatrick     args.push_back(0);
186061da546Spatrick   return args;
187061da546Spatrick }
188*f6aab3d8Srobert 
GetSiginfoType(const llvm::Triple & triple)189*f6aab3d8Srobert CompilerType PlatformFreeBSD::GetSiginfoType(const llvm::Triple &triple) {
190*f6aab3d8Srobert   {
191*f6aab3d8Srobert     std::lock_guard<std::mutex> guard(m_mutex);
192*f6aab3d8Srobert     if (!m_type_system)
193*f6aab3d8Srobert       m_type_system = std::make_shared<TypeSystemClang>("siginfo", triple);
194*f6aab3d8Srobert   }
195*f6aab3d8Srobert   TypeSystemClang *ast = m_type_system.get();
196*f6aab3d8Srobert 
197*f6aab3d8Srobert   // generic types
198*f6aab3d8Srobert   CompilerType int_type = ast->GetBasicType(eBasicTypeInt);
199*f6aab3d8Srobert   CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt);
200*f6aab3d8Srobert   CompilerType long_type = ast->GetBasicType(eBasicTypeLong);
201*f6aab3d8Srobert   CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
202*f6aab3d8Srobert 
203*f6aab3d8Srobert   // platform-specific types
204*f6aab3d8Srobert   CompilerType &pid_type = int_type;
205*f6aab3d8Srobert   CompilerType &uid_type = uint_type;
206*f6aab3d8Srobert 
207*f6aab3d8Srobert   CompilerType sigval_type = ast->CreateRecordType(
208*f6aab3d8Srobert       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t",
209*f6aab3d8Srobert       clang::TTK_Union, lldb::eLanguageTypeC);
210*f6aab3d8Srobert   ast->StartTagDeclarationDefinition(sigval_type);
211*f6aab3d8Srobert   ast->AddFieldToRecordType(sigval_type, "sival_int", int_type,
212*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
213*f6aab3d8Srobert   ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type,
214*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
215*f6aab3d8Srobert   ast->CompleteTagDeclarationDefinition(sigval_type);
216*f6aab3d8Srobert 
217*f6aab3d8Srobert   // siginfo_t
218*f6aab3d8Srobert   CompilerType siginfo_type = ast->CreateRecordType(
219*f6aab3d8Srobert       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t",
220*f6aab3d8Srobert       clang::TTK_Struct, lldb::eLanguageTypeC);
221*f6aab3d8Srobert   ast->StartTagDeclarationDefinition(siginfo_type);
222*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type,
223*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
224*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,
225*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
226*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,
227*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
228*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_pid", pid_type,
229*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
230*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_uid", uid_type,
231*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
232*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_status", int_type,
233*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
234*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_addr", voidp_type,
235*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
236*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "si_value", sigval_type,
237*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
238*f6aab3d8Srobert 
239*f6aab3d8Srobert   // union used to hold the signal data
240*f6aab3d8Srobert   CompilerType union_type = ast->CreateRecordType(
241*f6aab3d8Srobert       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
242*f6aab3d8Srobert       clang::TTK_Union, lldb::eLanguageTypeC);
243*f6aab3d8Srobert   ast->StartTagDeclarationDefinition(union_type);
244*f6aab3d8Srobert 
245*f6aab3d8Srobert   ast->AddFieldToRecordType(
246*f6aab3d8Srobert       union_type, "_fault",
247*f6aab3d8Srobert       ast->CreateStructForIdentifier(ConstString(),
248*f6aab3d8Srobert                                      {
249*f6aab3d8Srobert                                          {"_trapno", int_type},
250*f6aab3d8Srobert                                      }),
251*f6aab3d8Srobert       lldb::eAccessPublic, 0);
252*f6aab3d8Srobert 
253*f6aab3d8Srobert   ast->AddFieldToRecordType(
254*f6aab3d8Srobert       union_type, "_timer",
255*f6aab3d8Srobert       ast->CreateStructForIdentifier(ConstString(),
256*f6aab3d8Srobert                                      {
257*f6aab3d8Srobert                                          {"_timerid", int_type},
258*f6aab3d8Srobert                                          {"_overrun", int_type},
259*f6aab3d8Srobert                                      }),
260*f6aab3d8Srobert       lldb::eAccessPublic, 0);
261*f6aab3d8Srobert 
262*f6aab3d8Srobert   ast->AddFieldToRecordType(
263*f6aab3d8Srobert       union_type, "_mesgq",
264*f6aab3d8Srobert       ast->CreateStructForIdentifier(ConstString(),
265*f6aab3d8Srobert                                      {
266*f6aab3d8Srobert                                          {"_mqd", int_type},
267*f6aab3d8Srobert                                      }),
268*f6aab3d8Srobert       lldb::eAccessPublic, 0);
269*f6aab3d8Srobert 
270*f6aab3d8Srobert   ast->AddFieldToRecordType(
271*f6aab3d8Srobert       union_type, "_poll",
272*f6aab3d8Srobert       ast->CreateStructForIdentifier(ConstString(),
273*f6aab3d8Srobert                                      {
274*f6aab3d8Srobert                                          {"_band", long_type},
275*f6aab3d8Srobert                                      }),
276*f6aab3d8Srobert       lldb::eAccessPublic, 0);
277*f6aab3d8Srobert 
278*f6aab3d8Srobert   ast->CompleteTagDeclarationDefinition(union_type);
279*f6aab3d8Srobert   ast->AddFieldToRecordType(siginfo_type, "_reason", union_type,
280*f6aab3d8Srobert                             lldb::eAccessPublic, 0);
281*f6aab3d8Srobert 
282*f6aab3d8Srobert   ast->CompleteTagDeclarationDefinition(siginfo_type);
283*f6aab3d8Srobert   return siginfo_type;
284*f6aab3d8Srobert }
285