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