15ffd83dbSDimitry Andric //===-- PlatformFreeBSD.cpp -----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "PlatformFreeBSD.h"
100b57cec5SDimitry Andric #include "lldb/Host/Config.h"
110b57cec5SDimitry Andric 
12fe6060f1SDimitry Andric #include <cstdio>
13480093f4SDimitry Andric #if LLDB_ENABLE_POSIX
140b57cec5SDimitry Andric #include <sys/utsname.h>
150b57cec5SDimitry Andric #endif
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
180b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointSite.h"
190b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
200b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
210b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
220b57cec5SDimitry Andric #include "lldb/Target/Process.h"
230b57cec5SDimitry Andric #include "lldb/Target/Target.h"
240b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
2581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
260b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
270b57cec5SDimitry Andric #include "lldb/Utility/State.h"
280b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
290b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
300b57cec5SDimitry Andric 
3106c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
3206c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
33e8d8bef9SDimitry Andric 
340b57cec5SDimitry Andric // Define these constants from FreeBSD mman.h for use when targeting remote
350b57cec5SDimitry Andric // FreeBSD systems even when host has different values.
360b57cec5SDimitry Andric #define MAP_PRIVATE 0x0002
370b57cec5SDimitry Andric #define MAP_ANON 0x1000
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace lldb;
400b57cec5SDimitry Andric using namespace lldb_private;
410b57cec5SDimitry Andric using namespace lldb_private::platform_freebsd;
420b57cec5SDimitry Andric 
435ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(PlatformFreeBSD)
445ffd83dbSDimitry Andric 
450b57cec5SDimitry Andric static uint32_t g_initialize_count = 0;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric 
CreateInstance(bool force,const ArchSpec * arch)480b57cec5SDimitry Andric PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
4981ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Platform);
500b57cec5SDimitry Andric   LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
510b57cec5SDimitry Andric            arch ? arch->GetArchitectureName() : "<null>",
520b57cec5SDimitry Andric            arch ? arch->GetTriple().getTriple() : "<null>");
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   bool create = force;
550b57cec5SDimitry Andric   if (!create && arch && arch->IsValid()) {
560b57cec5SDimitry Andric     const llvm::Triple &triple = arch->GetTriple();
570b57cec5SDimitry Andric     switch (triple.getOS()) {
580b57cec5SDimitry Andric     case llvm::Triple::FreeBSD:
590b57cec5SDimitry Andric       create = true;
600b57cec5SDimitry Andric       break;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric #if defined(__FreeBSD__)
630b57cec5SDimitry Andric     // Only accept "unknown" for the OS if the host is BSD and it "unknown"
640b57cec5SDimitry Andric     // wasn't specified (it was just returned because it was NOT specified)
650b57cec5SDimitry Andric     case llvm::Triple::OSType::UnknownOS:
660b57cec5SDimitry Andric       create = !arch->TripleOSWasSpecified();
670b57cec5SDimitry Andric       break;
680b57cec5SDimitry Andric #endif
690b57cec5SDimitry Andric     default:
700b57cec5SDimitry Andric       break;
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric   LLDB_LOG(log, "create = {0}", create);
740b57cec5SDimitry Andric   if (create) {
750b57cec5SDimitry Andric     return PlatformSP(new PlatformFreeBSD(false));
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric   return PlatformSP();
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
GetPluginDescriptionStatic(bool is_host)80349cc55cSDimitry Andric llvm::StringRef PlatformFreeBSD::GetPluginDescriptionStatic(bool is_host) {
810b57cec5SDimitry Andric   if (is_host)
820b57cec5SDimitry Andric     return "Local FreeBSD user platform plug-in.";
830b57cec5SDimitry Andric   return "Remote FreeBSD user platform plug-in.";
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
Initialize()860b57cec5SDimitry Andric void PlatformFreeBSD::Initialize() {
870b57cec5SDimitry Andric   Platform::Initialize();
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   if (g_initialize_count++ == 0) {
900b57cec5SDimitry Andric #if defined(__FreeBSD__)
910b57cec5SDimitry Andric     PlatformSP default_platform_sp(new PlatformFreeBSD(true));
920b57cec5SDimitry Andric     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
930b57cec5SDimitry Andric     Platform::SetHostPlatform(default_platform_sp);
940b57cec5SDimitry Andric #endif
950b57cec5SDimitry Andric     PluginManager::RegisterPlugin(
960b57cec5SDimitry Andric         PlatformFreeBSD::GetPluginNameStatic(false),
970b57cec5SDimitry Andric         PlatformFreeBSD::GetPluginDescriptionStatic(false),
980b57cec5SDimitry Andric         PlatformFreeBSD::CreateInstance, nullptr);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
Terminate()1020b57cec5SDimitry Andric void PlatformFreeBSD::Terminate() {
1030b57cec5SDimitry Andric   if (g_initialize_count > 0) {
1040b57cec5SDimitry Andric     if (--g_initialize_count == 0) {
1050b57cec5SDimitry Andric       PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   PlatformPOSIX::Terminate();
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric /// Default Constructor
PlatformFreeBSD(bool is_host)1130b57cec5SDimitry Andric PlatformFreeBSD::PlatformFreeBSD(bool is_host)
1140b57cec5SDimitry Andric     : PlatformPOSIX(is_host) // This is the local host platform
115349cc55cSDimitry Andric {
116349cc55cSDimitry Andric   if (is_host) {
1170b57cec5SDimitry Andric     ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
118349cc55cSDimitry Andric     m_supported_architectures.push_back(hostArch);
119349cc55cSDimitry Andric     if (hostArch.GetTriple().isArch64Bit()) {
120349cc55cSDimitry Andric       m_supported_architectures.push_back(
121349cc55cSDimitry Andric           HostInfo::GetArchitecture(HostInfo::eArchKind32));
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric   } else {
124349cc55cSDimitry Andric     m_supported_architectures = CreateArchList(
125349cc55cSDimitry Andric         {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::aarch64,
126349cc55cSDimitry Andric          llvm::Triple::arm, llvm::Triple::mips64, llvm::Triple::ppc64,
127349cc55cSDimitry Andric          llvm::Triple::ppc},
128349cc55cSDimitry Andric         llvm::Triple::FreeBSD);
129349cc55cSDimitry Andric   }
130349cc55cSDimitry Andric }
131349cc55cSDimitry Andric 
13281ad6265SDimitry Andric std::vector<ArchSpec>
GetSupportedArchitectures(const ArchSpec & process_host_arch)13381ad6265SDimitry Andric PlatformFreeBSD::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
1340b57cec5SDimitry Andric   if (m_remote_platform_sp)
13581ad6265SDimitry Andric     return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
136349cc55cSDimitry Andric   return m_supported_architectures;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
GetStatus(Stream & strm)1390b57cec5SDimitry Andric void PlatformFreeBSD::GetStatus(Stream &strm) {
1400b57cec5SDimitry Andric   Platform::GetStatus(strm);
1410b57cec5SDimitry Andric 
142480093f4SDimitry Andric #if LLDB_ENABLE_POSIX
1430b57cec5SDimitry Andric   // Display local kernel information only when we are running in host mode.
1440b57cec5SDimitry Andric   // Otherwise, we would end up printing non-FreeBSD information (when running
1450b57cec5SDimitry Andric   // on Mac OS for example).
1460b57cec5SDimitry Andric   if (IsHost()) {
1470b57cec5SDimitry Andric     struct utsname un;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric     if (uname(&un))
1500b57cec5SDimitry Andric       return;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     strm.Printf("    Kernel: %s\n", un.sysname);
1530b57cec5SDimitry Andric     strm.Printf("   Release: %s\n", un.release);
1540b57cec5SDimitry Andric     strm.Printf("   Version: %s\n", un.version);
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric #endif
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
CanDebugProcess()1590b57cec5SDimitry Andric bool PlatformFreeBSD::CanDebugProcess() {
160e8d8bef9SDimitry Andric   if (IsHost()) {
161d409305fSDimitry Andric     return true;
162e8d8bef9SDimitry Andric   } else {
163e8d8bef9SDimitry Andric     // If we're connected, we can debug.
164e8d8bef9SDimitry Andric     return IsConnected();
165e8d8bef9SDimitry Andric   }
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
CalculateTrapHandlerSymbolNames()1680b57cec5SDimitry Andric void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
1690b57cec5SDimitry Andric   m_trap_handlers.push_back(ConstString("_sigtramp"));
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
GetMmapArgumentList(const ArchSpec & arch,addr_t addr,addr_t length,unsigned prot,unsigned flags,addr_t fd,addr_t offset)1720b57cec5SDimitry Andric MmapArgList PlatformFreeBSD::GetMmapArgumentList(const ArchSpec &arch,
1730b57cec5SDimitry Andric                                                  addr_t addr, addr_t length,
1740b57cec5SDimitry Andric                                                  unsigned prot, unsigned flags,
1750b57cec5SDimitry Andric                                                  addr_t fd, addr_t offset) {
1760b57cec5SDimitry Andric   uint64_t flags_platform = 0;
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   if (flags & eMmapFlagsPrivate)
1790b57cec5SDimitry Andric     flags_platform |= MAP_PRIVATE;
1800b57cec5SDimitry Andric   if (flags & eMmapFlagsAnon)
1810b57cec5SDimitry Andric     flags_platform |= MAP_ANON;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   MmapArgList args({addr, length, prot, flags_platform, fd, offset});
1840b57cec5SDimitry Andric   if (arch.GetTriple().getArch() == llvm::Triple::x86)
1850b57cec5SDimitry Andric     args.push_back(0);
1860b57cec5SDimitry Andric   return args;
1870b57cec5SDimitry Andric }
18804eeddc0SDimitry Andric 
GetSiginfoType(const llvm::Triple & triple)18904eeddc0SDimitry Andric CompilerType PlatformFreeBSD::GetSiginfoType(const llvm::Triple &triple) {
190bdd1243dSDimitry Andric   {
191bdd1243dSDimitry Andric     std::lock_guard<std::mutex> guard(m_mutex);
192bdd1243dSDimitry Andric     if (!m_type_system)
193bdd1243dSDimitry Andric       m_type_system = std::make_shared<TypeSystemClang>("siginfo", triple);
194bdd1243dSDimitry Andric   }
195bdd1243dSDimitry Andric   TypeSystemClang *ast = m_type_system.get();
19604eeddc0SDimitry Andric 
19704eeddc0SDimitry Andric   // generic types
19804eeddc0SDimitry Andric   CompilerType int_type = ast->GetBasicType(eBasicTypeInt);
19904eeddc0SDimitry Andric   CompilerType uint_type = ast->GetBasicType(eBasicTypeUnsignedInt);
20004eeddc0SDimitry Andric   CompilerType long_type = ast->GetBasicType(eBasicTypeLong);
20104eeddc0SDimitry Andric   CompilerType voidp_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
20204eeddc0SDimitry Andric 
20304eeddc0SDimitry Andric   // platform-specific types
20404eeddc0SDimitry Andric   CompilerType &pid_type = int_type;
20504eeddc0SDimitry Andric   CompilerType &uid_type = uint_type;
20604eeddc0SDimitry Andric 
20704eeddc0SDimitry Andric   CompilerType sigval_type = ast->CreateRecordType(
20804eeddc0SDimitry Andric       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_sigval_t",
2095f757f3fSDimitry Andric       llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
21004eeddc0SDimitry Andric   ast->StartTagDeclarationDefinition(sigval_type);
21104eeddc0SDimitry Andric   ast->AddFieldToRecordType(sigval_type, "sival_int", int_type,
21204eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
21304eeddc0SDimitry Andric   ast->AddFieldToRecordType(sigval_type, "sival_ptr", voidp_type,
21404eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
21504eeddc0SDimitry Andric   ast->CompleteTagDeclarationDefinition(sigval_type);
21604eeddc0SDimitry Andric 
21704eeddc0SDimitry Andric   // siginfo_t
21804eeddc0SDimitry Andric   CompilerType siginfo_type = ast->CreateRecordType(
21904eeddc0SDimitry Andric       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "__lldb_siginfo_t",
2205f757f3fSDimitry Andric       llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
22104eeddc0SDimitry Andric   ast->StartTagDeclarationDefinition(siginfo_type);
22204eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_signo", int_type,
22304eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
22404eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_errno", int_type,
22504eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
22604eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_code", int_type,
22704eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
22804eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_pid", pid_type,
22904eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
23004eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_uid", uid_type,
23104eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
23204eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_status", int_type,
23304eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
23404eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_addr", voidp_type,
23504eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
23604eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "si_value", sigval_type,
23704eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
23804eeddc0SDimitry Andric 
23904eeddc0SDimitry Andric   // union used to hold the signal data
24004eeddc0SDimitry Andric   CompilerType union_type = ast->CreateRecordType(
24104eeddc0SDimitry Andric       nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "",
2425f757f3fSDimitry Andric       llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
24304eeddc0SDimitry Andric   ast->StartTagDeclarationDefinition(union_type);
24404eeddc0SDimitry Andric 
24504eeddc0SDimitry Andric   ast->AddFieldToRecordType(
24604eeddc0SDimitry Andric       union_type, "_fault",
24706c3fb27SDimitry Andric       ast->CreateStructForIdentifier(llvm::StringRef(),
24804eeddc0SDimitry Andric                                      {
24904eeddc0SDimitry Andric                                          {"_trapno", int_type},
25004eeddc0SDimitry Andric                                      }),
25104eeddc0SDimitry Andric       lldb::eAccessPublic, 0);
25204eeddc0SDimitry Andric 
25304eeddc0SDimitry Andric   ast->AddFieldToRecordType(
25404eeddc0SDimitry Andric       union_type, "_timer",
25506c3fb27SDimitry Andric       ast->CreateStructForIdentifier(llvm::StringRef(),
25604eeddc0SDimitry Andric                                      {
25704eeddc0SDimitry Andric                                          {"_timerid", int_type},
25804eeddc0SDimitry Andric                                          {"_overrun", int_type},
25904eeddc0SDimitry Andric                                      }),
26004eeddc0SDimitry Andric       lldb::eAccessPublic, 0);
26104eeddc0SDimitry Andric 
26204eeddc0SDimitry Andric   ast->AddFieldToRecordType(
26304eeddc0SDimitry Andric       union_type, "_mesgq",
26406c3fb27SDimitry Andric       ast->CreateStructForIdentifier(llvm::StringRef(),
26504eeddc0SDimitry Andric                                      {
26604eeddc0SDimitry Andric                                          {"_mqd", int_type},
26704eeddc0SDimitry Andric                                      }),
26804eeddc0SDimitry Andric       lldb::eAccessPublic, 0);
26904eeddc0SDimitry Andric 
27004eeddc0SDimitry Andric   ast->AddFieldToRecordType(
27104eeddc0SDimitry Andric       union_type, "_poll",
27206c3fb27SDimitry Andric       ast->CreateStructForIdentifier(llvm::StringRef(),
27304eeddc0SDimitry Andric                                      {
27404eeddc0SDimitry Andric                                          {"_band", long_type},
27504eeddc0SDimitry Andric                                      }),
27604eeddc0SDimitry Andric       lldb::eAccessPublic, 0);
27704eeddc0SDimitry Andric 
27804eeddc0SDimitry Andric   ast->CompleteTagDeclarationDefinition(union_type);
27904eeddc0SDimitry Andric   ast->AddFieldToRecordType(siginfo_type, "_reason", union_type,
28004eeddc0SDimitry Andric                             lldb::eAccessPublic, 0);
28104eeddc0SDimitry Andric 
28204eeddc0SDimitry Andric   ast->CompleteTagDeclarationDefinition(siginfo_type);
28304eeddc0SDimitry Andric   return siginfo_type;
28404eeddc0SDimitry Andric }
285