This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

source: ps/trunk/source/lib/sysdep/os/linux/ldbg.cpp

Last change on this file was 24625, checked in by Vladislav Belov, 4 years ago

Replaces UNICODE characters in the code by consistent ASCII characters.

Beside consistency improves reading for such console tools like svn diff or vim diff.

  • Property svn:eol-style set to native
File size: 5.3 KB
Line 
1/* Copyright (C) 2021 Wildfire Games.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23// Note: This used to use BFD to get more useful debugging information.
24// (See SVN r8270 if you want that code.)
25// That requires binutils at runtime, which hits some bugs and library versioning
26// issues on some Linux distros.
27// The debugging info reported by this code with BFD wasn't especially useful,
28// and it's easy enough to get people to run in gdb if we want a proper backtrace.
29// So we now go with the simple approach of not using BFD.
30
31#include "precompiled.h"
32
33#include "lib/sysdep/sysdep.h"
34#include "lib/debug.h"
35
36#include <algorithm>
37#include <cstring>
38#include <sys/syscall.h>
39
40#if OS_ANDROID
41
42// Android NDK doesn't support backtrace()
43// TODO: use unwind.h or similar?
44
45void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
46{
47 return NULL;
48}
49
50Status debug_DumpStack(wchar_t* UNUSED(buf), size_t UNUSED(max_chars), void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
51{
52 return ERR::NOT_SUPPORTED;
53}
54
55Status debug_ResolveSymbol(void* UNUSED(ptr_of_interest), wchar_t* UNUSED(sym_name), wchar_t* UNUSED(file), int* UNUSED(line))
56{
57 return ERR::NOT_SUPPORTED;
58}
59
60#else
61
62#include <execinfo.h>
63
64void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
65{
66 // bt[0] == this function
67 // bt[1] == our caller
68 // bt[2] == the first caller they are interested in
69 // HACK: we currently don't support lastFuncToSkip (would require debug information),
70 // instead just returning the caller of the function calling us
71 void *bt[3];
72 int bt_size = backtrace(bt, 3);
73 if (bt_size < 3)
74 return NULL;
75 return bt[2];
76}
77
78Status debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
79{
80 static const size_t N_FRAMES = 16;
81 void *bt[N_FRAMES];
82 int bt_size = 0;
83 wchar_t *bufpos = buf;
84 wchar_t *bufend = buf + max_chars;
85
86 bt_size = backtrace(bt, ARRAY_SIZE(bt));
87
88 // Assumed max length of a single print-out
89 static const size_t MAX_OUT_CHARS = 1024;
90
91 for (size_t i = 0; (int)i < bt_size && bufpos+MAX_OUT_CHARS < bufend; i++)
92 {
93 wchar_t file[DEBUG_FILE_CHARS];
94 wchar_t symbol[DEBUG_SYMBOL_CHARS];
95 int line;
96 int len;
97
98 if (debug_ResolveSymbol(bt[i], symbol, file, &line) == 0)
99 {
100 if (file[0])
101 len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls:%d %ls\n", bt[i], file, line, symbol);
102 else
103 len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls\n", bt[i], symbol);
104 }
105 else
106 {
107 len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p)\n", bt[i]);
108 }
109
110 if (len < 0)
111 {
112 // MAX_OUT_CHARS exceeded, realistically this was caused by some
113 // mindbogglingly long symbol name... replace the end with an
114 // ellipsis and a newline
115 memcpy(&bufpos[MAX_OUT_CHARS-6], L"...\n", 5*sizeof(wchar_t));
116 len = MAX_OUT_CHARS;
117 }
118
119 bufpos += len;
120 }
121
122 return INFO::OK;
123}
124
125Status debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line)
126{
127 if (sym_name)
128 *sym_name = 0;
129 if (file)
130 *file = 0;
131 if (line)
132 *line = 0;
133
134 char** symbols = backtrace_symbols(&ptr_of_interest, 1);
135 if (symbols)
136 {
137 swprintf_s(sym_name, DEBUG_SYMBOL_CHARS, L"%hs", symbols[0]);
138 free(symbols);
139
140 // (Note that this will usually return a pretty useless string,
141 // because we compile with -fvisibility=hidden and there won't be
142 // any exposed symbols for backtrace_symbols to report.)
143
144 return INFO::OK;
145 }
146 else
147 {
148 return ERR::FAIL;
149 }
150}
151
152#endif
153
154/* This is basically a reimplementation of the pthread_setname_np() glibc
155 * function, to make it work on every Linux distribution, no matter the libc
156 * used.
157 *
158 * The thread name limit is 16 (including the terminating null byte) on Linux,
159 * so we have to cut the provided name at 15 bytes.
160 *
161 * This API exists since Linux 2.6.33, on older kernels the user will just not
162 * get thread names.
163 */
164void debug_SetThreadName(const char* name)
165{
166 constexpr size_t MAX_THREAD_NAME_LEN = 15;
167 constexpr size_t MAX_FILE_PATH_LEN = 32;
168
169 char pathname[MAX_FILE_PATH_LEN];
170 pid_t tid = syscall(SYS_gettid);
171 snprintf(pathname, MAX_FILE_PATH_LEN, "/proc/self/task/%d/comm", tid);
172
173 FILE* comm = fopen(pathname, "w");
174 if (!comm)
175 return;
176
177 std::string limited_name(name, std::min(strlen(name), MAX_THREAD_NAME_LEN));
178 fputs(limited_name.c_str(), comm);
179 fclose(comm);
180}
Note: See TracBrowser for help on using the repository browser.