197a14e60SZachary Turner //===-- HostInfoLinux.cpp ---------------------------------------*- C++ -*-===// 297a14e60SZachary Turner // 397a14e60SZachary Turner // The LLVM Compiler Infrastructure 497a14e60SZachary Turner // 597a14e60SZachary Turner // This file is distributed under the University of Illinois Open Source 697a14e60SZachary Turner // License. See LICENSE.TXT for details. 797a14e60SZachary Turner // 897a14e60SZachary Turner //===----------------------------------------------------------------------===// 997a14e60SZachary Turner 1097a14e60SZachary Turner #include "lldb/Core/Log.h" 1197a14e60SZachary Turner #include "lldb/Host/linux/HostInfoLinux.h" 1297a14e60SZachary Turner 13e47ffc3bSZachary Turner #include <limits.h> 1497a14e60SZachary Turner #include <stdio.h> 1597a14e60SZachary Turner #include <string.h> 1697a14e60SZachary Turner #include <sys/utsname.h> 1797a14e60SZachary Turner 1897a14e60SZachary Turner #include <algorithm> 1997a14e60SZachary Turner 2097a14e60SZachary Turner using namespace lldb_private; 2197a14e60SZachary Turner 22673b6e4fSZachary Turner namespace 23673b6e4fSZachary Turner { 24673b6e4fSZachary Turner struct HostInfoLinuxFields 25673b6e4fSZachary Turner { 26673b6e4fSZachary Turner HostInfoLinuxFields() 27673b6e4fSZachary Turner : m_os_major(0) 28673b6e4fSZachary Turner , m_os_minor(0) 29673b6e4fSZachary Turner , m_os_update(0) 30673b6e4fSZachary Turner { 31673b6e4fSZachary Turner } 32673b6e4fSZachary Turner 33673b6e4fSZachary Turner std::string m_distribution_id; 34673b6e4fSZachary Turner uint32_t m_os_major; 35673b6e4fSZachary Turner uint32_t m_os_minor; 36673b6e4fSZachary Turner uint32_t m_os_update; 37673b6e4fSZachary Turner }; 38673b6e4fSZachary Turner 39673b6e4fSZachary Turner HostInfoLinuxFields *g_fields = nullptr; 40673b6e4fSZachary Turner } 41673b6e4fSZachary Turner 42673b6e4fSZachary Turner void 43673b6e4fSZachary Turner HostInfoLinux::Initialize() 44673b6e4fSZachary Turner { 45673b6e4fSZachary Turner HostInfoPosix::Initialize(); 46673b6e4fSZachary Turner 47673b6e4fSZachary Turner g_fields = new HostInfoLinuxFields(); 48673b6e4fSZachary Turner } 4997a14e60SZachary Turner 50*39de3110SZachary Turner uint32_t 51*39de3110SZachary Turner HostInfoLinux::GetMaxThreadNameLength() 52*39de3110SZachary Turner { 53*39de3110SZachary Turner return 16; 54*39de3110SZachary Turner } 55*39de3110SZachary Turner 5697a14e60SZachary Turner bool 5797a14e60SZachary Turner HostInfoLinux::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) 5897a14e60SZachary Turner { 5997a14e60SZachary Turner static bool is_initialized = false; 6097a14e60SZachary Turner static bool success = false; 6197a14e60SZachary Turner 6297a14e60SZachary Turner if (!is_initialized) 6397a14e60SZachary Turner { 6497a14e60SZachary Turner is_initialized = true; 6597a14e60SZachary Turner struct utsname un; 6697a14e60SZachary Turner 6797a14e60SZachary Turner if (uname(&un)) 6897a14e60SZachary Turner goto finished; 6997a14e60SZachary Turner 70673b6e4fSZachary Turner int status = sscanf(un.release, "%u.%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor, &g_fields->m_os_update); 7197a14e60SZachary Turner if (status == 3) 7297a14e60SZachary Turner { 7397a14e60SZachary Turner success = true; 7497a14e60SZachary Turner goto finished; 7597a14e60SZachary Turner } 7697a14e60SZachary Turner 7797a14e60SZachary Turner // Some kernels omit the update version, so try looking for just "X.Y" and 7897a14e60SZachary Turner // set update to 0. 79673b6e4fSZachary Turner g_fields->m_os_update = 0; 80673b6e4fSZachary Turner status = sscanf(un.release, "%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor); 8197a14e60SZachary Turner success = !!(status == 2); 8297a14e60SZachary Turner } 8397a14e60SZachary Turner 8497a14e60SZachary Turner finished: 85673b6e4fSZachary Turner major = g_fields->m_os_major; 86673b6e4fSZachary Turner minor = g_fields->m_os_minor; 87673b6e4fSZachary Turner update = g_fields->m_os_update; 8897a14e60SZachary Turner return success; 8997a14e60SZachary Turner } 9097a14e60SZachary Turner 9197a14e60SZachary Turner llvm::StringRef 9297a14e60SZachary Turner HostInfoLinux::GetDistributionId() 9397a14e60SZachary Turner { 9497a14e60SZachary Turner static bool is_initialized = false; 9597a14e60SZachary Turner // Try to run 'lbs_release -i', and use that response 9697a14e60SZachary Turner // for the distribution id. 9797a14e60SZachary Turner 9897a14e60SZachary Turner if (!is_initialized) 9997a14e60SZachary Turner { 10097a14e60SZachary Turner is_initialized = true; 10197a14e60SZachary Turner 10297a14e60SZachary Turner Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)); 10397a14e60SZachary Turner if (log) 10497a14e60SZachary Turner log->Printf("attempting to determine Linux distribution..."); 10597a14e60SZachary Turner 10697a14e60SZachary Turner // check if the lsb_release command exists at one of the 10797a14e60SZachary Turner // following paths 10897a14e60SZachary Turner const char *const exe_paths[] = {"/bin/lsb_release", "/usr/bin/lsb_release"}; 10997a14e60SZachary Turner 11097a14e60SZachary Turner for (size_t exe_index = 0; exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) 11197a14e60SZachary Turner { 11297a14e60SZachary Turner const char *const get_distribution_info_exe = exe_paths[exe_index]; 11397a14e60SZachary Turner if (access(get_distribution_info_exe, F_OK)) 11497a14e60SZachary Turner { 11597a14e60SZachary Turner // this exe doesn't exist, move on to next exe 11697a14e60SZachary Turner if (log) 11797a14e60SZachary Turner log->Printf("executable doesn't exist: %s", get_distribution_info_exe); 11897a14e60SZachary Turner continue; 11997a14e60SZachary Turner } 12097a14e60SZachary Turner 12197a14e60SZachary Turner // execute the distribution-retrieval command, read output 12297a14e60SZachary Turner std::string get_distribution_id_command(get_distribution_info_exe); 12397a14e60SZachary Turner get_distribution_id_command += " -i"; 12497a14e60SZachary Turner 12597a14e60SZachary Turner FILE *file = popen(get_distribution_id_command.c_str(), "r"); 12697a14e60SZachary Turner if (!file) 12797a14e60SZachary Turner { 12897a14e60SZachary Turner if (log) 12997a14e60SZachary Turner log->Printf("failed to run command: \"%s\", cannot retrieve " 13097a14e60SZachary Turner "platform information", 13197a14e60SZachary Turner get_distribution_id_command.c_str()); 13297a14e60SZachary Turner break; 13397a14e60SZachary Turner } 13497a14e60SZachary Turner 13597a14e60SZachary Turner // retrieve the distribution id string. 13697a14e60SZachary Turner char distribution_id[256] = {'\0'}; 13797a14e60SZachary Turner if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL) 13897a14e60SZachary Turner { 13997a14e60SZachary Turner if (log) 14097a14e60SZachary Turner log->Printf("distribution id command returned \"%s\"", distribution_id); 14197a14e60SZachary Turner 14297a14e60SZachary Turner const char *const distributor_id_key = "Distributor ID:\t"; 14397a14e60SZachary Turner if (strstr(distribution_id, distributor_id_key)) 14497a14e60SZachary Turner { 14597a14e60SZachary Turner // strip newlines 14697a14e60SZachary Turner std::string id_string(distribution_id + strlen(distributor_id_key)); 14797a14e60SZachary Turner id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), id_string.end()); 14897a14e60SZachary Turner 14997a14e60SZachary Turner // lower case it and convert whitespace to underscores 15097a14e60SZachary Turner std::transform(id_string.begin(), id_string.end(), id_string.begin(), [](char ch) 15197a14e60SZachary Turner { 15297a14e60SZachary Turner return tolower(isspace(ch) ? '_' : ch); 15397a14e60SZachary Turner }); 15497a14e60SZachary Turner 155673b6e4fSZachary Turner g_fields->m_distribution_id = id_string; 15697a14e60SZachary Turner if (log) 157673b6e4fSZachary Turner log->Printf("distribution id set to \"%s\"", g_fields->m_distribution_id.c_str()); 15897a14e60SZachary Turner } 15997a14e60SZachary Turner else 16097a14e60SZachary Turner { 16197a14e60SZachary Turner if (log) 16297a14e60SZachary Turner log->Printf("failed to find \"%s\" field in \"%s\"", distributor_id_key, distribution_id); 16397a14e60SZachary Turner } 16497a14e60SZachary Turner } 16597a14e60SZachary Turner else 16697a14e60SZachary Turner { 16797a14e60SZachary Turner if (log) 16897a14e60SZachary Turner log->Printf("failed to retrieve distribution id, \"%s\" returned no" 16997a14e60SZachary Turner " lines", 17097a14e60SZachary Turner get_distribution_id_command.c_str()); 17197a14e60SZachary Turner } 17297a14e60SZachary Turner 17397a14e60SZachary Turner // clean up the file 17497a14e60SZachary Turner pclose(file); 17597a14e60SZachary Turner } 17697a14e60SZachary Turner } 17797a14e60SZachary Turner 178673b6e4fSZachary Turner return g_fields->m_distribution_id.c_str(); 17997a14e60SZachary Turner } 18013b18261SZachary Turner 181a21fee0eSZachary Turner FileSpec 182a21fee0eSZachary Turner HostInfoLinux::GetProgramFileSpec() 183a21fee0eSZachary Turner { 184a21fee0eSZachary Turner static FileSpec g_program_filespec; 185a21fee0eSZachary Turner 186a21fee0eSZachary Turner if (!g_program_filespec) 187a21fee0eSZachary Turner { 188a21fee0eSZachary Turner char exe_path[PATH_MAX]; 189a21fee0eSZachary Turner ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); 190a21fee0eSZachary Turner if (len > 0) 191a21fee0eSZachary Turner { 192a21fee0eSZachary Turner exe_path[len] = 0; 193a21fee0eSZachary Turner g_program_filespec.SetFile(exe_path, false); 194a21fee0eSZachary Turner } 195a21fee0eSZachary Turner } 196a21fee0eSZachary Turner 197a21fee0eSZachary Turner return g_program_filespec; 198a21fee0eSZachary Turner } 199a21fee0eSZachary Turner 20042ff0ad8SZachary Turner bool 20142ff0ad8SZachary Turner HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec) 20242ff0ad8SZachary Turner { 2030d8400c8SGreg Clayton FileSpec temp_file("/usr/lib/lldb", true); 2040d8400c8SGreg Clayton file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); 20542ff0ad8SZachary Turner return true; 20642ff0ad8SZachary Turner } 20742ff0ad8SZachary Turner 20842ff0ad8SZachary Turner bool 20942ff0ad8SZachary Turner HostInfoLinux::ComputeUserPluginsDirectory(FileSpec &file_spec) 21042ff0ad8SZachary Turner { 21142ff0ad8SZachary Turner // XDG Base Directory Specification 21242ff0ad8SZachary Turner // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 21342ff0ad8SZachary Turner // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. 21442ff0ad8SZachary Turner const char *xdg_data_home = getenv("XDG_DATA_HOME"); 21542ff0ad8SZachary Turner if (xdg_data_home && xdg_data_home[0]) 21642ff0ad8SZachary Turner { 21742ff0ad8SZachary Turner std::string user_plugin_dir(xdg_data_home); 21842ff0ad8SZachary Turner user_plugin_dir += "/lldb"; 2190d8400c8SGreg Clayton file_spec.GetDirectory().SetCString(user_plugin_dir.c_str()); 22042ff0ad8SZachary Turner } 22142ff0ad8SZachary Turner else 2220d8400c8SGreg Clayton file_spec.GetDirectory().SetCString("~/.local/share/lldb"); 22342ff0ad8SZachary Turner return true; 22442ff0ad8SZachary Turner } 22542ff0ad8SZachary Turner 22613b18261SZachary Turner void 22713b18261SZachary Turner HostInfoLinux::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) 22813b18261SZachary Turner { 22913b18261SZachary Turner HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); 23013b18261SZachary Turner 23113b18261SZachary Turner const char *distribution_id = GetDistributionId().data(); 23213b18261SZachary Turner 23313b18261SZachary Turner // On Linux, "unknown" in the vendor slot isn't what we want for the default 23413b18261SZachary Turner // triple. It's probably an artifact of config.guess. 23513b18261SZachary Turner if (arch_32.IsValid()) 23613b18261SZachary Turner { 23713b18261SZachary Turner arch_32.SetDistributionId(distribution_id); 23813b18261SZachary Turner if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) 23913b18261SZachary Turner arch_32.GetTriple().setVendorName(""); 24013b18261SZachary Turner } 24113b18261SZachary Turner if (arch_64.IsValid()) 24213b18261SZachary Turner { 24313b18261SZachary Turner arch_64.SetDistributionId(distribution_id); 24413b18261SZachary Turner if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) 24513b18261SZachary Turner arch_64.GetTriple().setVendorName(""); 24613b18261SZachary Turner } 24713b18261SZachary Turner } 248