pstrace: initial commit
This commit is contained in:
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||||
|
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||||
|
|
||||||
|
<cconfiguration id="cdt.managedbuild.toolchain.gnu.base.1468173371">
|
||||||
|
|
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.1468173371" moduleId="org.eclipse.cdt.core.settings" name="Default">
|
||||||
|
|
||||||
|
<externalSettings/>
|
||||||
|
|
||||||
|
<extensions>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
|
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||||
|
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
</storageModule>
|
||||||
|
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
|
||||||
|
<configuration buildProperties="" id="cdt.managedbuild.toolchain.gnu.base.1468173371" name="Default" optionalBuildProperties="" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||||
|
|
||||||
|
<folderInfo id="cdt.managedbuild.toolchain.gnu.base.1468173371.1017613341" name="/" resourcePath="">
|
||||||
|
|
||||||
|
<toolChain id="cdt.managedbuild.toolchain.gnu.base.1636197543" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
|
||||||
|
|
||||||
|
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.GNU_ELF" id="cdt.managedbuild.target.gnu.platform.base.1674893854" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
|
||||||
|
|
||||||
|
<builder id="cdt.managedbuild.target.gnu.builder.base.492736432" managedBuildOn="false" name="Gnu Make Builder.Default" superClass="cdt.managedbuild.target.gnu.builder.base"/>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.archiver.base.1377706988" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1039311466" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
|
||||||
|
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1872151988" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||||
|
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.660299689" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
|
||||||
|
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.638871469" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||||
|
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1500078272" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.1726003080" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
|
||||||
|
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1727193008" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||||
|
|
||||||
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
|
||||||
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
|
||||||
|
</inputType>
|
||||||
|
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
<tool id="cdt.managedbuild.tool.gnu.assembler.base.2091043016" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
|
||||||
|
|
||||||
|
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.596755823" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||||
|
|
||||||
|
</tool>
|
||||||
|
|
||||||
|
</toolChain>
|
||||||
|
|
||||||
|
</folderInfo>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
|
|
||||||
|
</storageModule>
|
||||||
|
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
|
|
||||||
|
</cconfiguration>
|
||||||
|
|
||||||
|
</storageModule>
|
||||||
|
|
||||||
|
<storageModule moduleId="scannerConfiguration">
|
||||||
|
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
|
||||||
|
<scannerConfigBuildInfo instanceId="0.853637962">
|
||||||
|
|
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
|
|
||||||
|
</scannerConfigBuildInfo>
|
||||||
|
|
||||||
|
</storageModule>
|
||||||
|
|
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||||
|
|
||||||
|
<project id="pstrace.null.718903189" name="pstrace"/>
|
||||||
|
|
||||||
|
</storageModule>
|
||||||
|
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||||
|
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||||
|
|
||||||
|
</cproject>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>trace</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||||
|
<triggers>full,incremental,</triggers>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#ifndef LOG_H_
|
||||||
|
#define LOG_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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_ */
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#ifndef LOG_FILE_H_
|
||||||
|
#define LOG_FILE_H_
|
||||||
|
|
||||||
|
//framework
|
||||||
|
#include "log.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef MUTEX_H_
|
||||||
|
#define MUTEX_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,509 @@
|
|||||||
|
/*
|
||||||
|
* sysutils.cpp
|
||||||
|
*
|
||||||
|
* Created on: Dec 28, 2019
|
||||||
|
* Author: nnosov
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <elfutils/libdwfl.h>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <dwarf.h>
|
||||||
|
|
||||||
|
#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 <inttypes.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* sysutils.h
|
||||||
|
*
|
||||||
|
* Created on: Dec 28, 2019
|
||||||
|
* Author: nnosov
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SC_SYSUTILS_H_
|
||||||
|
#define SC_SYSUTILS_H_
|
||||||
|
|
||||||
|
//system
|
||||||
|
#include <string>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
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_ */
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
//system
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#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 <ucontext.h>
|
||||||
|
#include <execinfo.h>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
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 <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#produce very simple debug info vithout sources
|
||||||
|
echo 'void foo () {}' | gcc -g -O99 -o - -S -xc - -dA | grep frame_base
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user