From a9bcc81f821d7c66f623779fa5147e728eb3c388 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 03:24:41 +0200 Subject: Adding upstream version 3.3.0+dfsg1. Signed-off-by: Daniel Baumann --- winpr/libwinpr/utils/corkscrew/backtrace.h | 120 ++++++++++++ winpr/libwinpr/utils/corkscrew/debug.c | 260 ++++++++++++++++++++++++++ winpr/libwinpr/utils/corkscrew/debug.h | 40 ++++ winpr/libwinpr/utils/corkscrew/demangle.h | 43 +++++ winpr/libwinpr/utils/corkscrew/map_info.h | 76 ++++++++ winpr/libwinpr/utils/corkscrew/ptrace.h | 139 ++++++++++++++ winpr/libwinpr/utils/corkscrew/symbol_table.h | 62 ++++++ 7 files changed, 740 insertions(+) create mode 100644 winpr/libwinpr/utils/corkscrew/backtrace.h create mode 100644 winpr/libwinpr/utils/corkscrew/debug.c create mode 100644 winpr/libwinpr/utils/corkscrew/debug.h create mode 100644 winpr/libwinpr/utils/corkscrew/demangle.h create mode 100644 winpr/libwinpr/utils/corkscrew/map_info.h create mode 100644 winpr/libwinpr/utils/corkscrew/ptrace.h create mode 100644 winpr/libwinpr/utils/corkscrew/symbol_table.h (limited to 'winpr/libwinpr/utils/corkscrew') diff --git a/winpr/libwinpr/utils/corkscrew/backtrace.h b/winpr/libwinpr/utils/corkscrew/backtrace.h new file mode 100644 index 0000000..408f988 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/backtrace.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* A stack unwinder. */ + +#ifndef _CORKSCREW_BACKTRACE_H +#define _CORKSCREW_BACKTRACE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include + + /* + * Describes a single frame of a backtrace. + */ + typedef struct + { + uintptr_t absolute_pc; /* absolute PC offset */ + uintptr_t stack_top; /* top of stack for this frame */ + size_t stack_size; /* size of this stack frame */ + } backtrace_frame_t; + + /* + * Describes the symbols associated with a backtrace frame. + */ + typedef struct + { + uintptr_t relative_pc; /* relative frame PC offset from the start of the library, + or the absolute PC if the library is unknown */ + uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the + library or 0 if the library is unknown */ + char* map_name; /* executable or library name, or NULL if unknown */ + char* symbol_name; /* symbol name, or NULL if unknown */ + char* demangled_name; /* demangled symbol name, or NULL if unknown */ + } backtrace_symbol_t; + + /* + * Unwinds the call stack for the current thread of execution. + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + */ + ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth); + + /* + * Unwinds the call stack for a thread within this process. + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + * + * The task is briefly suspended while the backtrace is being collected. + */ + ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + + /* + * Unwinds the call stack of a task within a remote process using ptrace(). + * Populates the backtrace array with the program counters from the call stack. + * Returns the number of frames collected, or -1 if an error occurred. + */ + ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context, + backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + + /* + * Gets the symbols for each frame of a backtrace. + * The symbols array must be big enough to hold one symbol record per frame. + * The symbols must later be freed using free_backtrace_symbols. + */ + void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + + /* + * Gets the symbols for each frame of a backtrace from a remote process. + * The symbols array must be big enough to hold one symbol record per frame. + * The symbols must later be freed using free_backtrace_symbols. + */ + void get_backtrace_symbols_ptrace(const ptrace_context_t* context, + const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + + /* + * Frees the storage associated with backtrace symbols. + */ + void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames); + + enum + { + // A hint for how big to make the line buffer for format_backtrace_line + MAX_BACKTRACE_LINE_LENGTH = 800, + }; + + /** + * Formats a line from a backtrace as a zero-terminated string into the specified buffer. + */ + void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame, + const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_BACKTRACE_H diff --git a/winpr/libwinpr/utils/corkscrew/debug.c b/winpr/libwinpr/utils/corkscrew/debug.c new file mode 100644 index 0000000..0fc2fd6 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/debug.c @@ -0,0 +1,260 @@ +/** + * WinPR: Windows Portable Runtime + * Debugging Utils + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "debug.h" + +#define TAG "com.winpr.utils.debug" +#define LOGT(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \ + } while (0) +#define LOGD(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \ + } while (0) +#define LOGI(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \ + } while (0) +#define LOGW(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \ + } while (0) +#define LOGE(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \ + } while (0) +#define LOGF(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \ + } while (0) + +static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!"; + +typedef struct +{ + backtrace_frame_t* buffer; + size_t max; + size_t used; +} t_corkscrew_data; + +typedef struct +{ + void* hdl; + ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context, + backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context, + const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames); + void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame, + const backtrace_symbol_t* symbol, char* buffer, + size_t bufferSize); +} t_corkscrew; + +static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static t_corkscrew* fkt = NULL; + +void load_library(void) +{ + static t_corkscrew lib; + { + lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY); + + if (!lib.hdl) + { + LOGF("dlopen error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace"); + + if (!lib.unwind_backtrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread"); + + if (!lib.unwind_backtrace_thread) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace"); + + if (!lib.unwind_backtrace_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols"); + + if (!lib.get_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace"); + + if (!lib.get_backtrace_symbols_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols"); + + if (!lib.free_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line"); + + if (!lib.format_backtrace_line) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + fkt = &lib; + return; + } +fail: +{ + if (lib.hdl) + dlclose(lib.hdl); + + fkt = NULL; +} +} + +void winpr_corkscrew_backtrace_free(void* buffer) +{ + t_corkscrew_data* data = (t_corkscrew_data*)buffer; + if (!data) + return; + + free(data->buffer); + free(data); +} + +void* winpr_corkscrew_backtrace(DWORD size) +{ + t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data)); + + if (!data) + return NULL; + + data->buffer = calloc(size, sizeof(backtrace_frame_t)); + + if (!data->buffer) + { + free(data); + return NULL; + } + + pthread_once(&initialized, load_library); + data->max = size; + data->used = fkt->unwind_backtrace(data->buffer, 0, size); + return data; +} + +char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used) +{ + t_corkscrew_data* data = (t_corkscrew_data*)buffer; + if (used) + *used = 0; + + if (!data) + return NULL; + + pthread_once(&initialized, load_library); + + if (!fkt) + { + LOGF(support_msg); + return NULL; + } + else + { + size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t array_size = data->used * sizeof(char*); + size_t lines_size = data->used * line_len; + char** vlines = calloc(1, array_size + lines_size); + backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t)); + + if (!vlines || !symbols) + { + free(vlines); + free(symbols); + return NULL; + } + + /* Set the pointers in the allocated buffer's initial array section */ + for (size_t i = 0; i < data->used; i++) + vlines[i] = (char*)vlines + array_size + i * line_len; + + fkt->get_backtrace_symbols(data->buffer, data->used, symbols); + + for (size_t i = 0; i < data->used; i++) + fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len); + + fkt->free_backtrace_symbols(symbols, data->used); + free(symbols); + + if (used) + *used = data->used; + + return vlines; + } +} diff --git a/winpr/libwinpr/utils/corkscrew/debug.h b/winpr/libwinpr/utils/corkscrew/debug.h new file mode 100644 index 0000000..e98b9bd --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/debug.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_DEBUG_CORKSCREW_H +#define WINPR_DEBUG_CORKSCREW_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + void* winpr_corkscrew_backtrace(DWORD size); + void winpr_corkscrew_backtrace_free(void* buffer); + char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used); + void winpr_corkscrew_backtrace_symbols_fd(void* buffer, int fd); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_DEBUG_CORKSCREW_H */ diff --git a/winpr/libwinpr/utils/corkscrew/demangle.h b/winpr/libwinpr/utils/corkscrew/demangle.h new file mode 100644 index 0000000..75c01d7 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/demangle.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* C++ symbol name demangling. */ + +#ifndef _CORKSCREW_DEMANGLE_H +#define _CORKSCREW_DEMANGLE_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* + * Demangles a C++ symbol name. + * If name is NULL or if the name cannot be demangled, returns NULL. + * Otherwise, returns a newly allocated string that contains the demangled name. + * + * The caller must free the returned string using free(). + */ + char* demangle_symbol_name(const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_DEMANGLE_H diff --git a/winpr/libwinpr/utils/corkscrew/map_info.h b/winpr/libwinpr/utils/corkscrew/map_info.h new file mode 100644 index 0000000..dc2275e --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/map_info.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Process memory map. */ + +#ifndef _CORKSCREW_MAP_INFO_H +#define _CORKSCREW_MAP_INFO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + struct map_info* next; + uintptr_t start; + uintptr_t end; + bool is_readable; + bool is_writable; + bool is_executable; + void* data; // arbitrary data associated with the map by the user, initially NULL + char name[]; + } map_info_t; + + /* Loads memory map from /proc//maps. */ + map_info_t* load_map_info_list(pid_t tid); + + /* Frees memory map. */ + void free_map_info_list(map_info_t* milist); + + /* Finds the memory map that contains the specified address. */ + const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr); + + /* Returns true if the addr is in a readable map. */ + bool is_readable_map(const map_info_t* milist, uintptr_t addr); + /* Returns true if the addr is in a writable map. */ + bool is_writable_map(const map_info_t* milist, uintptr_t addr); + /* Returns true if the addr is in an executable map. */ + bool is_executable_map(const map_info_t* milist, uintptr_t addr); + + /* Acquires a reference to the memory map for this process. + * The result is cached and refreshed automatically. + * Make sure to release the map info when done. */ + map_info_t* acquire_my_map_info_list(); + + /* Releases a reference to the map info for this process that was + * previous acquired using acquire_my_map_info_list(). */ + void release_my_map_info_list(map_info_t* milist); + + /* Flushes the cached memory map so the next call to + * acquire_my_map_info_list() gets fresh data. */ + void flush_my_map_info_list(); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_MAP_INFO_H diff --git a/winpr/libwinpr/utils/corkscrew/ptrace.h b/winpr/libwinpr/utils/corkscrew/ptrace.h new file mode 100644 index 0000000..8ff7575 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/ptrace.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Useful ptrace() utility functions. */ + +#ifndef _CORKSCREW_PTRACE_H +#define _CORKSCREW_PTRACE_H + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Stores information about a process that is used for several different + * ptrace() based operations. */ + typedef struct + { + map_info_t* map_info_list; + } ptrace_context_t; + + /* Describes how to access memory from a process. */ + typedef struct + { + pid_t tid; + const map_info_t* map_info_list; + } memory_t; + +#ifdef __i386__ + /* ptrace() register context. */ + typedef struct pt_regs_x86 + { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t xds; + uint32_t xes; + uint32_t xfs; + uint32_t xgs; + uint32_t orig_eax; + uint32_t eip; + uint32_t xcs; + uint32_t eflags; + uint32_t esp; + uint32_t xss; + } pt_regs_x86_t; +#endif + +#ifdef __mips__ + /* ptrace() GET_REGS context. */ + typedef struct pt_regs_mips + { + uint64_t regs[32]; + uint64_t lo; + uint64_t hi; + uint64_t cp0_epc; + uint64_t cp0_badvaddr; + uint64_t cp0_status; + uint64_t cp0_cause; + } pt_regs_mips_t; +#endif + + /* + * Initializes a memory structure for accessing memory from this process. + */ + void init_memory(memory_t* memory, const map_info_t* map_info_list); + + /* + * Initializes a memory structure for accessing memory from another process + * using ptrace(). + */ + void init_memory_ptrace(memory_t* memory, pid_t tid); + + /* + * Reads a word of memory safely. + * If the memory is local, ensures that the address is readable before dereferencing it. + * Returns false and a value of 0xffffffff if the word could not be read. + */ + bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value); + + /* + * Reads a word of memory safely using ptrace(). + * Returns false and a value of 0xffffffff if the word could not be read. + */ + bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value); + + /* + * Loads information needed for examining a remote process using ptrace(). + * The caller must already have successfully attached to the process + * using ptrace(). + * + * The context can be used for any threads belonging to that process + * assuming ptrace() is attached to them before performing the actual + * unwinding. The context can continue to be used to decode backtraces + * even after ptrace() has been detached from the process. + */ + ptrace_context_t* load_ptrace_context(pid_t pid); + + /* + * Frees a ptrace context. + */ + void free_ptrace_context(ptrace_context_t* context); + + /* + * Finds a symbol using ptrace. + * Returns the containing map and information about the symbol, or + * NULL if one or the other is not available. + */ + void find_symbol_ptrace(const ptrace_context_t* context, uintptr_t addr, + const map_info_t** out_map_info, const symbol_t** out_symbol); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_PTRACE_H diff --git a/winpr/libwinpr/utils/corkscrew/symbol_table.h b/winpr/libwinpr/utils/corkscrew/symbol_table.h new file mode 100644 index 0000000..380e17d --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/symbol_table.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CORKSCREW_SYMBOL_TABLE_H +#define _CORKSCREW_SYMBOL_TABLE_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + uintptr_t start; + uintptr_t end; + char* name; + } symbol_t; + + typedef struct + { + symbol_t* symbols; + size_t num_symbols; + } symbol_table_t; + + /* + * Loads a symbol table from a given file. + * Returns NULL on error. + */ + symbol_table_t* load_symbol_table(const char* filename); + + /* + * Frees a symbol table. + */ + void free_symbol_table(symbol_table_t* table); + + /* + * Finds a symbol associated with an address in the symbol table. + * Returns NULL if not found. + */ + const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr); + +#ifdef __cplusplus +} +#endif + +#endif // _CORKSCREW_SYMBOL_TABLE_H -- cgit v1.2.3