Add FreeBSD operating system support.

This commit is contained in:
Er2
2023-11-02 19:02:10 +03:00
committed by Baldur Karlsson
parent de06321536
commit 86cb3ebf80
13 changed files with 295 additions and 16 deletions
+4
View File
@@ -9,6 +9,10 @@ if(APPLE)
SET(CMAKE_XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE "Disabled")
endif()
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "FreeBSD")
set(FreeBSD YES)
endif()
# Configure some stuff that needs to be set really early
if(BUILD_ANDROID)
if(NOT DEFINED ENV{JAVA_HOME})
+13 -3
View File
@@ -20,6 +20,7 @@
actual site failure. So the debugger stops on the CHECK() or REQUIRE()
call instead of inside AssertionHandler::complete()
* https://github.com/baldurk/renderdoc/commit/4232736fc21fc6a13a4de6997a5ae106598b225f
* Add FreeBSD support with correct debugger handling
*/
#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
@@ -2724,7 +2725,7 @@ namespace Catch {
#define CATCH_TRAP() __asm__(".inst 0xde01")
#endif
#elif defined(CATCH_PLATFORM_LINUX)
#elif defined(CATCH_PLATFORM_LINUX) || defined(__FreeBSD__)
// If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside
// raise() called from it, i.e. one stack frame below.
@@ -10428,7 +10429,7 @@ namespace Catch {
// end catch_debug_console.cpp
// start catch_debugger.cpp
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) || defined(__FreeBSD__)
# include <cassert>
# include <sys/types.h>
@@ -10440,10 +10441,13 @@ namespace Catch {
// These headers will only compile with AppleClang (XCode)
// For other compilers (Clang, GCC, ... ) we need to exclude them
# include <sys/sysctl.h>
#elif defined(__FreeBSD__)
# include <sys/user.h>
# include <sys/sysctl.h>
#endif
namespace Catch {
#ifdef __apple_build_version__
#if defined(__apple_build_version__) || defined(__FreeBSD__)
// The following function is taken directly from the following technical note:
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
@@ -10454,10 +10458,12 @@ namespace Catch {
struct kinfo_proc info;
std::size_t size;
#ifndef __FreeBSD__
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
#endif
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
@@ -10477,7 +10483,11 @@ namespace Catch {
// We're being debugged if the P_TRACED flag is set.
#ifdef __FreeBSD__
return ( (info.ki_flag & P_TRACED) != 0 );
#else
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
#endif
}
#else
bool isDebuggerActive() {
+2 -2
View File
@@ -79,7 +79,7 @@ enum
Key_F = 33,
Key_W = 17,
Key_R = 19,
#elif defined(Q_OS_LINUX)
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
Key_A = 30 + 8,
Key_S = 31 + 8,
Key_D = 32 + 8,
@@ -111,7 +111,7 @@ enum
Key_F = quint32('F'),
Key_W = quint32('W'),
Key_R = quint32('R'),
#elif defined(Q_OS_LINUX)
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
Key_A = quint32('a'),
Key_S = quint32('s'),
Key_D = quint32('d'),
+2 -2
View File
@@ -471,7 +471,7 @@ void CaptureDialog::vulkanLayerWarn_mouseClick()
bool needReg = RENDERDOC_NeedVulkanLayerRegistration(NULL);
ui->vulkanLayerWarn->setVisible(needReg);
#if !defined(Q_OS_LINUX)
#if !defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
// can't alert the user on linux because the command might still be running - there's
// seemingly no portable way to wait for the command to finish.
if(needReg)
@@ -490,7 +490,7 @@ void CaptureDialog::vulkanLayerWarn_mouseClick()
{
// linux sometimes can't run GUI apps as root, so we have to run renderdoccmd. Check that it's
// installed, error if not, then invoke it.
#if defined(Q_OS_LINUX)
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
QDir binDir = QFileInfo(qApp->applicationFilePath()).absoluteDir();
QString cmd = lit("renderdoccmd");
+13 -3
View File
@@ -20,6 +20,7 @@
actual site failure. So the debugger stops on the CHECK() or REQUIRE()
call instead of inside AssertionHandler::complete()
* https://github.com/baldurk/renderdoc/commit/4232736fc21fc6a13a4de6997a5ae106598b225f
* Add FreeBSD support with correct debugger handling
*/
#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
@@ -2724,7 +2725,7 @@ namespace Catch {
#define CATCH_TRAP() __asm__(".inst 0xde01")
#endif
#elif defined(CATCH_PLATFORM_LINUX)
#elif defined(CATCH_PLATFORM_LINUX) || defined(__FreeBSD__)
// If we can use inline assembler, do it because this allows us to break
// directly at the location of the failing check instead of breaking inside
// raise() called from it, i.e. one stack frame below.
@@ -10428,7 +10429,7 @@ namespace Catch {
// end catch_debug_console.cpp
// start catch_debugger.cpp
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) || defined(__FreeBSD__)
# include <cassert>
# include <sys/types.h>
@@ -10440,10 +10441,13 @@ namespace Catch {
// These headers will only compile with AppleClang (XCode)
// For other compilers (Clang, GCC, ... ) we need to exclude them
# include <sys/sysctl.h>
#elif defined(__FreeBSD__)
# include <sys/user.h>
# include <sys/sysctl.h>
#endif
namespace Catch {
#ifdef __apple_build_version__
#if defined(__apple_build_version__) || defined(__FreeBSD__)
// The following function is taken directly from the following technical note:
// https://developer.apple.com/library/archive/qa/qa1361/_index.html
@@ -10454,10 +10458,12 @@ namespace Catch {
struct kinfo_proc info;
std::size_t size;
#ifndef __FreeBSD__
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
#endif
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
@@ -10477,7 +10483,11 @@ namespace Catch {
// We're being debugged if the P_TRACED flag is set.
#ifdef __FreeBSD__
return ( (info.ki_flag & P_TRACED) != 0 );
#else
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
#endif
}
#else
bool isDebuggerActive() {
+26
View File
@@ -59,6 +59,15 @@ elseif(UNIX)
PRIVATE -ldl
PRIVATE -lrt)
if(FreeBSD)
list(APPEND RDOC_LIBRARIES
PRIVATE -L/usr/local/lib
PRIVATE -liconv
PRIVATE -lexecinfo
PRIVATE -lutil
)
endif()
if(ENABLE_XLIB)
find_package(X11 REQUIRED)
@@ -329,6 +338,23 @@ elseif(ENABLE_GGP)
os/posix/posix_stringio.cpp
os/posix/posix_threading.cpp
os/posix/posix_specific.h)
elseif(FreeBSD)
list(APPEND sources
data/embedded_files.h
os/posix/linux/linux_stringio.cpp
os/posix/linux/linux_callstack.cpp
os/posix/linux/linux_threading.cpp
os/posix/freebsd/freebsd_process.cpp
os/posix/linux/linux_hook.cpp
os/posix/linux/linux_network.cpp
3rdparty/plthook/plthook.h
3rdparty/plthook/plthook_elf.c
os/posix/posix_network.h
os/posix/posix_network.cpp
os/posix/posix_process.cpp
os/posix/posix_stringio.cpp
os/posix/posix_threading.cpp
os/posix/posix_specific.h)
elseif(UNIX)
list(APPEND sources
data/embedded_files.h
+1 -1
View File
@@ -35,7 +35,7 @@
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
#define RENDERDOC_CC __cdecl
#elif defined(__linux__)
#elif defined(__linux__) || defined(__FreeBSD__)
#define RENDERDOC_CC
#elif defined(__APPLE__)
#define RENDERDOC_CC
+3
View File
@@ -84,6 +84,9 @@ void GLResourceManager::MarkFBOAttachmentsReferenced(ResourceId fboid, GLResourc
{
FBOCache *cache = m_FBOAttachmentsCache[fboid];
if(!record)
return;
if(!cache)
{
cache = m_FBOAttachmentsCache[fboid] = new FBOCache;
@@ -0,0 +1,211 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2023 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include <dlfcn.h> // for dlsym
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
#include <unistd.h>
#include "common/common.h"
#include "common/formatting.h"
#include "core/core.h"
#include "os/os_specific.h"
// extern char **environ;
char **GetCurrentEnvironment()
{
// environ is broken: https://reviews.freebsd.org/D30842
return *(char ***)dlsym(RTLD_DEFAULT, "environ");
// return environ;
}
rdcstr execcmd(const char *cmd)
{
FILE *pipe = popen(cmd, "r");
if(!pipe)
return "ERROR";
char buffer[128];
rdcstr result = "";
while(!feof(pipe))
{
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
bool isNewline(char c)
{
return c == '\n' || c == '\r';
}
// FIXME: lsof is in ports but not in base system
int GetIdentPort(pid_t childPid)
{
rdcstr lsof = StringFormat::Fmt("lsof -p %d -a -i 4 -F n", (int)childPid);
rdcstr result;
uint32_t wait = 1;
// Wait for a maximum of ~16 seconds
for(int i = 0; i < 14; ++i)
{
result = execcmd(lsof.c_str());
if(!result.empty())
break;
usleep(wait * 1000);
wait *= 2;
}
if(result.empty())
{
RDCERR("No output from lsof command: '%s'", lsof.c_str());
return 0;
}
// Parse the result expecting:
// p<PID>
// <TEXT>
// n*:<PORT>
rdcstr parseResult(result);
const int len = parseResult.count();
if(parseResult[0] == 'p')
{
int tokenStart = 1;
int i = tokenStart;
for(; i < len; i++)
{
if(parseResult[i] < '0' || parseResult[i] > '9')
break;
}
parseResult[i++] = 0;
if(isNewline(parseResult[i]))
i++;
const int pid = atoi(&result[tokenStart]);
if(pid == (int)childPid)
{
const char *netString("n*:");
while(i < len)
{
const int netStart = parseResult.find(netString, i);
if(netStart >= 0)
{
tokenStart = netStart + (int)strlen(netString);
i = tokenStart;
for(; i < len; i++)
{
if(parseResult[i] < '0' || parseResult[i] > '9')
break;
}
parseResult[i++] = 0;
if(isNewline(parseResult[i]))
i++;
const int port = atoi(&result[tokenStart]);
if(port >= RenderDoc_FirstTargetControlPort && port <= RenderDoc_LastTargetControlPort)
{
return port;
}
// continue on to next port
}
else
{
RDCERR("Malformed line - expected 'n*':\n%s", &result[i]);
return 0;
}
}
}
else
{
RDCERR("pid from lsof output doesn't match childPid");
return 0;
}
}
RDCERR("Failed to parse output from lsof:\n%s", result.c_str());
return 0;
}
void StopAtMainInChild()
{
}
bool StopChildAtMain(pid_t childPid, bool *exitWithNoExec)
{
return false;
}
void ResumeProcess(pid_t childPid, uint32_t delay)
{
}
// OSUtility::DebuggerPresent is called a lot
// cache the value at startup as an optimisation
static bool s_debuggerPresent = false;
static bool s_debuggerCached = false;
void CacheDebuggerPresent()
{
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
struct kinfo_proc info = {};
size_t size = sizeof(info);
if(!sysctl(mib, ARRAY_COUNT(mib), &info, &size, NULL, 0))
{
s_debuggerPresent = (info.ki_flag & P_TRACED);
s_debuggerCached = true;
}
}
bool OSUtility::DebuggerPresent()
{
if(!s_debuggerCached)
CacheDebuggerPresent();
return s_debuggerPresent;
}
rdcstr Process::GetEnvVariable(const rdcstr &name)
{
const char *val = getenv(name.c_str());
return val ? val : rdcstr();
}
uint64_t Process::GetMemoryUsage()
{
int mib[4] = {CTL_VM, KERN_PROC, KERN_PROC_PID, getpid()};
struct kinfo_proc info = {};
size_t size = sizeof(info);
if(sysctl(mib, ARRAY_COUNT(mib), &info, &size, NULL, 0) != 0)
return 0;
// from usr.bin/top/machine.c macro PROCSIZE
return info.ki_size / 1024;
}
+2 -2
View File
@@ -66,11 +66,11 @@ private:
{
void *addrs_ptr[ARRAY_COUNT(addrs)];
int ret = backtrace(addrs_ptr, ARRAY_COUNT(addrs));
size_t ret = backtrace(addrs_ptr, ARRAY_COUNT(addrs));
numLevels = 0;
if(ret > 0)
numLevels = (size_t)ret;
numLevels = ret;
int offs = 0;
// if we want to trim levels of the stack, we can do that here
+6
View File
@@ -38,7 +38,11 @@
Threading::CriticalSection libLock;
#ifdef __linux__
RDOC_EXTERN_CONFIG(bool, Linux_Debug_PtraceLogging);
#else
#define Linux_Debug_PtraceLogging() false
#endif
static std::map<rdcstr, rdcarray<FunctionLoadCallback>> libraryCallbacks;
static rdcarray<rdcstr> libraryHooks;
@@ -116,6 +120,7 @@ int direct_setenv(const char *name, const char *value, int overwrite);
// The other variants all forward to one of those - the 'l' cases unroll the va_args first before
// calling onwards
#ifndef __FreeBSD__ // TODO: environ bug
#define GET_EXECL_PARAMS(has_e) \
va_list args; \
va_start(args, arg); \
@@ -194,6 +199,7 @@ __attribute__((visibility("default"))) int execvp(const char *pathname, char *co
return execvpe(pathname, argv, environ);
}
#endif // __FreeBSD__
__attribute__((visibility("default"))) int execve(const char *pathname, char *const argv[],
char *const envp[])
@@ -24,7 +24,9 @@
#include "os/os_specific.h"
#ifdef __linux__
#include <sys/prctl.h>
#endif
#include <time.h>
#include <unistd.h>
@@ -42,5 +44,7 @@ uint64_t Timing::GetTick()
void Threading::SetCurrentThreadName(const rdcstr &name)
{
#ifdef __linux__
prctl(PR_SET_NAME, (unsigned long)name.c_str(), 0, 0, 0);
#endif
}
+8 -3
View File
@@ -50,9 +50,14 @@ elseif(ENABLE_GGP)
elseif(UNIX)
list(APPEND sources renderdoccmd_linux.cpp)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set_property(SOURCE renderdoccmd_linux.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-shadow")
endif()
if(FreeBSD)
list(APPEND libraries PRIVATE -L/usr/local/lib)
list(APPEND includes /usr/local/include)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set_property(SOURCE renderdoccmd_linux.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-shadow")
endif()
if(ENABLE_XLIB)
list(APPEND libraries PRIVATE -lX11)