mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 09:00:44 +00:00
Add FreeBSD operating system support.
This commit is contained in:
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user