diff --git a/.cproject b/.cproject
new file mode 100644
index 0000000..e756c1f
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..5a0810a
--- /dev/null
+++ b/.project
@@ -0,0 +1,27 @@
+
+
+ trace
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f3832f6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,114 @@
+#use Bash instead of SH
+export SHELL := /bin/bash
+
+# echo command color definitions
+ifndef NO_COLOR
+RED=\e[0;31m
+GREEN=\e[0;32m
+YELLOW=\e[1;33m
+NC=\e[0m # No Color
+COLOR=-fdiagnostics-color
+else
+RED=
+GREEN=
+YELLOW=
+NC=
+COLOR=
+endif
+
+CXX = g++
+CC = gcc
+RM = rm -f
+AR = ar rvs
+
+BUILD_DIR = ./build
+RESULT_DIR = ./build
+
+BIN = $(RESULT_DIR)/trace
+
+# Generate module software version and build version
+#$(shell \
+# STR=`cat $(BUILD_DIR)/version.h 2> /dev/null | grep "SOFT_BUILD" | sed 's/[a-z A-Z#\-\._]//g'`; \
+# let "STR += 1";\
+# echo "#ifndef VERSION_H_" > $(BUILD_DIR)/version.h; \
+# echo "#define VERSION_H_" >> $(BUILD_DIR)/version.h; \
+# echo "/* Automatically generated file, DO NOT EDIT it !!! */" >> $(BUILD_DIR)/version.h; \
+# echo "" >> $(BUILD_DIR)/version.h; \
+# echo "#define SOFT_BUILD $$STR" >> $(BUILD_DIR)/version.h; \
+# echo "#define USER_BUILD \"$${USER}\"" >> $(BUILD_DIR)/version.h; \
+# echo "#define DATE_BUILD \"`date +"%D %T"`\"" >> $(BUILD_DIR)/version.h; \
+# echo "#define REV_BUILD \"`git rev-parse --short HEAD`\"" >> $(BUILD_DIR)/version.h; \
+# echo "" >> $(BUILD_DIR)/version.h; \
+# echo "#endif /* VERSION_H_ */" >> $(BUILD_DIR)/version.h \
+# )
+
+#source file search path. add here new directories which contains files specified for $(SRC)
+VPATH = ./
+
+SRC = $(shell find . -name '*.cpp')
+#OBJ = $(patsubst %.cpp,%.o,$(addprefix $(BUILD_DIR)/,$(notdir $(SRC))))
+OBJ = $(BUILD_DIR)/main.o
+
+LIBS = -L./ -lpthread -lpq -lpqtypes -luuid -lrabbitmq -ljson-c -lcrypto -ldl -lcurl -ldw -lxml2 -lmicrohttpd -larchive -lmagic
+ATR_LIBS = ./build/libframework.a
+
+INCS = -I./ \
+-I/usr/include/postgresql -I /usr/include/libxml2 -I./thirdparty -I/opt/swifttest/include -I/usr/include/GraphicsMagick \
+-I./framework -I./framework/swi -I./framework/utils -I./framework/rmq -I./framework/logger -I$(BUILD_DIR)
+FLAGS = -Wall -gdwarf-4 -fPIC -O3 -rdynamic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++11
+
+
+.PHONY: all clean $(BIN)
+
+all: $(BIN)
+
+$(ATR_LIBS):
+ @make -C ./framework
+
+clean:
+ ${RM} $(BUILD_DIR)/*.o $(BUILD_DIR)/*.dep $(BIN) $(BUILD_DIR)/prepare.bld $(RESULT_DIR)/prepare.res $(BUILD_DIR)/version.h
+ @if [ -z "$$(ls -A $(BUILD_DIR) 2>&1)" ]; then ${RM} -r $(BUILD_DIR); fi
+ @if [ -z "$$(ls -A $(RESULT_DIR) 2>&1)" ]; then ${RM} -r $(RESULT_DIR); fi
+
+$(BUILD_DIR)/prepare.bld:
+ @if [ ! -e $(BUILD_DIR) ]; then mkdir -vp $(BUILD_DIR); fi
+ @touch $@
+
+$(RESULT_DIR)/prepare.res:
+ @if [ ! -e $(RESULT_DIR) ]; then mkdir -vp $(RESULT_DIR); fi
+ @touch $@
+
+$(BIN): $(BUILD_DIR)/prepare.bld $(RESULT_DIR)/prepare.res $(OBJ) $(ATR_LIBS)
+ gcc -ggdb -O3 -o simple simple.cpp
+ @make -C ./framework
+ @printf "Create %-60s" $@
+ @OUT=$$($(CXX) $(COLOR) -o $@ $(OBJ) $(ATR_LIBS) $(LIBS) 2>&1); \
+ if [ $$? -ne "0" ]; \
+ then echo -e "${RED}[FAILED]${NC}"; echo -e "$$OUT"; \
+ else \
+ if [ -n "$$OUT" ]; \
+ then echo -e "${YELLOW}[DONE]${NC}"; echo -e "'$$OUT'"; \
+ else \
+ echo -e "${GREEN}[DONE]${NC}"; \
+ fi; \
+ fi
+
+$(BUILD_DIR)/%.o: %.cpp
+#compile source code directly to $BUILD_DIR directory
+ @printf "Building %-60s" $@
+ @OUT=$$($(CXX) $(COLOR) -o $@ -c $< $(FLAGS) $(INCS) 2>&1); \
+ if [ $$? -ne "0" ]; \
+ then echo -e "${RED}[FAILED]${NC}"; echo -e "$$OUT"; \
+ else \
+ if [ -n "$$OUT" ]; \
+ then echo -e "${YELLOW}[DONE]${NC}"; echo -e "'$$OUT'"; \
+ else \
+ echo -e "${GREEN}[DONE]${NC}"; \
+ fi; \
+ fi
+#create dependencies
+ @$(CXX) -MM -MT '$@' -c $< > $@.dep $(FLAGS) $(INCS)
+
+#include dependencies for track changes in source code and related header files
+DEPEND := $(OBJ:.o=.o.dep)
+-include $(DEPEND)
diff --git a/framework/logger/log.cpp b/framework/logger/log.cpp
new file mode 100644
index 0000000..d043ab9
--- /dev/null
+++ b/framework/logger/log.cpp
@@ -0,0 +1,55 @@
+#include "log.h"
+
+#include
+
+#define LOG_BUFF_SIZE (1024*1024)
+
+
+const char * const SC_LogBase::mSeverityStrings[] = {
+ " [DEBUG] : ",
+ " [INFO] : ",
+ " [WARNING]: ",
+ " [ERROR] : "
+};
+
+char SC_LogBase::mString[LOG_BUFF_SIZE];
+uint32_t SC_LogBase::mStringSize = sizeof(SC_LogBase::mString);
+
+SC_LogBase::SC_LogBase(uint32_t id, const char* source) : mID(id)
+{
+ mStringLen = 0;
+ mCurrentSeverity = SEVERITY_DEBUG;
+ if(source) {
+ mSource = source;
+ }
+}
+
+SC_LogBase::~SC_LogBase()
+{
+ Close();
+}
+
+void SC_LogBase::FormatString(const char* fmt, va_list args)
+{
+ mStringLen += vsnprintf(mString + mStringLen, mStringSize - mStringLen, fmt, args);
+}
+
+void SC_LogBase::FormatPrefix(SC_LogSeverity severity)
+{
+ time_t rawTime;
+ struct tm * timeinfo;
+ time(&rawTime);
+ timeinfo = gmtime(&rawTime);
+
+ mStringLen += strftime(mString, sizeof(mString), "%d-%m-%Y %H:%M:%S", timeinfo);
+ strncpy(mString + mStringLen, mSeverityStrings[(int)severity], strlen(mSeverityStrings[(int)severity]));
+ mStringLen += strlen(mSeverityStrings[(int)severity]);
+}
+
+void SC_LogBase::FormatPostfix()
+{
+ if((mStringLen + 2) < mStringSize) {
+ mString[mStringLen++] = '\n';
+ mString[mStringLen++] = 0;
+ }
+}
diff --git a/framework/logger/log.h b/framework/logger/log.h
new file mode 100644
index 0000000..5602e4a
--- /dev/null
+++ b/framework/logger/log.h
@@ -0,0 +1,148 @@
+#ifndef LOG_H_
+#define LOG_H_
+
+#include
+#include
+#include
+#include
+#include
+
+#include "mutex.h"
+
+using std::string;
+
+// Log message severity
+enum SC_LogSeverity {
+ SEVERITY_DEBUG = 0,
+ SEVERITY_INFO,
+ SEVERITY_WARNING,
+ SEVERITY_ERROR,
+ //----------------
+ SEVERITY_MAX
+};
+
+
+class SC_LogBase
+{
+protected:
+
+ SC_LogBase(uint32_t id, const char* source);
+
+public:
+
+ virtual ~SC_LogBase();
+
+ //variable argument number logging
+ inline virtual void Log(SC_LogSeverity severity, const char* fmt, ...)
+ {
+ if (severity < mCurrentSeverity)
+ return;
+
+ mLock.Lock();
+
+ if(!IsOpened())
+ {
+ //print header if present
+ if(Open() && mHeader.size())
+ {
+ SendMessage((char*)mHeader.c_str());
+ }
+ }
+
+ mStringLen = 0;
+ FormatPrefix(severity);
+ va_list args;
+ va_start(args, fmt);
+ FormatString(fmt, args);
+ va_end(args);
+ FormatPostfix();
+ SendMessage(mString);
+
+ mLock.Unlock();
+ }
+
+ //open source for send messages
+ virtual bool Open() = 0;
+
+ //close source
+ virtual void Close(){}
+
+ //whether source already opened
+ virtual bool IsOpened() = 0;
+
+ //returns source path
+ string& GetSource()
+ {
+ return mSource;
+ }
+
+ //assign source path
+ inline void SetSource(const char* source)
+ {
+ Close();
+ mSource = source;
+ }
+
+ void SetSource(string& source)
+ {
+ SetSource(source.c_str());
+ }
+
+ //assign Log header
+ inline void SetHeader(const char* header)
+ {
+ mHeader = string(header) + '\n';
+ }
+
+ //return Log ID
+ inline uint32_t GetID() const
+ {
+ return mID;
+ }
+
+ //set Log ID
+ inline void SetID(uint32_t id)
+ {
+ mID = id;
+ }
+
+ //return current severity threshold applied to the messages
+ inline SC_LogSeverity GetCurrentSeverity() const
+ {
+ return mCurrentSeverity;
+ }
+
+ //set severity threshold to be applied to the messages
+ inline void SetCurrentSeverity(SC_LogSeverity severity)
+ {
+ mCurrentSeverity = severity;
+ }
+
+protected:
+
+ //actually sends message to the source
+ virtual void SendMessage(const char* msg) = 0;
+
+ //format message prefix
+ virtual void FormatPrefix(SC_LogSeverity severity);
+
+ //format message body
+ virtual void FormatString(const char* fmt, va_list args);
+
+ //format message postfix
+ virtual void FormatPostfix();
+
+protected:
+
+ uint32_t mID; //log ID, associated with source
+ string mSource; //source for store log messages (file, IP address or sometsing else)
+ string mHeader; //header of the Log
+ static char mString[]; //formatted string to be printed
+ static uint32_t mStringSize; //size of the string buffer
+ uint32_t mStringLen; //length of the string
+ SC_LogSeverity mCurrentSeverity; //maximum severity value to be logged
+ static const char * const mSeverityStrings[];
+ SC_Mutex mLock;
+};
+
+#endif /* LOG_H_ */
diff --git a/framework/logger/log_console.h b/framework/logger/log_console.h
new file mode 100644
index 0000000..548a785
--- /dev/null
+++ b/framework/logger/log_console.h
@@ -0,0 +1,29 @@
+#ifndef SC_LOGCONSOLE_H
+#define SC_LOGCONSOLE_H
+
+#include "log.h"
+
+class SC_LogConsole : public SC_LogBase {
+public:
+
+ SC_LogConsole(uint32_t id, const char* source) : SC_LogBase(id, source) { }
+
+ //open file for writing
+ inline virtual bool Open() {
+ return true;
+ }
+
+ //close file opened
+ inline virtual void Close() { }
+
+ //whether file already opened or not
+ inline virtual bool IsOpened() {
+ return true;
+ }
+protected:
+ inline virtual void SendMessage(const char* msg) {
+ fprintf(stderr, "%s", msg);
+ }
+};
+
+#endif // SC_LOGCONSOLE_H
diff --git a/framework/logger/log_file.h b/framework/logger/log_file.h
new file mode 100644
index 0000000..08aa43c
--- /dev/null
+++ b/framework/logger/log_file.h
@@ -0,0 +1,108 @@
+#ifndef LOG_FILE_H_
+#define LOG_FILE_H_
+
+//framework
+#include "log.h"
+#include
+#include
+
+using std::string;
+
+//=============================================================================================
+// SWI Logger to file logging class declaration
+//=============================================================================================
+class SC_LogFile : public SC_LogBase
+{
+public:
+
+ SC_LogFile(uint32_t id, const char* source) : SC_LogBase(id, source)
+ {
+ mFile = 0;
+ //2GByte by default
+ mMaxFileSize = 0x0000000080000000ULL;
+ mBytesCount = 0;
+ }
+
+ //open file for writing
+ inline virtual bool Open()
+ {
+ if(!mFile) {
+ // extract log and path names
+ uint32_t namelen = mSource.size();
+ if(namelen) {
+ const char* ptr = strrchr(mSource.c_str(), '/');
+ uint32_t pathlen = 0;
+ if(ptr) {
+ pathlen = ptr - mSource.c_str() + 1;
+ namelen -= pathlen + 1;
+ }
+
+ mLogPath.append(mSource.c_str(), pathlen);
+
+ mLogName.append((mSource.c_str() + pathlen), namelen);
+
+ //open the file finally
+ mFile = fopen(mSource.c_str(), "a+");
+ }
+ }
+
+ return (mFile != 0);
+ }
+
+ //close file opened
+ inline virtual void Close()
+ {
+ if(mFile) {
+ fclose(mFile);
+ }
+
+ mFile = 0;
+ mBytesCount = 0;
+ }
+
+ //whether file already opened or not
+ inline virtual bool IsOpened()
+ {
+ return (mFile != 0);
+ }
+
+ inline void SetMaxFileSize(uint64_t size)
+ {
+ mMaxFileSize = size;
+ }
+
+ inline uint64_t GetMaxFileSize()
+ {
+ return mMaxFileSize;
+ }
+
+ inline FILE* GetLogFD()
+ {
+ return mFile;
+ }
+
+protected:
+
+ inline virtual void SendMessage(const char* msg)
+ {
+ if(mFile && mBytesCount < mMaxFileSize) {
+ if(fputs(msg, mFile) >= 0) {
+ fflush(mFile);
+ mBytesCount += mStringLen;
+ } else {
+ fclose(mFile);
+ mFile = 0;
+ }
+ }
+ }
+
+protected:
+
+ string mLogPath; //path to the log file
+ string mLogName; //name of the log file
+ FILE* mFile; //log file descriptor
+ uint64_t mMaxFileSize; //maximum number bytes allowed to be written to the file
+ uint64_t mBytesCount; //number of bytes actually written
+};
+
+#endif /* LOG_FILE_H_ */
diff --git a/framework/mutex.h b/framework/mutex.h
new file mode 100644
index 0000000..ba42e80
--- /dev/null
+++ b/framework/mutex.h
@@ -0,0 +1,40 @@
+#ifndef MUTEX_H_
+#define MUTEX_H_
+
+#include
+#include
+
+class SC_Mutex {
+public:
+ SC_Mutex() {
+ pthread_mutex_init(&m, NULL);
+ }
+ SC_Mutex(SC_Mutex const&) {
+ pthread_mutex_init(&m, NULL);
+ }
+ SC_Mutex& operator=(SC_Mutex const& rhs) {
+ if (&rhs != this) {
+ pthread_mutex_init(&m, NULL);
+ }
+ return *this;
+ }
+ ~SC_Mutex() {
+ pthread_mutex_destroy(&m);
+ }
+
+ void Lock() {
+ pthread_mutex_lock(&m);
+ }
+
+ void Unlock() {
+ pthread_mutex_unlock(&m);
+ }
+
+ bool Trylock() {
+ return (pthread_mutex_trylock(&m) == 0);
+ }
+private:
+ pthread_mutex_t m;
+};
+
+#endif /* MUTEX_H_ */
diff --git a/framework/sysutils.cpp b/framework/sysutils.cpp
new file mode 100644
index 0000000..4032d6d
--- /dev/null
+++ b/framework/sysutils.cpp
@@ -0,0 +1,509 @@
+/*
+ * sysutils.cpp
+ *
+ * Created on: Dec 28, 2019
+ * Author: nnosov
+ */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "logger/log.h"
+#include "sysutils.h"
+
+extern SC_LogBase* logger;
+
+char __stack_trace[8192];
+
+
+Dwarf_Frame* frame;
+Dwfl_Module* module;
+
+// dwfl_addrsegment() possibly can be used to check address validity
+// dwarf_getattrs() allows to enumerate all DIE attributes
+// dwarf_getfuncs() allows to enumerate functions within CU
+
+static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix);
+
+bool is_location_form(int form)
+{
+ if (form == DW_FORM_block1 ||
+ form == DW_FORM_block2 ||
+ form == DW_FORM_block4 ||
+ form == DW_FORM_block ||
+ form == DW_FORM_data4 ||
+ form == DW_FORM_data8 ||
+ form == DW_FORM_sec_offset) {
+ return true;
+ }
+ return false;
+}
+
+char* GetExecutableName(char* path, uint32_t size)
+{
+ char link[PATH_MAX];
+ snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
+ int nret = readlink(link, path, size);
+ if (nret == -1) {
+ return NULL;
+ }
+
+ // trailing zero
+ path[nret] = 0;
+
+ return path;
+}
+
+#include
+
+typedef struct __reginfo {
+ __reginfo() {
+ regname[0] = 0;
+ regno = -1;
+ }
+ char regname[1024];
+ int regno;
+} reginfo;
+
+int regname_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
+{
+ reginfo* info = (reginfo*)arg;
+ if(info->regno == regno) {
+ snprintf(info->regname, sizeof(info->regname), "%s %s%s", setname, prefix, regname);
+ }
+
+ return 0;
+}
+
+int reginfo_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
+{
+ reginfo* info = (reginfo*)arg;
+
+ //logger->Log(SEVERITY_DEBUG, "%s: info_reg = 0x%hhX, reg = 0x%hhX", __FUNCTION__, info->regno, regno);
+ if(info->regno == regno) {
+ snprintf(info->regname, sizeof(info->regname), "%s %s%s", setname, prefix, regname);
+ Dwarf_Op ops_mem[3];
+ Dwarf_Op* ops;
+ size_t nops;
+ int ret = dwarf_frame_register(frame, info->regno, ops_mem, &ops, &nops);
+ if(ret != 0) {
+ logger->Log(SEVERITY_DEBUG, "Failed to get CFI expression for register %s", info->regname);
+ return 0;
+ }
+ if(nops == 0 && ops == ops_mem) {
+ logger->Log(SEVERITY_DEBUG, "CFI expression for register %s is UNDEFINED", info->regname);
+ return 0;
+ }
+ if(nops == 0 && ops == NULL) {
+ logger->Log(SEVERITY_DEBUG, "CFI expression for register %s is SAME VALUE", info->regname);
+ return 0;
+ }
+ logger->Log(SEVERITY_DEBUG, "Found CFI expression for register %s, number of expressions: %d", info->regname, nops);
+ for(size_t i = 0; i < nops; ++i) {
+ logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
+ }
+ }
+
+ return 0;
+}
+
+void HandleType(Dwarf_Attribute* param, bool is_return = false)
+{
+ Dwarf_Attribute attr_mem;
+ Dwarf_Attribute* attr;
+
+ // get DIE of return type
+ Dwarf_Die ret_die;
+
+ if(dwarf_formref_die(param, &ret_die)) {
+ switch (dwarf_tag(&ret_die)) {
+ case DW_TAG_base_type: {
+ // get Size attribute and it's value
+ Dwarf_Word size = 0;
+ attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
+ if(attr) {
+ dwarf_formudata(attr, &size);
+ }
+ logger->Log(SEVERITY_INFO, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
+ break;
+ }
+ case DW_TAG_array_type:
+ logger->Log(SEVERITY_INFO, "array type");
+ break;
+ case DW_TAG_pointer_type:
+ logger->Log(SEVERITY_INFO, "pointer type");
+ break;
+ case DW_TAG_enumeration_type:
+ logger->Log(SEVERITY_INFO, "enumeration type");
+ break;
+ case DW_TAG_const_type:
+ logger->Log(SEVERITY_INFO, "constant type");
+ break;
+ case DW_TAG_subroutine_type:
+ logger->Log(SEVERITY_INFO, "subroutine type");
+ break;
+ case DW_TAG_typedef:
+ logger->Log(SEVERITY_INFO, "typedef '%s' type", dwarf_diename(&ret_die));
+ break;
+ default:
+ logger->Log(SEVERITY_INFO, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
+ break;
+ }
+ attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
+ if(attr) {
+ HandleType(attr);
+ }
+ }
+}
+
+void
+print_expr_block (Dwarf_Attribute *attr, Dwarf_Op *exprs, int len,
+ Dwarf_Addr addr, int depth)
+{
+ printf ("{");
+ for (int i = 0; i < len; i++)
+ {
+ printf ("%s", (i + 1 < len ? ", " : ""));
+ }
+ printf ("}");
+}
+
+void HandleParameter(Dwarf_Die* result)
+{
+ Dwarf_Attribute attr_mem;
+ Dwarf_Attribute* attr;
+
+ // Get reference to attribute type of the parameter/variable
+ attr = dwarf_attr(result, DW_AT_type, &attr_mem);
+ logger->Log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
+ if(attr) {
+ HandleType(attr);
+ }
+
+ // determine location of parameter in stack/heap or CPU registers
+ attr = dwarf_attr(result, DW_AT_location, &attr_mem);
+ if(attr) {
+ logger->Log(SEVERITY_DEBUG, "parameter location attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
+ if(dwarf_hasform(attr, DW_FORM_exprloc)) {
+ Dwarf_Op *expr;
+ size_t exprlen;
+ if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
+ logger->Log(SEVERITY_DEBUG, "Found DW_AT_location expression");
+ print_detail(0, expr, exprlen, 0, "\tLocation ");
+ if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) {
+ Dwarf_Op ops_mem[3];
+ Dwarf_Op* ops;
+ size_t nops;
+ int ret = dwarf_frame_register(frame, expr[0].atom, ops_mem, &ops, &nops);
+ if(ret != 0) {
+ logger->Log(SEVERITY_DEBUG, "Failed to get CFI expression for register 0x%hhX", expr[0].atom);
+ return;
+ }
+ if(nops == 0 && ops == ops_mem) {
+ logger->Log(SEVERITY_DEBUG, "CFI expression for register 0x%hhX is UNDEFINED", expr[0].atom);
+ return;
+ }
+ if(nops == 0 && ops == NULL) {
+ logger->Log(SEVERITY_DEBUG, "CFI expression for register 0x%hhX is SAME VALUE", expr[0].atom);
+ return;
+ }
+ logger->Log(SEVERITY_DEBUG, "Found CFI expression for register 0x%hhX, number of expressions: %d", expr[0].atom, nops);
+ for(size_t i = 0; i < nops; ++i) {
+ logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
+ }
+ }
+ }
+ } else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
+ Dwarf_Addr base, start, end;
+ ptrdiff_t off = 0;
+ Dwarf_Op *fb_expr;
+ size_t fb_exprlen;
+ while ((off = dwarf_getlocations (attr, off, &base, &start, &end, &fb_expr, &fb_exprlen)) > 0) {
+ printf (" (%" PRIx64 ",%" PRIx64 ") ", start, end);
+ print_expr_block (attr, fb_expr, fb_exprlen, start, 0);
+ printf ("\n");
+ }
+
+
+ Dwarf_Word value;
+
+ int ret = dwarf_formudata(attr, &value);
+ if(ret >= 0) {
+ logger->Log(SEVERITY_DEBUG, "Found DW_AT_location offset = 0x%lX", value);
+ }
+ } else {
+ logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
+ }
+
+ }
+}
+
+void HandleFunction(Dwarf_Die* func, const char* fname)
+{
+ if(!strcmp(fname, dwarf_diename(func))) {
+ logger->Log(SEVERITY_INFO, "Found function in debug info. DWARF tag: 0x%X, name = %s(...)", dwarf_tag(func), dwarf_diename(func));
+
+ Dwarf_Attribute attr_mem;
+ Dwarf_Attribute* attr;
+
+ // determine function's stack frame base
+ attr = dwarf_attr(func, DW_AT_frame_base, &attr_mem);
+ if(attr) {
+ if(dwarf_hasform(attr, DW_FORM_exprloc)) {
+ Dwarf_Op *expr;
+ size_t exprlen;
+ if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
+ logger->Log(SEVERITY_DEBUG, "Found DW_AT_framebase expression");
+ print_detail(0, expr, exprlen, 0, "\tLocation ");
+ } else {
+ logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
+ }
+ }
+ }
+
+ // Get reference to return attribute type of the function
+ // may be to use dwfl_module_return_value_location() instead
+ attr = dwarf_attr(func, DW_AT_type, &attr_mem);
+ if(attr) {
+ logger->Log(SEVERITY_INFO, "Handle return parameter");
+ HandleType(attr, true);
+ } else {
+ logger->Log(SEVERITY_DEBUG, "return attr name = 'void(0)'");
+ }
+
+ Dwarf_Die result;
+ if (dwarf_child(func, &result) != 0)
+ return;
+
+ // went through parameters and local variables of the function
+ do {
+ switch (dwarf_tag(&result)) {
+ case DW_TAG_formal_parameter:
+ case DW_TAG_variable:
+ HandleParameter(&result);
+ break;
+// case DW_TAG_inlined_subroutine:
+// /* Recurse further down */
+// HandleFunction(&result, dwarf_diename(&result));
+// break;
+ default:
+ break;
+ }
+ } while(dwarf_siblingof(&result, &result) == 0);
+ }
+ return;
+}
+
+static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix)
+{
+ printf("\t%s ", prefix);
+ if (result < 0) {
+ printf("indeterminate (%s)\n", dwarf_errmsg (-1));
+ } else if (nops == 0) {
+ printf("%s\n", ops == NULL ? "same_value" : "undefined");
+ } else {
+ printf("%s expression:", result == 0 ? "location" : "value");
+ for (size_t i = 0; i < nops; ++i) {
+ printf (" 0x%X (offset: 0x%lX)", ops[i].atom, ops[i].offset);
+ if (ops[i].number2 == 0) {
+ if (ops[i].atom == DW_OP_addr) {
+ printf ("(%#" PRIx64 ")", ops[i].number + bias);
+ } else if (ops[i].number != 0) {
+ printf ("(%" PRIx64 ")", ops[i].number);
+ }
+ }
+ else {
+ printf ("(%" PRIx64 ",%" PRIx64 ")", ops[i].number, ops[i].number2);
+ }
+ }
+ puts("");
+ }
+}
+
+void HandleCompilationUnit(Dwfl_Module* module, Dwarf_Addr addr, const char* fname)
+{
+ Dwarf_Addr mod_bias = 0;
+ // get function debug definition
+ Dwarf_Die* cdie = dwfl_module_addrdie(module, addr, &mod_bias);
+ logger->Log(SEVERITY_DEBUG, "Function bias in module is 0x%lX", mod_bias);
+ //Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
+ if(!cdie) {
+ logger->Log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", addr);
+ return;
+ }
+
+ // get CFI (Call Frame Information) for current module
+ // from handle_cfi()
+ Dwarf_CFI* cfi = dwfl_module_eh_cfi(module, &mod_bias);
+ if(cfi) {
+ // get frame of CFI for address
+ logger->Log(SEVERITY_INFO, "Found CFI for module %s", dwarf_diename(cdie));
+ int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
+ if (result == 0) {
+ // get frame information
+ logger->Log(SEVERITY_INFO, "Found CFI frame for module %s", dwarf_diename(cdie));
+ Dwarf_Addr start = addr;
+ Dwarf_Addr end = addr;
+ bool signalp;
+ int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
+ if (ra_regno >= 0)
+ {
+ start += mod_bias;
+ end += mod_bias;
+ }
+ logger->Log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", addr, start, end, signalp ? "true" : "false");
+ if (ra_regno < 0)
+ logger->Log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg (0));
+ else {
+ reginfo info; info.regno = ra_regno;
+ dwfl_module_register_names(module, regname_callback, &info);
+ logger->Log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
+ }
+
+ // finally get CFA (Canonical Frame Address)
+ // Point cfa_ops to dummy to match print_detail expectations.
+ // (nops == 0 && cfa_ops != NULL => "undefined")
+ Dwarf_Op dummy;
+ Dwarf_Op *cfa_ops = &dummy;
+ size_t cfa_nops;
+ result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
+
+ print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
+ }
+
+ }
+
+ if(dwarf_tag(cdie) != DW_TAG_compile_unit) {
+ logger->Log(SEVERITY_DEBUG, "Skipping non-cu die. DWARF tag: 0x%X, name = %s", dwarf_tag(cdie), dwarf_diename(cdie));
+ return;
+ }
+
+ logger->Log(SEVERITY_DEBUG, "Enumerating Compilation Unit '%s' to lookup for function %s()", dwarf_diename(cdie), fname);
+ Dwarf_Die result;
+ if(dwarf_child(cdie, &result)) {
+ logger->Log(SEVERITY_INFO, "No child DIE found for CU");
+ return;
+ }
+
+ do {
+ switch (dwarf_tag(&result)) {
+ case DW_TAG_subprogram:
+ case DW_TAG_entry_point:
+ case DW_TAG_inlined_subroutine:
+ HandleFunction(&result, fname);
+ break;
+ default:
+ //logger->Log(SEVERITY_INFO, "Unknown tag 0x%X for die '%s'", dwarf_tag(&result), dwarf_diename(&result));
+ break;
+ }
+ } while(dwarf_siblingof(&result, &result) == 0);
+}
+
+const char* LibdwTraceCallStack(ucontext_t* uctx)
+{
+ void * caller_address = 0;
+#ifdef REG_RIP // x86_64
+ caller_address = (void *) uctx->uc_mcontext.gregs[REG_RIP];
+#elif defined(REG_EIP) // x86_32
+ caller_address = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
+#elif defined(__arm__)
+ caller_address = (void *) uctx->uc_mcontext.arm_pc);
+#elif defined(__aarch64__)
+ caller_address = (void *) uctx->uc_mcontext.pc);
+#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
+ caller_address = (void *) uctx->uc_mcontext.regs->nip);
+#elif defined(__s390x__)
+ caller_address = (void *) uctx->uc_mcontext.psw.addr);
+#elif defined(__APPLE__) && defined(__x86_64__)
+ caller_address = (void *) uctx->uc_mcontext->__ss.__rip);
+#else
+# error "unknown architecture!"
+#endif
+ void * array[50];
+ int size = backtrace(array, 50);
+ int skipped = 0;
+ for(int i = 0; i < size && array[i] != caller_address; ++i, ++skipped);
+ __stack_trace[0] = 0; uint32_t offset = 0;
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Stack trace(caller = %p. Total stack frames: %d, skipped: %d):\n",
+ caller_address, size, skipped);
+
+ char *debuginfo_path = NULL;
+ Dwfl_Callbacks callbacks = {
+ .find_elf = dwfl_linux_proc_find_elf,
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .section_address = dwfl_offline_section_address,
+ .debuginfo_path = &debuginfo_path,
+ };
+
+ Dwfl* dwfl = dwfl_begin(&callbacks);
+ if(dwfl == NULL) {
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to initialize libdw session for parse stack frames");
+ return __stack_trace;
+ }
+
+ if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to parse debug section of executable");
+ return __stack_trace;
+ }
+
+ for (int i = skipped, idx = 0; i < size ; ++i, ++idx) {
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "[%-2d] ", idx);
+
+ Dwarf_Addr addr = (uintptr_t)array[i];
+ Dwfl_Line *line = dwfl_getsrc(dwfl, addr);
+ if(line != NULL) {
+ int nline;
+ Dwarf_Addr addr;
+ const char* filename = dwfl_lineinfo (line, &addr, &nline, NULL, NULL, NULL);
+ if(filename) {
+ const char* str = strrchr(filename, '/');
+ if(str && *str != 0) {
+ str++;
+ } else {
+ str = filename;
+ }
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%s:%d", str, nline);
+ } else {
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
+ }
+ } else {
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
+ }
+
+ module = dwfl_addrmodule(dwfl, addr);
+ const char* addrname = dwfl_module_addrname(module, addr);
+ char* demangle_name = NULL;
+ if(addrname) {
+ int status;
+ demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
+ char* function_name = NULL;
+ if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
+ logger->Log(SEVERITY_ERROR, "Failed to allocate memory");
+ return __stack_trace;
+ }
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, " --> %s", function_name);
+
+ char* str = strchr(function_name, '(');
+ if(str) {
+ *str = 0;
+ }
+ HandleCompilationUnit(module, addr, function_name);
+ free(function_name);
+ }
+
+ if(demangle_name) {
+ free(demangle_name);
+ }
+
+ offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "\n");
+ }
+
+ return __stack_trace;
+}
diff --git a/framework/sysutils.h b/framework/sysutils.h
new file mode 100644
index 0000000..ce9ac05
--- /dev/null
+++ b/framework/sysutils.h
@@ -0,0 +1,30 @@
+/*
+ * sysutils.h
+ *
+ * Created on: Dec 28, 2019
+ * Author: nnosov
+ */
+
+#ifndef SC_SYSUTILS_H_
+#define SC_SYSUTILS_H_
+
+//system
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using std::string;
+
+// stack trace string buffer
+extern char __stack_trace[8192];
+
+// libdw-based trace call stack implementation
+const char* LibdwTraceCallStack(ucontext_t* uctx);
+
+char* GetExecutableName(char* path, uint32_t size);
+
+#endif /* SC_SYSUTILS_H_ */
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..a9ae941
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,199 @@
+//system
+#include
+#include
+#include
+
+#include "logger/log_console.h"
+
+#include "sysutils.h"
+
+static SC_LogConsole log_local(0, "/tmp/unspecified.file");
+SC_LogBase* logger = &log_local;
+
+typedef enum {
+ DEF_1 = 1,
+ DEF_2,
+ DEF_3
+} my_int;
+
+void Fun2(int arg1, uint32_t arg2)
+{
+ int* ptr = NULL;
+ *ptr = arg1;
+}
+
+uint32_t Fun1(const int arg1, my_int arg2, uint32_t arg3)
+{
+ int my_local = arg1 + 2;
+ printf("%d", my_local);
+ Fun2(my_local, arg3);
+ return arg2;
+}
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef void (*sig_handler_t)(int sig);
+
+void SetSignalHandler(sig_handler_t handler = 0);
+
+void SigusrHandler(int sig)
+{
+ // just do nothing on SIGUSR1 & SIGUSR2
+ SetSignalHandler(SigusrHandler);
+}
+
+volatile sig_atomic_t fatal_error_in_progress = 0;
+
+void FatalSignalHandler(int sig, siginfo_t* info, void* context)
+{
+ // Since this handler is established for more than one kind of signal,
+ // it might still get invoked recursively by delivery of some other kind
+ // of signal. Use a static variable to keep track of that.
+ if (fatal_error_in_progress) {
+ raise (sig);
+ }
+
+ fatal_error_in_progress = 1;
+
+ logger->Log(SEVERITY_ERROR, "%s signal handled", strsignal(sig));
+ const char* trace = 0;
+ if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE))
+ {
+ trace = LibdwTraceCallStack((ucontext_t*)context);
+ }
+
+ if(trace) {
+ logger->Log(SEVERITY_DEBUG, "%s", trace);
+ } else {
+ logger->Log(SEVERITY_ERROR, "No stack trace obtained");
+ }
+
+ // comment out line below to prevent coredump
+ // exit(EXIT_FAILURE);
+
+ // Now reraise the signal.
+ // We reactivate the signal’s default handling, which is to terminate the process.
+ // We could just call exit or abort, but reraising the signal sets the return status
+ // from the process correctly.
+ signal (sig, SIG_DFL);
+ raise (sig);
+}
+
+void SignalHandler(int sig)
+{
+// if (handled_error_in_progress)
+// raise (sig);
+// handled_error_in_progress = 1;
+
+// const char* str_sig = strsignal(sig);
+// logger->Log(SEVERITY_INFO, "%s received.", str_sig);
+ if(sig == SIGUSR1) {
+ logger->Log(SEVERITY_INFO, "Maintenance mode enabled.");
+ } else if(sig == SIGUSR2) {
+ logger->Log(SEVERITY_INFO, "Maintenance mode disabled.");
+ }
+// signal (sig, SIG_DFL);
+// raise(sig);
+ // reset to our handler back
+ SetSignalHandler();
+}
+
+#include
+#include
+
+void SetSignalHandler(sig_handler_t handler)
+{
+ //signals set
+ sigset_t ss;
+ sigfillset(&ss);
+
+ //remove previous handlers
+// sigdelset(&ss, SIGINT);
+ sigdelset(&ss, SIGUSR1);
+ sigdelset(&ss, SIGUSR2);
+ sigdelset(&ss, SIGSEGV);
+ sigdelset(&ss, SIGABRT);
+ sigdelset(&ss, SIGBUS);
+ sigdelset(&ss, SIGFPE);
+ sigdelset(&ss, SIGCHLD);
+ sigdelset(&ss, SIGTERM); //without replacement
+
+ //signal action
+ struct sigaction sa;
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_mask = ss;
+
+ // cleanup
+ sa.sa_handler = NULL;
+ sa.sa_sigaction = NULL;
+
+// //set interrupt signal
+// sa.sa_handler = SignalHandler;
+// sigaction(SIGINT, &sa, 0);
+
+ //set stop signal
+ sa.sa_handler = (handler == NULL) ? SignalHandler : handler;
+ sigaction(SIGUSR1, &sa, 0);
+
+ sa.sa_handler = SignalHandler;
+ sigaction(SIGUSR2, &sa, 0);
+
+ // cleanup
+ sa.sa_handler = NULL;
+ sa.sa_sigaction = NULL;
+
+ //set SIGSEGV
+ sa.sa_sigaction = FatalSignalHandler;
+ sigaction(SIGSEGV, &sa, 0);
+
+ //set SIGABRT
+ sa.sa_sigaction = FatalSignalHandler;
+ sigaction(SIGABRT, &sa, 0);
+
+ //set SIGBUS
+ sa.sa_sigaction = FatalSignalHandler;
+ sigaction(SIGBUS, &sa, 0);
+
+ //set FPE signal
+ sa.sa_sigaction = FatalSignalHandler;
+ sigaction(SIGFPE, &sa, 0);
+
+ //enable signals set
+ sigprocmask(SIG_BLOCK, &ss, 0);
+
+ //set core dump size to 1Gb
+ struct rlimit limit;
+ limit.rlim_cur = 1073741824;
+ limit.rlim_max = 1073741824;
+ if (setrlimit(RLIMIT_CORE, &limit))
+ {
+ logger->Log(SEVERITY_DEBUG, "Failed to set limit for core dump file size");
+ }
+}
+
+void ResetSignalHandler() {
+ signal(SIGINT, SIG_DFL);
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+ signal(SIGUSR2, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+}
+
+int main(int argc, char* argv[])
+{
+
+ SetSignalHandler(SigusrHandler);
+
+ Fun1(1, DEF_2, 3);
+
+ return 0;
+}
diff --git a/receips.txt b/receips.txt
new file mode 100644
index 0000000..b1441b9
--- /dev/null
+++ b/receips.txt
@@ -0,0 +1,2 @@
+#produce very simple debug info vithout sources
+echo 'void foo () {}' | gcc -g -O99 -o - -S -xc - -dA | grep frame_base
\ No newline at end of file
diff --git a/simple.cpp b/simple.cpp
new file mode 100644
index 0000000..9df250a
--- /dev/null
+++ b/simple.cpp
@@ -0,0 +1,18 @@
+#include
+
+
+void do_stuff(int my_arg)
+{
+ int my_local = my_arg + 2;
+ int i;
+
+ for (i = 0; i < my_local; ++i)
+ printf("i = %d\n", i);
+}
+
+
+int main()
+{
+ do_stuff(2);
+ return 0;
+}