Add backtrace.c (the same that was used to build backtrace.dll earlier) to tree

and build our own DLL, now called ebacktrace1.dll.  The change consists of
breaking the link to the libintl lib and its dependencies, so the backtrace dll
is now the only one required.

git-svn-id: https://svn.eduke32.com/eduke32@2037 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2011-09-21 22:38:24 +00:00
parent d4572c8957
commit e91c4dc15b
2 changed files with 394 additions and 4 deletions

View file

@ -50,6 +50,10 @@ JAUDIOLIB=libjfaudiolib.a
ENETDIR=$(SRC)/enet
ENETLIB=libenet.a
EBACKTRACEDLL=ebacktrace1.dll
EBACKTRACEDLL_TARGET=
include $(EROOT)/Makefile.shared
@ -58,9 +62,12 @@ ifeq ($(PLATFORM),WINDOWS)
OBJ=obj_win
EOBJ=eobj_win
LIBS+= $(L_SSP) -Wl,--enable-auto-import
ifeq (0,$(RELEASE))
EBACKTRACEDLL_TARGET=$(EBACKTRACEDLL)
endif
ifneq (0,$(USE_LIBVPX))
LIBS+= -L$(OBJ)/../Windows/lib
OURCFLAGS+= -I$(OBJ)/../Windows/include #-I$(OBJ)/../Windows/include/vpx
LIBS+= -LWindows/lib
OURCFLAGS+= -IWindows/include
endif
else
ifeq ($(PLATFORM),LINUX)
@ -221,7 +228,7 @@ all:
notice:
$(BUILD_STARTED)
eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(ENETDIR)/$(ENETLIB)
eduke32$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(ENETDIR)/$(ENETLIB) $(EBACKTRACEDLL_TARGET)
$(LINK_STATUS)
if $(CC) $(CFLAGS) $(OURCFLAGS) -o $@ $^ $(LIBS) $(STDCPPLIB) $(MISCLINKOPTS); then $(LINK_OK); else $(LINK_FAILED); fi
ifeq (1,$(RELEASE))
@ -230,7 +237,7 @@ ifeq (1,$(RELEASE))
endif
endif
mapster32$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)/$(EDITORLIB) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB)
mapster32$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)/$(EDITORLIB) $(EOBJ)/$(ENGINELIB) $(JAUDIOLIBDIR)/$(JAUDIOLIB) $(EBACKTRACEDLL_TARGET)
$(LINK_STATUS)
if $(CC) $(CFLAGS) $(OURCFLAGS) -o $@ $^ $(LIBS) $(STDCPPLIB) $(MISCLINKOPTS); then $(LINK_OK); else $(LINK_FAILED); fi
ifeq (1,$(RELEASE))
@ -278,6 +285,9 @@ endif
# RULES
$(EBACKTRACEDLL): Windows/src/backtrace.c
if $(CC) -O2 -shared -Wall -Wextra -o $@ $^ -lbfd -liberty -limagehlp; then $(COMPILE_OK); else $(COMPILE_FAILED); fi
$(OBJ)/%.$o: $(SRC)/%.nasm
$(COMPILE_STATUS)
$(AS) $(NASMFLAGS) $< -o $@

View file

@ -0,0 +1,380 @@
/*
Copyright (c) 2010 ,
Cloud Wu . All rights reserved.
http://www.codingnow.com
Use, modification and distribution are subject to the "New BSD License"
as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
filename: backtrace.c
compiler: gcc 3.4.5 (mingw-win32)
build command: gcc -O2 -shared -Wall -o backtrace.dll backtrace.c -lbfd -liberty -limagehlp
how to use: Call LoadLibraryA("backtrace.dll"); at beginning of your program .
*/
/* modified from original for EDuke32 */
#include <windows.h>
#include <excpt.h>
#include <imagehlp.h>
#include <bfd.h>
#include <psapi.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>
#define BUFFER_MAX (16*1024)
struct bfd_ctx {
bfd * handle;
asymbol ** symbol;
};
struct bfd_set {
char * name;
struct bfd_ctx * bc;
struct bfd_set *next;
};
struct find_info {
asymbol **symbol;
bfd_vma counter;
const char *file;
const char *func;
unsigned line;
};
struct output_buffer {
char * buf;
size_t sz;
size_t ptr;
};
static void
output_init(struct output_buffer *ob, char * buf, size_t sz)
{
ob->buf = buf;
ob->sz = sz;
ob->ptr = 0;
ob->buf[0] = '\0';
}
static void
output_print(struct output_buffer *ob, const char * format, ...)
{
if (ob->sz == ob->ptr)
return;
ob->buf[ob->ptr] = '\0';
va_list ap;
va_start(ap,format);
vsnprintf(ob->buf + ob->ptr , ob->sz - ob->ptr , format, ap);
va_end(ap);
ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr;
}
static void
lookup_section(bfd *abfd, asection *sec, void *opaque_data)
{
struct find_info *data = opaque_data;
if (data->func)
return;
if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
return;
bfd_vma vma = bfd_get_section_vma(abfd, sec);
if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter)
return;
bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma, &(data->file), &(data->func), &(data->line));
}
static void
find(struct bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line)
{
struct find_info data;
data.func = NULL;
data.symbol = b->symbol;
data.counter = offset;
data.file = NULL;
data.func = NULL;
data.line = 0;
bfd_map_over_sections(b->handle, &lookup_section, &data);
if (file) {
*file = data.file;
}
if (func) {
*func = data.func;
}
if (line) {
*line = data.line;
}
}
static int
init_bfd_ctx(struct bfd_ctx *bc, const char * procname, struct output_buffer *ob)
{
bc->handle = NULL;
bc->symbol = NULL;
bfd *b = bfd_openr(procname, 0);
if (!b) {
output_print(ob,"Failed to open bfd from (%s)\n" , procname);
return 1;
}
int r1 = bfd_check_format(b, bfd_object);
int r2 = bfd_check_format_matches(b, bfd_object, NULL);
int r3 = bfd_get_file_flags(b) & HAS_SYMS;
if (!(r1 && r2 && r3)) {
bfd_close(b);
output_print(ob,"Failed to init bfd from (%s): %d %d %d\n", procname, r1,r2,r3);
return 1;
}
void *symbol_table;
unsigned dummy = 0;
if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) {
if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) {
free(symbol_table);
bfd_close(b);
output_print(ob,"Failed to read symbols from (%s)\n", procname);
return 1;
}
}
bc->handle = b;
bc->symbol = symbol_table;
return 0;
}
static void
close_bfd_ctx(struct bfd_ctx *bc)
{
if (bc) {
if (bc->symbol) {
free(bc->symbol);
}
if (bc->handle) {
bfd_close(bc->handle);
}
}
}
static struct bfd_ctx *
get_bc(struct output_buffer *ob , struct bfd_set *set , const char *procname)
{
while(set->name) {
if (strcmp(set->name , procname) == 0) {
return set->bc;
}
set = set->next;
}
struct bfd_ctx bc;
if (init_bfd_ctx(&bc, procname , ob)) {
return NULL;
}
set->next = calloc(1, sizeof(*set));
set->bc = malloc(sizeof(struct bfd_ctx));
memcpy(set->bc, &bc, sizeof(bc));
set->name = strdup(procname);
return set->bc;
}
static void
release_set(struct bfd_set *set)
{
while(set) {
struct bfd_set * temp = set->next;
free(set->name);
close_bfd_ctx(set->bc);
free(set);
set = temp;
}
}
static char procname[MAX_PATH];
static void
_backtrace(struct output_buffer *ob, struct bfd_set *set, int depth , LPCONTEXT context)
{
GetModuleFileNameA(NULL, procname, sizeof procname);
struct bfd_ctx *bc = NULL;
STACKFRAME frame;
memset(&frame,0,sizeof(frame));
frame.AddrPC.Offset = context->Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrStack.Offset = context->Esp;
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
char symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 255];
char module_name_raw[MAX_PATH];
while(StackWalk(IMAGE_FILE_MACHINE_I386,
process,
thread,
&frame,
context,
0,
SymFunctionTableAccess,
SymGetModuleBase, 0)) {
--depth;
if (depth < 0)
break;
IMAGEHLP_SYMBOL *symbol = (IMAGEHLP_SYMBOL *)symbol_buffer;
symbol->SizeOfStruct = (sizeof *symbol) + 255;
symbol->MaxNameLength = 254;
DWORD module_base = SymGetModuleBase(process, frame.AddrPC.Offset);
const char * module_name = "[unknown module]";
if (module_base &&
GetModuleFileNameA((HINSTANCE)module_base, module_name_raw, MAX_PATH)) {
module_name = module_name_raw;
bc = get_bc(ob, set, module_name);
}
const char * file = NULL;
const char * func = NULL;
unsigned line = 0;
if (bc) {
find(bc,frame.AddrPC.Offset,&file,&func,&line);
}
if (file == NULL) {
DWORD dummy = 0;
if (SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol)) {
file = symbol->Name;
}
else {
file = "[unknown file]";
}
}
if (func == NULL) {
output_print(ob,"0x%x : %s : %s \n",
frame.AddrPC.Offset,
module_name,
file);
}
else {
output_print(ob,"0x%x : %s : %s (%d) : in function (%s) \n",
frame.AddrPC.Offset,
module_name,
file,
line,
func);
}
}
}
static char * g_output = NULL;
static LPTOP_LEVEL_EXCEPTION_FILTER g_prev = NULL;
static LONG WINAPI
exception_filter(LPEXCEPTION_POINTERS info)
{
struct output_buffer ob;
output_init(&ob, g_output, BUFFER_MAX);
if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) {
output_print(&ob,"Failed to init symbol context\n");
}
else {
bfd_init();
struct bfd_set *set = calloc(1,sizeof(*set));
_backtrace(&ob , set , 128 , info->ContextRecord);
release_set(set);
SymCleanup(GetCurrentProcess());
}
int logfd = open("eduke32_or_mapster32.crashlog", O_APPEND | O_CREAT | O_WRONLY);
int written;
if (logfd) {
while ((written = write(logfd, g_output, strlen(g_output)))) {
g_output += written;
}
close(logfd);
}
//fputs(g_output, stderr);
exit(1);
return 0;
}
static void
backtrace_register(void)
{
if (g_output == NULL) {
g_output = malloc(BUFFER_MAX);
g_prev = SetUnhandledExceptionFilter(exception_filter);
}
}
static void
backtrace_unregister(void)
{
if (g_output) {
free(g_output);
SetUnhandledExceptionFilter(g_prev);
g_prev = NULL;
g_output = NULL;
}
}
BOOL WINAPI
DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
hinstDLL = hinstDLL;
lpvReserved = lpvReserved;
switch (dwReason) {
case DLL_PROCESS_ATTACH:
backtrace_register();
break;
case DLL_PROCESS_DETACH:
backtrace_unregister();
break;
}
return TRUE;
}
/* cut dependence on libintl... libbfd needs this */
char *libintl_dgettext (const char *domain_name, const char *msgid)
{
static char buf[1024] = "XXX placeholder XXX";
domain_name = domain_name;
msgid = msgid;
return buf;
}