]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
Vendor import of lldb trunk r303197:
[FreeBSD/FreeBSD.git] / source / Plugins / Platform / FreeBSD / PlatformFreeBSD.cpp
1 //===-- PlatformFreeBSD.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PlatformFreeBSD.h"
11 #include "lldb/Host/Config.h"
12
13 // C Includes
14 #include <stdio.h>
15 #ifndef LLDB_DISABLE_POSIX
16 #include <sys/utsname.h>
17 #endif
18
19 // C++ Includes
20 // Other libraries and framework includes
21 // Project includes
22 #include "lldb/Breakpoint/BreakpointLocation.h"
23 #include "lldb/Breakpoint/BreakpointSite.h"
24 #include "lldb/Core/Debugger.h"
25 #include "lldb/Core/PluginManager.h"
26 #include "lldb/Core/State.h"
27 #include "lldb/Host/HostInfo.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/Target.h"
30 #include "lldb/Utility/FileSpec.h"
31 #include "lldb/Utility/Log.h"
32 #include "lldb/Utility/Status.h"
33 #include "lldb/Utility/StreamString.h"
34
35 // Define these constants from FreeBSD mman.h for use when targeting
36 // remote FreeBSD systems even when host has different values.
37 #define MAP_PRIVATE 0x0002
38 #define MAP_ANON 0x1000
39
40 using namespace lldb;
41 using namespace lldb_private;
42 using namespace lldb_private::platform_freebsd;
43
44 static uint32_t g_initialize_count = 0;
45
46 //------------------------------------------------------------------
47
48 PlatformSP PlatformFreeBSD::CreateInstance(bool force, const ArchSpec *arch) {
49   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
50   LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
51            arch ? arch->GetArchitectureName() : "<null>",
52            arch ? arch->GetTriple().getTriple() : "<null>");
53
54   bool create = force;
55   if (create == false && arch && arch->IsValid()) {
56     const llvm::Triple &triple = arch->GetTriple();
57     switch (triple.getOS()) {
58     case llvm::Triple::FreeBSD:
59       create = true;
60       break;
61
62 #if defined(__FreeBSD__)
63     // Only accept "unknown" for the OS if the host is BSD and
64     // it "unknown" wasn't specified (it was just returned because it
65     // was NOT specified)
66     case llvm::Triple::OSType::UnknownOS:
67       create = !arch->TripleOSWasSpecified();
68       break;
69 #endif
70     default:
71       break;
72     }
73   }
74   LLDB_LOG(log, "create = {0}", create);
75   if (create) {
76     return PlatformSP(new PlatformFreeBSD(false));
77   }
78   return PlatformSP();
79 }
80
81 ConstString PlatformFreeBSD::GetPluginNameStatic(bool is_host) {
82   if (is_host) {
83     static ConstString g_host_name(Platform::GetHostPlatformName());
84     return g_host_name;
85   } else {
86     static ConstString g_remote_name("remote-freebsd");
87     return g_remote_name;
88   }
89 }
90
91 const char *PlatformFreeBSD::GetPluginDescriptionStatic(bool is_host) {
92   if (is_host)
93     return "Local FreeBSD user platform plug-in.";
94   else
95     return "Remote FreeBSD user platform plug-in.";
96 }
97
98 ConstString PlatformFreeBSD::GetPluginName() {
99   return GetPluginNameStatic(IsHost());
100 }
101
102 void PlatformFreeBSD::Initialize() {
103   Platform::Initialize();
104
105   if (g_initialize_count++ == 0) {
106 #if defined(__FreeBSD__)
107     PlatformSP default_platform_sp(new PlatformFreeBSD(true));
108     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
109     Platform::SetHostPlatform(default_platform_sp);
110 #endif
111     PluginManager::RegisterPlugin(
112         PlatformFreeBSD::GetPluginNameStatic(false),
113         PlatformFreeBSD::GetPluginDescriptionStatic(false),
114         PlatformFreeBSD::CreateInstance, nullptr);
115   }
116 }
117
118 void PlatformFreeBSD::Terminate() {
119   if (g_initialize_count > 0) {
120     if (--g_initialize_count == 0) {
121       PluginManager::UnregisterPlugin(PlatformFreeBSD::CreateInstance);
122     }
123   }
124
125   PlatformPOSIX::Terminate();
126 }
127
128 //------------------------------------------------------------------
129 /// Default Constructor
130 //------------------------------------------------------------------
131 PlatformFreeBSD::PlatformFreeBSD(bool is_host)
132     : PlatformPOSIX(is_host) // This is the local host platform
133 {}
134
135 PlatformFreeBSD::~PlatformFreeBSD() = default;
136
137 bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
138                                                       ArchSpec &arch) {
139   if (IsHost()) {
140     ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
141     if (hostArch.GetTriple().isOSFreeBSD()) {
142       if (idx == 0) {
143         arch = hostArch;
144         return arch.IsValid();
145       } else if (idx == 1) {
146         // If the default host architecture is 64-bit, look for a 32-bit variant
147         if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) {
148           arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
149           return arch.IsValid();
150         }
151       }
152     }
153   } else {
154     if (m_remote_platform_sp)
155       return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
156
157     llvm::Triple triple;
158     // Set the OS to FreeBSD
159     triple.setOS(llvm::Triple::FreeBSD);
160     // Set the architecture
161     switch (idx) {
162     case 0:
163       triple.setArchName("x86_64");
164       break;
165     case 1:
166       triple.setArchName("i386");
167       break;
168     case 2:
169       triple.setArchName("aarch64");
170       break;
171     case 3:
172       triple.setArchName("arm");
173       break;
174     case 4:
175       triple.setArchName("mips64");
176       break;
177     case 5:
178       triple.setArchName("mips");
179       break;
180     case 6:
181       triple.setArchName("ppc64");
182       break;
183     case 7:
184       triple.setArchName("ppc");
185       break;
186     default:
187       return false;
188     }
189     // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the
190     // vendor by
191     // calling triple.SetVendorName("unknown") so that it is a "unspecified
192     // unknown".
193     // This means when someone calls triple.GetVendorName() it will return an
194     // empty string
195     // which indicates that the vendor can be set when two architectures are
196     // merged
197
198     // Now set the triple into "arch" and return true
199     arch.SetTriple(triple);
200     return true;
201   }
202   return false;
203 }
204
205 void PlatformFreeBSD::GetStatus(Stream &strm) {
206   Platform::GetStatus(strm);
207
208 #ifndef LLDB_DISABLE_POSIX
209   // Display local kernel information only when we are running in host mode.
210   // Otherwise, we would end up printing non-FreeBSD information (when running
211   // on Mac OS for example).
212   if (IsHost()) {
213     struct utsname un;
214
215     if (uname(&un))
216       return;
217
218     strm.Printf("    Kernel: %s\n", un.sysname);
219     strm.Printf("   Release: %s\n", un.release);
220     strm.Printf("   Version: %s\n", un.version);
221   }
222 #endif
223 }
224
225 size_t
226 PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target,
227                                                  BreakpointSite *bp_site) {
228   switch (target.GetArchitecture().GetMachine()) {
229   case llvm::Triple::arm: {
230     lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0));
231     AddressClass addr_class = eAddressClassUnknown;
232
233     if (bp_loc_sp) {
234       addr_class = bp_loc_sp->GetAddress().GetAddressClass();
235       if (addr_class == eAddressClassUnknown &&
236           (bp_loc_sp->GetAddress().GetFileAddress() & 1))
237         addr_class = eAddressClassCodeAlternateISA;
238     }
239
240     if (addr_class == eAddressClassCodeAlternateISA) {
241       // TODO: Enable when FreeBSD supports thumb breakpoints.
242       // FreeBSD kernel as of 10.x, does not support thumb breakpoints
243       return 0;
244     }
245
246     static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7};
247     size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
248     assert(bp_site);
249     if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size))
250       return trap_opcode_size;
251   }
252     LLVM_FALLTHROUGH;
253   default:
254     return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
255   }
256 }
257
258 Status PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
259   Status error;
260   if (IsHost()) {
261     error = Platform::LaunchProcess(launch_info);
262   } else {
263     if (m_remote_platform_sp)
264       error = m_remote_platform_sp->LaunchProcess(launch_info);
265     else
266       error.SetErrorString("the platform is not currently connected");
267   }
268   return error;
269 }
270
271 lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
272                                         Debugger &debugger, Target *target,
273                                         Status &error) {
274   lldb::ProcessSP process_sp;
275   if (IsHost()) {
276     if (target == NULL) {
277       TargetSP new_target_sp;
278       ArchSpec emptyArchSpec;
279
280       error = debugger.GetTargetList().CreateTarget(debugger, "", emptyArchSpec,
281                                                     false, m_remote_platform_sp,
282                                                     new_target_sp);
283       target = new_target_sp.get();
284     } else
285       error.Clear();
286
287     if (target && error.Success()) {
288       debugger.GetTargetList().SetSelectedTarget(target);
289       // The freebsd always currently uses the GDB remote debugger plug-in
290       // so even when debugging locally we are debugging remotely!
291       // Just like the darwin plugin.
292       process_sp = target->CreateProcess(
293           attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
294
295       if (process_sp)
296         error = process_sp->Attach(attach_info);
297     }
298   } else {
299     if (m_remote_platform_sp)
300       process_sp =
301           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
302     else
303       error.SetErrorString("the platform is not currently connected");
304   }
305   return process_sp;
306 }
307
308 // FreeBSD processes cannot yet be launched by spawning and attaching.
309 bool PlatformFreeBSD::CanDebugProcess() {
310   return false;
311 }
312
313 void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
314   m_trap_handlers.push_back(ConstString("_sigtramp"));
315 }
316
317 uint64_t PlatformFreeBSD::ConvertMmapFlagsToPlatform(const ArchSpec &arch,
318                                                      unsigned flags) {
319   uint64_t flags_platform = 0;
320
321   if (flags & eMmapFlagsPrivate)
322     flags_platform |= MAP_PRIVATE;
323   if (flags & eMmapFlagsAnon)
324     flags_platform |= MAP_ANON;
325   return flags_platform;
326 }